Blackfire

De kracht van Blackfire

Gepubliceerd door Nathalie De Martin

Tijdens mijn onderzoek naar Blackfire (https://blackfire.io) en de functionaliteit ervan, heb ik besloten om me te richten op de categorie pagina's van Magento 1. Categoriepagina's worden het meest gevraagd in het hele framework, dus elke prestatieverbetering resulteert in een betere gebruikerservaring bij het navigeren door de productencatalogus.

 

Nadat ik het eerste profiel op mijn lokale projectomgeving, die alleen gebruik maakt van configureerbare producten, heb ik de volgende resultaten ontvangen:

BF_Picture1
BF_Picture2 (1)

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

 

Hieronder een screenshot van alle functies en subfuncties van de getConfigurableAttributes functie, met een duidelijk rood pad om te volgen.

BF_Picture3

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

BF_Picture4 (1)

We zien dat het laden van een collection class telkens de afterload functie activeert, die weer andere functies aanroept en zo verder.... Aan het eind van ons pad zien we dat de attributesCompare functie 39,65% van alle tijden gebruikt en 31122 keer wordt genoemd.

 

Laten we elke belangrijke functie op het pad nader bekijken zodat we een beter begrip hebben van wat er gebeurt en waarom attributenVergelijken zo vaak wordt genoemd. We beginnen met de functie getAttributeById in de 'Mage_Catalog_Model_Model_Product_Type_Abstract' klasse.

BF_Picture5 (1)

Het enige wat deze functie doet, is de getSetAttributes aanroepen om alle attributen voor een specifiek product te ontvangen. Het loops alle attributen tot het attribuut is gevonden dat overeenkomt met de attributeId 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 gaan we verder met ons onderzoek door daar te kijken.

BF_Picture6

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

BF_Picture7

Deze functie controleert welke attributen zich in de bijgeleverde attributenset bevinden en sorteert ze met de uasort functie die op zijn attributesCompare aanroept. Zoals eerder gezegd, is deze functie de eindfunctie op ons pad en moet verbeterd worden. We weten dat deze functie voor elk product herhaald wordt, wat nutteloos is, omdat een specifieke attributenset altijd dezelfde attributenvolgorde zal behouden 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 'Mage_Eav_Model_Entity_Abstract' klasse in de 'app/code/local' pool op hetzelfde bestandspad te plaatsen als het bestand in de 'app/code/core' code pool.

 

Eerst voegen we een statische variabele toe. Deze variabele wordt gebruikt bij de eerste keer dat de attributen gesorteerd worden en bewaart de resultaten op een specifieke attributeset-id-index. Op deze manier hoeven we de posities van deze attributen niet meer te berekenen wanneer dezelfde attributenet-id wordt opgegeven. We geven alleen de dataset van onze variabele terug.

BF_Picture8

Vervolgens wijzigen we de functie getSortedAttributes en brengen we de volgende wijzigingen aan.

We controleren of onze sleutel bestaat. Zo ja, dan sturen we de gegevens terug. Zo niet, dan berekenen we het en stellen we de array index aan het eind in voor verder gebruik.

 

Laten we onze pagina opnieuw profileren en kijken of de wijzigingen effect hebben gehad.

BF_Picture9
BF_Picture10

We zien een verbetering van 45% wandkloktijd op onze hele pagina! Onze CPU tijd is verminderd met 48%.

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

 

Verdere verbeteringen zouden kunnen zijn om de collectie één keer te laden voor alle producten in plaats van 21 keer apart. Het probleem boven aan onze rode weg aanpakken, is meestal een beter idee omdat elke subfunctie volgt. Omdat in dit geval elk product verschillende configureerbare attributen 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 functie getSortedAttributes de kern van de Magento functionaliteit en kan een snelle winst 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 tabbladen te controleren. Geheugen, Netwerk, Http, Http, Queries, etc.... Een goed voorbeeld zijn import/export scripts. Deze kunnen gemakkelijk CPU problemen veroorzaken, maar ook geheugenproblemen. Laat me je een voorbeeld geven van een ander geval. Dit keer over een Magento's varien core bestand.

 

Bij het importeren van productafbeeldingen met een van Magento's cronjobs is een 'out of memory' fout gemaakt. Ik besloot dit keer om Blackfire's CLI te gebruiken, omdat cronjobs wel eens tijdrovend kunnen zijn. Vooral bij het verwerken van import scripts. Dit profiel werd gegenereerd met de gratis versie van Blackfire, dus sommige tabbladen hadden kunnen verdwijnen.

BF_Picture11
BF_Picture12

Boven het resultaat van ons profiel. Let op dat we dit keer onze gegevens onder het geheugen tabblad bekijken, want onze fout is geheugenspecifiek. Ons pad is nu lichtblauw in plaats van rood.

 

De meest tijdrovende functie is de imagecratefromjpeg die slechts 32 keer wordt aangeroepen. Deze 32 staat voor het aantal beelden dat geïmporteerd werd voordat de geheugenfout werd gegooid. We kunnen ook concluderen dat voor elke afbeelding een nieuwe instantie van de 'Varien_Image_Adapter_Gd2' wordt aangemaakt. De constructeur van het varien_image roept de open functie van deze klasse aan, die op zijn beurt de imagecreatefromjpeg aanroept.

 

Al deze afbeeldingen worden gemaakt en bewaard in het geheugen, maar nergens uit het geheugen verwijderd.

 

Het is dus duidelijk dat deze na verloop van tijd een fout zullen maken. Vooral bij het importeren van veel beelden. Eens kijken hoe we het script zo kunnen aanpassen dat ons geheugen na elke import van een afbeelding weer wordt vrijgegeven.

 

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

BF_Picture13

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

 

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.

 

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

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

BF_Picture14
blackfire_partner-silver

BLACKFIRE SILVER PARTNER

PHPro is Blackfire.io Silver Partner. Blackfire stelt alle ontwikkelaars en IT/Ops in staat om continu hun applicatieprestaties te verifiëren en te verbeteren, gedurende de gehele levenscyclus, door op het juiste moment de juiste informatie te krijgen. 

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.

Contacteer ons