Når en side ikke rammer en cache, går serverens tid til to ting: databasen og PHP. Er databasen i orden, og er siden stadig langsom, før browseren overhovedet får noget, så er det PHP, der skal ses på: den version, der kører koden, den måde serveren holder PHP klar på, og den kode, dine plugins og dit tema faktisk kører.
Guiden bygger videre på WordPress-arkitekturen, så hvis bootstrap og hooks er nye begreber, så start der.
PHP-versionen
En af de billigste forbedringer er ofte at køre en nyere PHP-version. Nyere versioner kører typisk den samme kode hurtigere, og ældre versioner holder op med at få sikkerhedsopdateringer; du kan se, hvilke der stadig er understøttet, på php.net. Du finder din nuværende version under Værktøjer → Webstedstilstand i WordPress.
Risikoen ligger i gamle plugins og temaer, der ikke er opdateret til den nye version. Skift derfor først på en kopi af siden, slå WP_DEBUG_LOG til, klik dig igennem de vigtigste sider og en ordre, og læs logfilen. Kan din udbyder ikke give dig en nyere version eller en kopi at teste på, er det et tegn på, at du bør kigge efter hosting med den rigtige PHP-opsætning.
OPcache
PHP er et fortolket sprog: hver fil skal læses og oversættes, før den kan køre. OPcache gemmer den oversatte kode i hukommelsen, så det kun sker én gang. For WordPress, der indlæser hundredvis af filer fra kerne, plugins og tema på hver request, er det en af de indstillinger, der betyder mest. Den er ofte slået til allerede, men standardstørrelserne er ofte for små til en webshop med mange plugins:
opcache.enable = 1
opcache.memory_consumption = 256 ; MB til kompileret kode
opcache.interned_strings_buffer = 16 ; MB til gentagne tekststrenge
opcache.max_accelerated_files = 20000 ; flere filer end WordPress + plugins
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60 ; tjek for ændrede filer hvert minutOm størrelsen passer, kan du se med opcache_get_status() eller et lille plugin, der viser den: er hukommelsen fuld, eller er antallet af filer nået, smider OPcache kode ud og oversætter den igen. Sætter du validate_timestamps til 0, sparer du også tjekket, men så skal OPcache tømmes ved hver opdatering, ellers kører den gamle kode videre. JIT-compileren fra PHP 8 hjælper beregningstung kode, men WordPress bruger mest tiden på at vente på databasen og bygge tekst, så gevinsten er som regel lille. PHP skriver selv, at almindelige applikationer kører omtrent som på PHP 7.4 (på engelsk) med JIT.
OPcache må ikke forveksles med en object cache. OPcache husker koden; en object cache husker data, som koden ellers skulle hente i databasen. Du har brug for begge, og hvilket plugin du bruger til at forbinde object cachen, kan gøre en forskel, som vores test af object cache-plugins viser.
PHP-FPM og antallet af workers
På de fleste servere kører PHP gennem PHP-FPM, der holder et antal PHP-processer, workers, klar. Hver worker håndterer én request ad gangen. Tager en side 300 millisekunder at generere, kan én worker klare lidt over tre af dem i sekundet. Kommer der flere requests, end der er ledige workers, venter de i kø, og svartiden stiger for alle, selvom den enkelte side er lige så hurtig som før.
Det naturlige svar er flere workers, men hver worker bruger hukommelse, og med WooCommerce og mange plugins kan det blive en del. Sætter du grænsen højere, end hukommelsen kan bære, begynder serveren at swappe, og så bliver alt langsomt. En brugbar tommelfingerregel er: den hukommelse, der er til rådighed for PHP, divideret med det, en worker bruger i gennemsnit. Du kan se forbruget med ps eller i din overvågning, når siden har kørt et stykke tid under normal trafik.
; /etc/php/8.x/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20 ; loftet: hukommelse til PHP / hukommelse pr. worker
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500 ; genstart en worker efter 500 requests
pm.status_path = /fpm-statusStatussiden viser, hvor mange workers der er i gang, og om der har stået requests i kø (listen queue og max children reached). Er loftet ofte nået, har du enten brug for flere workers og mere hukommelse eller for at gøre hver request hurtigere, så de bliver frigivet før. Det sidste er som regel billigst. Webserveren og PHP-FPM bør tale sammen over en Unix-socket, når de ligger på samme server; det sparer netværkslaget.
Hukommelse og tidsgrænser
memory_limit i PHP og WP_MEMORY_LIMIT i wp-config.php bestemmer, hvor meget en enkelt request må bruge, og max_execution_time, hvor længe den må køre. De gør ikke noget hurtigere. De forhindrer, at en tung import eller rapport fejler, og de sætter et loft over, hvor meget skade en løbsk request kan gøre. WooCommerce anbefaler en WordPress-hukommelsesgrænse på mindst 256 MB (på engelsk). Har du brug for meget mere, er det værd at finde ud af hvorfor.
Find den langsomme kode
Serverindstillingerne sætter bunden. Resten er koden, og den skal måles, ikke gættes. Query Monitor er stedet at starte: det viser databaseforespørgsler, kald til eksterne tjenester og hvilke plugins der står bag, og det viser den samlede tid og hukommelse for siden. Er det forespørgslerne, der tager tiden, handler næste skridt om databasen.
Er det ikke forespørgslerne, skal du bruge en profiler, der viser, hvilke PHP-funktioner tiden går i. New Relic og Tideways gør det løbende i produktion; Blackfire, SPX og Xdebug er gode til at se én request i detaljer. Det var sådan, vi fandt problemet i vores JSON-case: en funktion i et filterplugin, der brugte 100 ms på noget, PHP selv kan gøre på under et millisekund.
Typiske syndere
Langsom PHP-kode i WordPress skyldes sjældent noget eksotisk. Ofte er det en af disse:
- Kald til et eksternt API på hver request, fx licenstjek eller valutakurser, uden at svaret gemmes i en transient.
- Forespørgsler inde i en løkke, så en produktliste med 24 produkter giver 24 ekstra opslag.
- Tungt arbejde på
initellerplugins_loaded, som kun skulle køre i admin eller på én bestemt side. - Gammel kode, der genopfinder noget, PHP har indbygget, som JSON-funktionen ovenfor.
- Baggrundsjob fra WP-Cron eller Action Scheduler, der kører under en almindelig sidevisning.
Fælles for dem er, at løsningen sjældent er mere hardware. Det er at få koden til at lade være med at gøre arbejdet, eller at gøre det én gang og huske resultatet.
Belastningstest
Workers og hukommelse skal passe til den trafik, du får, når det gælder, fx en kampagne. Test det på en kopi af siden, ikke i produktion, med et værktøj som k6, og hold øje med FPM-statussiden imens:
import http from 'k6/http';
import { sleep } from 'k6';
export const options = { vus: 20, duration: '2m' };
export default function () {
http.get('https://staging.eksempel.dk/produkt-kategori/sko/');
sleep(1);
}Test sider, der ikke er sidecachet, som kategorier med filtre og kurven, for det er dem, der rammer PHP.
Ofte stillede spørgsmål
Kan jeg optimere PHP på delt hosting?
Kun det, udbyderen lader dig vælge, typisk PHP-versionen. Workers og OPcache styrer de. Koden kan du stadig gøre hurtigere, og det er ofte der, den største gevinst ligger.
Skal jeg slå JIT til?
Det skader sjældent, men forvent ikke meget. WordPress venter mest på databasen og bygger tekst, og det er ikke den slags arbejde, JIT gør hurtigere. Brug hukommelsen på OPcache først.
Hvor mange workers skal jeg have?
Så mange, som hukommelsen kan bære, og ikke flere. Mål, hvad en worker bruger, del den hukommelse, der er til PHP, med det tal, og hold øje med, om køen bliver fyldt.
Vil du have hjælp?
Vi profilerer din side, finder den kode og de indstillinger, der koster tid, og retter dem. Læs mere om optimering af WooCommerce.