Jachim Coudenys z'n sessie leverde ruimschoots wat we er van verwacht hadden. Hij begon met de grondbeginselen. Een belangrijk aspect is dat PHP-FPM gebruik maakt van een masterproces dat child processen voortbrengt. Deze child processen hebben allemaal toegang tot het gedeelde geheugen van de master.
Daarna het eerste deel: Realpath Cache. Deze cache wordt gevuld wanneer een pad wordt opgevraagd in PHP. Het explodeert een pad op het forward slash ('/') en steekt dan alle mogelijke paden in cache.
$presentation = file_get_contents( __DIR__ . '/../ffi.php' );
$presentation2 = file_get_contents( dirname(__DIR__) . '/ffi.php' );
$filesize = filesize( __DIR__ . '/../est.txt' ); print_r(realpath_cache_get());
[/home/jachim/demo] => Array
(
[key] => 1.6354972010384E+19
[is_dir] => 1
[realpath] => /home/jachim/demo
[expires] => 1579859105
)
[/home] => Array
(
[key] => 4353355791257440477
[is_dir] => 1
[realpath] => /home
[expires] => 1579859105
)
[/home/jachim] => Array
(
[key] => 5522554812971572568
[is_dir] => 1
[realpath] => /home/jachim
[expires] => 1579859105
)
[/home/jachim/demo /../ffi.php] => Array
(
[key] => 1.6164035761241E+19
[is_dir] =>
[realpath] => /home/jachim/ffi.php
[expires] => 1579859105
)
[/home/jachim/ffi.php] => Array
(
[key] => 5100116734180765326
[is_dir] =>
[realpath] => /home/jachim/ffi.php
[expires] => 1579859105
)
[/home/jachim/demo/realpath.php] => Array
(
[key] => 1.8190176096283E+19
[is_dir] =>
[realpath] => /home/jachim/demo/realpath.php
[expires] => 1579859105
)
Uiteraard verlopen volgende calls sneller, maar dit mechanisme maakt geen gebruik van gedeeld geheugen. Een prestatieboost kan worden bereikt door de cachegrootte en de entries TTL te tweaken.
Next up, OPCache: opcodes worden sinds PHP 5.5 gecached. Telkens wanneer een aanvraag door PHP wordt behandeld, wordt de code gecompileerd tot opcodes (kort voor operation codes). Een coole tool die Jachim liet zien, was de Vulcan Logic Dumper die deze opcodes visualiseert. Aangezien deze opcodes nooit veranderen (in productie), is het zinvol om wat cache toe te voegen. Er waren verschillende tools beschikbaar, maar het was de Zend Optimizer, die door Zend werd gedoneerd en in PHP 5.5 werd opgenomen, en het is met elke release beter geworden. Deze cache zit in het gedeelde geheugen en wordt dus door elk kind van het master FPM proces gebruikt.
Een aantal belangrijke aspecten:
- Shared memory: Zoals hierboven uitgelegd, wordt het gedeeld tussen de child processen, maar dit betekent ook dat het alleen nuttig is als er child processen zijn, dus misschien moet je nadenken over een aantal workarounds om de masterprocessen draaiende te houden, en zo de cache warm te houden (hoewel er andere OPCaching priming trucs zijn, zoals het opslaan van de opcodes om die in het geheugen op te slaan en te laden bij het spinnen van het masterproces, FPM-pools, etc.).
- Verspild geheugen: OPCache doet niet aan "defragmentatie". Dit betekent dat als sommige cache-items ongeldig worden verklaard, het geheugen wordt gemarkeerd als verspild, maar het wordt niet vrijgegeven. Nieuwe items worden altijd toegevoegd. Dit kan leiden tot een suboptimaal gebruik van het beschikbare geheugen.
Er zijn verschillende opties om de configuratie te tweaken:
- Het is standaard uitgeschakeld voor CLI-commando's, omdat het niet zinvol is om het te cachen omdat het proces onmiddellijk wordt beëindigd. Echter, in sommige gevallen (denk dat daemons) zal het gewoon activeren je al een betere prestatie geven.
- Een andere voor de hand liggende winst is het verhogen van het toegestane geheugengebruik, maar het hangt af van wat de stats (opcache_get_status()) je vertellen over het huidige cachegebruik.
- Tweaken wanneer de cache ongeldig wordt is ook een optie. Elke revalidate_freq seconden, zal OPCache controleren op bijgewerkte scripts. Je kunt deze waarde verhogen of de instelling validate_timestamps helemaal uitschakelen, wat betekent dat de cache geldig is tot in de eeuwigheid (en handmatige ongeldigverklaring is vereist).
- De opcache.max_wasted_percentage is de drempel om te bepalen wanneer een herstart moet plaatsvinden om (verspild) geheugen vrij te maken.
Jachim concludeerde dat de hitrate van je OPCache altijd minimaal boven de 90% moet liggen, maar eigenlijk zou je in de meeste gevallen een hitrate van 99% moeten zien. Het verspilde geheugen zou idealiter nul moeten zijn, en je zou nooit een volledige cache moeten hebben. Een coole visualisatietool is OPcache Status.
Het laatste deel, Preloading: OPCache op steroïden. Het maakt deel uit van OPCache sinds PHP 7.4, en in principe betekent het dat sommige van uw functies en classes kunnen worden geladen wanneer PHP start, dus voordat het eventuele verzoeken accepteert. Eigenlijk worden je functies onderdeel van de PHP engine, net als bijvoorbeeld strlen(). Er is een valkuil: je klassen moeten "in volgorde" geladen worden, dat wil zeggen als je klasse een andere klasse nodig heeft, moet die al bekend zijn.
Conclusie
Ook al lijkt dit misschien devops-materie, en is het inderdaad zeer low level, maar het is zeker interessant om te weten hoe dit alles werkt, en het heeft ons team zeker weer aan het denken gezet over een aantal van onze hosting-configuraties.