Nieuws

15 min leestijd

De kracht van Blackfire

Tijdens mijn onderzoek naar Blackfire (https://blackfire.io) en de functionaliteit ervan, besloot ik me te richten op de categoriepagina's van Magento 1. Categoriepagina's worden het meest gevraagd in het gehele kader, zodat elke prestatieverbetering resulteert in een betere gebruikerservaring bij het navigeren door de productencatalogus.

Nadat ik het eerste profiel had aangemaakt op mijn lokale projectomgeving, die alleen configureerbare producten gebruikt, ontving ik de volgende resultaten: Blackfire_configureerbare_producten

blackfire-profiling
BF_Picture2

We zien dat ons profiel een wandkloktijd van 15,8 seconden heeft, wat teleurstellend langzaam is. Wandkloktijd is een berekening van uw CPU (hoeveelheid tijd gebruikt voor het verwerken van instructies) + de I/O-tijd (netwerk + schijftijd). Met deze resultaten vraagt onze pagina om verder onderzoek.

Bij het volgen van het rode pad - opeenvolging van rode blokken die het meest tijdrovend waren - zag ik dat 59,12% van de hele aanvraag wandkloktijd naar de getConfigurableAttributes functie gaat.

We zien nu dat onze getConfigurableAttributes functie 3 callees heeft, functies die worden aangeroepen vanuit de huidige functie. Een van deze functies is de Varien_Data_Collection_Db::load functie, die 98% van alle callees tijd gebruikt. Een vraag die we ons kunnen stellen: "Waarom laadt Magento 21 collecties en is dit nodig?

Rechts een screenshot van alle functies en subfuncties van de getConfigurableAttributes functie, met een duidelijk rood pad om te volgen. We zien dat het laden van een collectieklasse elke keer de afterload functie activeert, die weer andere functies aanroept en zo verder..... Aan het einde van ons pad zien we dat de attributenvergelijkingsfunctie 39,65% van alle tijd gebruikt en 31122 keer wordt aangeroepen.

BF_Picture3
BF_Picture4

Laten we eens dieper ingaan op elke belangrijke functie op het pad, zodat we een beter begrip hebben van wat er gebeurt en waarom attributenvergelijking zo veel wordt genoemd. We beginnen met de getAttributeById functie in de 'Mage_Catalog_Model_Model_Product_Type_Abstract' klasse.

Het enige wat deze functie doet, is de getSetAttributes aanroepen om alle attributen voor een specifiek product te ontvangen. Het loops van alle attributen totdat het attribuut wordt gevonden dat overeenkomt met de attribuutId parameter. Als het gevonden wordt, geeft het het attribuut terug. We weten dat de getSetAttributes-functie de volgende belangrijke functie op ons pad is, dus we gaan verder met ons onderzoek door daar een kijkje te nemen.

BF_Picture5
BF_Picture6

Deze functie retourneert alle producten van een specifiek product (zoals eerder vermeld) met de loadAllAttributes functie, maar noemt ook de getSortedAttributes functie. Dat is het grootste probleem, zoals we kunnen concluderen uit ons Blackfire profiel (47,23%).

Deze functie controleert welke attributen in de bijgeleverde attribuutenset zitten en sorteert ze met de uasort-functie die de attributen op zijn beurt vergelijkt. Zoals eerder gezegd is deze functie de eindfunctie op ons pad en moet deze verbeterd worden. We weten dat deze functie voor elk product wordt herhaald, wat nutteloos is omdat een specifieke attribuutenset altijd dezelfde attribuutvolgorde behoudt voor elk product dat die set gebruikt. Laten we proberen deze functionaliteit te herschrijven.

Helaas bevindt deze functie zich in een abstracte Magento-klasse, dus een goede herschrijving is niet mogelijk. In plaats daarvan moeten we de hele klasse overschrijven. Dit doen we door de klasse 'Mage_Eav_Model_Entity_Abstract' in de 'app/code/local' pool te plaatsen op hetzelfde bestandspad als het bestand in de 'app/code/core' code pool.

Allereerst voegen we een statische variabele toe. Deze variabele wordt gebruikt wanneer de attributen voor het eerst gesorteerd worden en houdt de resultaten bij op een specifieke attributeset-id-index. Op deze manier hoeven we deze attribuutposities niet meer te berekenen wanneer dezelfde attribuut-id wordt geleverd. We geven gewoon de dataset van onze variabele terug.

BF_Picture7
BF_Picture8

Vervolgens passen we de getSortedAttributes-functie aan en maken we de volgende wijzigingen.

Rechts een vergelijking van de twee profielen. De vorige en de huidige. De blauwe blokken geven verbeteringen aan met de wandkloktijd in seconden. Een simpele verandering met enorme effecten. Natuurlijk is het ook mogelijk om het profiel niet in de vergelijkingsmodus te bekijken.

Verdere verbeteringen zouden kunnen zijn om de inzamelbelasting voor alle producten één keer te laten lopen in plaats van 21 keer apart. De aanpak van het probleem aan de bovenkant van ons rode pad, is meestal een beter idee, omdat elke subfunctie volgt. Omdat in dit geval elk product verschillende configureerbare attributen geconfigureerd kan hebben, is dit misschien niet het beste idee. Let op: dit is niet de standaard list.phtml Magento template. In tegenstelling tot deze template is de getSortedAttributes-functie de kern van de Magento-functionaliteit en kan het een snelle overwinning zijn voor verschillende Magento-projecten.

Dit probleem was vooral een CPU-probleem, maar je kunt ook andere factoren hebben die problemen kunnen veroorzaken. Het is een goed idee om alle geleverde tabbladen te inspecteren. Geheugen, Netwerk, Http, Queries, etc..... Een goed voorbeeld zijn import / export scripts. Deze kunnen gemakkelijk CPU problemen veroorzaken, maar ook geheugenproblemen. Laat ik u een voorbeeld geven van een ander geval. Deze keer over een Magento's varien core bestand.

Bij het importeren van productafbeeldingen met een van Magento's cronjobs, werd een 'out of memory' fout gegooid. Ik besloot deze keer Blackfire's CLI te gebruiken, omdat cronjobs tijdrovend konden zijn. Vooral bij het verwerken van import scripts. Dit profiel werd gegenereerd met de gratis versie van Blackfire, zodat sommige tabbladen verdwenen konden zijn.

BF_Picture10
BF_Picture11

Links het resultaat van ons profiel. Wees ervan bewust dat we onze gegevens deze keer onder het geheugentabblad bekijken, omdat onze fout memory-specifiek is. Ons pad is nu lichtblauw in plaats van rood.

De meest tijdrovende functie is de imagecreatefromjpeg die slechts 32 keer wordt genoemd. Deze 32 staat voor het aantal beelden dat werd geïmporteerd voordat de geheugenfout werd gegooid. We kunnen ook concluderen dat er voor elk beeld een nieuwe versie van de 'Varien_Image_Adapter_Gd2' wordt gemaakt. De constructeur van het varien_image noemt de open functie van deze klasse, die op zijn beurt de imagecreatefromjpeg noemt.

Al deze beelden worden in het geheugen aangemaakt en bewaard, maar nergens uit het geheugen verwijderd.

Het is dus duidelijk dat deze na verloop van tijd een fout zullen veroorzaken. Vooral bij het importeren van veel beelden. Laten we eens kijken hoe we het script kunnen veranderen, zodat ons geheugen weer wordt vrijgegeven na elke beeldimport.

Als we kijken naar de open functie van onze 'Varien_Image_Adapter_Gdapter_Gd2' klasse zien we dat de huidige afbeelding is opgeslagen in een variabele $_imageHandler.

Het zou een goed idee kunnen zijn om de afbeelding in deze variabele te vernietigen nadat de klasse niet meer wordt gebruikt. Op dat moment is de image al geïmporteerd zodat we dit niet meer nodig hebben.

Laten we de 'Varien_Image_Adapter_Gd2' klasse uit onze Magento 1 lib directory overschrijven door dezelfde klasse toe te voegen onder het 'app/code/local/Varien/Image/Adapter/' pad.

BF_Picture12
BF_Picture13

Een goede plek om onze functionaliteit te schrijven zou in de destructor kunnen zijn. Deze functie zal altijd worden aangeroepen tijdens de afspeelvolgorde van een bepaald object. We voegen de volgende code toe: BF_Picture13

Hier activeren we de @imagedestroy functie op onze variabele. Door dit te doen, wordt het beeldobject vernietigd en het geheugen vrijgegeven. Laten we ons script opnieuw profileren en de impact zien.

We zien nu dat ons geheugen is afgenomen met 209MB! Ook werd elk product nu met succes geïmporteerd (200+ afbeeldingen) en het geheugen bleef stabiel, wat het belangrijkste is. We zijn er nu zeker van dat we ook grotere importen kunnen uitvoeren.

Ik hoop dat deze twee voorbeelden u de kracht van Blackfire laten zien bij het ontwikkelen van nieuwe code of het onderhouden van bestaande code.

BF_Picture14

Blackfire Silver Partner

PHPro is Blackfire.io Silver Partner. Blackfire stelt alle ontwikkelaars en IT/Ops in staat om hun applicatieprestaties continu te controleren en te verbeteren, gedurende de gehele levenscyclus, door de juiste informatie op het juiste moment te verkrijgen. Als u extra hulp nodig heeft, performance consultancy om uw PHP-applicaties te verbeteren, aarzel dan niet om contact op te nemen met het PHPro PHP Performance Team.

blackfire_partner-silver