...

PHP-sessie garbage collection: waarom het je website kan blokkeren

De php session gc kan verzoeken blokkeren, omdat het bij het opschonen van tienduizenden sessiebestanden het PHP-proces langdurig bezighoudt, waardoor andere verzoeken moeten wachten. Ik laat zien hoe probabilistische opschoning, bestandsvergrendelingen en trage I/O tot merkbare vertragingen leiden en hoe ik deze vertragingen voorkom met duidelijke instellingen, cron-taken en RAM-opslag, zodat de website vloeibaar blijft.

Centrale punten

  • oorzaak van het probleem: Probabilistische GC, bestands-I/O en locks leiden tot wachttijden.
  • risicofactor: Veel sessies (bijvoorbeeld 170.000) verlengen elke GC-run.
  • WordPress: Admin + Heartbeat versterken vertragingen.
  • Hosting: RAM, SSD en isolatie verminderen GC-kosten.
  • Oplossing: Cron-opschoning en Redis versnellen verzoeken.

PHP-sessie garbage collection kort uitgelegd

Sessies slaan statusgegevens tussen verzoeken op, meestal als bestanden in het bestandssysteem. De garbage collection verwijdert verouderde bestanden waarvan de wijzigingstijd ouder is dan session.gc_maxlifetime, vaak 1440 seconden. Standaard start PHP deze opschoning probabilistisch via session.gc_probability en session.gc_divisor, vaak als 1 op 1000 oproepen. Klinkt onschuldig, maar bij veel verkeer raakt het altijd wel iemand die de hele run moet doorstaan. Hoe meer bestanden er in de sessiemap staan, hoe langer de Opruimen het proces.

Waarom blokkeert het opschonen verzoeken?

Een GC-run moet de sessiemap doorlopen, elk bestand controleren en oude vermeldingen verwijderen, wat bij trage I/O snel Seconden kost. Als er 170.000 bestanden zijn, werken veel systeemaanroepen achter elkaar, die CPU, RAM en opslagruimte in beslag nemen. Parallel gestarte PHP-processen proberen soms tegelijkertijd te verwijderen en veroorzaken extra bestandsvergrendelingen. Dit verlengt de wachttijden, omdat processen elkaar vertragen of blokkeren. Wie dieper in Sessievergrendeling begint, ziet hoe sterk locking het antwoordtijdprofiel beïnvloedt en de time-to-first-byte omhoog drijft, vooral bij piekbelastingen, die ik wil vermijden door de GC ontkoppelen.

WordPress: trage beheerderspagina's door sessies

Het admin-gedeelte vereist meer CPU- en databasetoegang dan de frontend, waardoor elke extra vertraging merkbaar is. maakt. Als op dat moment de garbage collection start, neemt de tijd tot de voltooide HTML-uitvoer aanzienlijk toe. De Heartbeat-API vraagt bovendien de server en botst bij pech met een GC-run. Hierdoor voelt de backend traag aan en duren klikken langer, hoewel de eigenlijke logica niet veel doet. Ik verzacht dit door de waarschijnlijkheid van GC in verzoeken op nul te zetten en de opruimwerk buiten de antwoordtijden start.

Hostingprestaties en infrastructuur

Op gedeelde systemen delen veel projecten I/O-capaciteit, waardoor een enkele GC-run andere websites remmen. Betere hardware met snelle NVMe-opslag en voldoende RAM vermindert de kosten per bestandstoegang. Een nette isolatie per klant of container voorkomt dat vreemde piekbelastingen je project beïnvloeden. Ik controleer ook proceslimieten en I/O-planners, zodat veel gelijktijdige PHP-workers niet vastlopen. Wie dieper wil plannen, vindt bij een gerichte Hostingoptimalisatie concrete aanknopingspunten om GC-runs te ontkoppelen en de Latency stabiliseren.

Sessies in het bestandssysteem versus RAM-opslagplaatsen

Bestandsgebaseerde sessies zijn eenvoudig, maar veroorzaken veel Overhead bij het zoeken, controleren en verwijderen. RAM-gebaseerde opslagplaatsen zoals Redis of Memcached beheren sleutels efficiënt, leveren snel en hebben ingebouwde vervalmechanismen. Dat bespaart systeemoproepen, verkort de latentie en vermindert de kans op fouten door bestandsvergrendelingen. Ik geef de voorkeur aan RAM-opslag zodra het aantal bezoekers toeneemt of het admin-gedeelte traag reageert. Een omschakeling verloopt snel en er is een handleiding voor Sessiebeheer met Redis helpt om de configuratie duidelijk te houden en de Bronnen beter benutten.

Zinvolle PHP-instellingen voor sessies

Ik stel de garbage collection zo in dat er geen verzoek per ongeluk wordt gedaan. uitlöst. Hiervoor stel ik de waarschijnlijkheid in op nul, plan ik de opschoning via Cron en pas ik de levensduur aan het risico aan. Daarnaast activeer ik strikte modi, zodat PHP alleen geldige ID's accepteert. Ik controleer het geheugen en het pad, zodat er geen trage NFS-mounts of overvolle mappen zijn die het systeem vertragen. Het volgende overzicht toont gangbare standaardinstellingen en beproefde waarden die ik, afhankelijk van het gebruik, selecteer om de Prestaties meetbaar verbeteren.

Instelling Typische standaard Aanbeveling Effect
session.gc_maxlifetime 1440 seconden 900–3600 seconden Kortere levensduur vermindert oude bestanden en verlaagt I/O.
session.gc_probability / session.gc_divisor 1 / 1000 (vaak) 0 / 1 Geen opschoning in verzoeken, Cron neemt het over Opruimen.
session.save_handler bestanden redis of memcached RAM-opslag vermindert bestandsblokkades en verkort Latencies.
session.use_strict_mode 0 1 Alleen geldige ID's, minder conflicten en Risico's.
session.save_path systeempad Eigen snel pad Korte directorydiepte, lokale SSD, minder Stat-Oproepen.

Daarnaast zie ik nog andere schakelaars die de stabiliteit en veiligheid verbeteren zonder overhead te genereren:

  • session.use_only_cookies=1, session.use_cookies=1 voor duidelijk cookiebeleid zonder URL-ID's.
  • session.cookie_httponly=1, session.cookie_secure=1 (bij HTTPS) en een passende session.cookie_samesite (meestal Lax) om lekken te voorkomen.
  • session.lazy_write=1 om onnodige schrijfbewerkingen te vermijden wanneer de inhoud niet verandert.
  • session.serialize_handler=php_serialize voor moderne serialisatie en interoperabiliteit.
  • Verhoog session.sid_length en session.sid_bits_per_character om ID's robuuster te maken.

Concrete configuratie: php.ini, .user.ini en FPM

Ik veranker de instellingen daar waar ze betrouwbaar werken: globaal in php.ini, per pool in PHP‑FPM of lokaal via .user.ini in projecten die aparte behoeften hebben. Een pragmatische set ziet er als volgt uit:

; php.ini of FPM-pool session.gc_probability = 0 session.gc_divisor = 1 session.gc_maxlifetime = 1800 session.use_strict_mode = 1 session.use_only_cookies = 1 session.cookie_httponly = 1
session.cookie_secure = 1 session.cookie_samesite = Lax session.lazy_write = 1 ; sneller, lokaal pad of RAM-opslag ; session.save_handler = files ; session.save_path = "2;/var/lib/php/sessions"

In de FPM-pool kan ik waarden hard instellen, zodat individuele apps deze niet kunnen overschrijven:

; /etc/php/*/fpm/pool.d/www.conf php_admin_value[session.gc_probability] = 0
php_admin_value[session.gc_divisor] = 1 php_admin_value[session.gc_maxlifetime] = 1800 php_admin_value[session.save_path] = "2;/var/lib/php/sessions"

Bestandssysteem en lay-out van opslagpad

Grote mappen met honderdduizenden bestanden zijn traag. Daarom deel ik de sessiemap op in submappen, zodat het opzoeken van mappen snel blijft:

session.save_path = "2;/var/lib/php/sessions"

De eerste 2 creëren twee niveaus van submappen, gebaseerd op hash-delen van de sessie-ID. Daarnaast helpen mount-opties zoals noatime en een bestandssysteem met goede directory-indexen. Ik vermijd NFS voor sessies indien mogelijk, of forceer sticky sessions op de load balancer totdat een RAM-opslag productief is.

Locking in de code onschadelijk maken

Veel vertragingen worden niet alleen veroorzaakt door GC, maar ook door onnodig lang aangehouden locks. Ik open de sessie zo kort mogelijk:

<?php session_start(); // lezen $data = $_SESSION['key'] ?? null; session_write_close(); // Lock vroeg vrijgeven // duur werk zonder Lock $result = heavy_operation($data);

// alleen indien nodig opnieuw openen en schrijven session_start(); $_SESSION['result'] = $result; session_write_close();

Als ik alleen lees, start ik de sessie met read_and_close, zodat PHP niet eens in de schrijfmodus gaat:

true]); // alleen lezen, schrijven niet nodig

Zo wordt de kans kleiner dat parallelle verzoeken op elkaar moeten wachten. In WordPress-plugins controleer ik of session_start() überhaupt nodig is en verplaats ik de aanroep naar latere hooks, zodat de kernstroom niet wordt geblokkeerd.

RAM-opslagconfiguratie voor sessies

Bij Redis of Memcached let ik op time-outs, databases en opslagbeleid. Een robuust voorbeeld voor Redis ziet er als volgt uit:

session.save_handler = redis session.save_path = "tcp://127.0.0.1:6379?database=2&timeout=2&read_timeout=2&persistent=1" session.gc_maxlifetime = 1800 session.gc_probability = 0 session.gc_divisor = 1

Omdat RAM-opslagplaatsen zelf de looptijden beheren, hoef ik geen bestands-GC uit te voeren. Ik beheer sessies apart van caches (andere DB of sleutelprefix), zodat evictions voor cache-sleutels niet onbedoeld sessies verwijderen. Ik richt het opslagbeleid op volatile-LRU, zodat alleen sleutels met TTL worden verdrongen wanneer het geheugen schaars wordt.

Externe opschoning via Cron: zo ontwar ik verzoeken

Ik bereik de veiligste ontkoppeling door de GC buiten de request-flow te plaatsen. start. Ik stel de waarschijnlijkheid in PHP‑ini of via .user.ini in op 0 en roep regelmatig een klein script op via Cron, dat de opschoning in gang zet. Idealiter draait Cron elke minuut of elke vijf minuten, afhankelijk van het verkeer en de gewenste hygiëne. Het blijft belangrijk dat de cron met dezelfde gebruiker werkt als de webserver, zodat de machtigingen kloppen. Daarnaast controleer ik logs en statistieken om er zeker van te zijn dat de geplande Routine betrouwbaar werkt.

Voor op bestanden gebaseerde sessies gebruik ik twee beproefde varianten:

  • Een PHP-regel die de interne GC aanroept (vanaf PHP 7.1):
*/5 * * * * php -d session.gc_probability=1 -d session.gc_divisor=1 -r 'session_gc();' 2>/dev/null
  • Een find-cleanup die de mtime vergelijkt met de gewenste levensduur:
*/5 * * * * find /var/lib/php/sessions -type f -mmin +30 -delete

Ik houd de cron-looptijd in de gaten. Als vijf minuten niet voldoende zijn, verhoog ik de frequentie of verlaag ik de levensduur. In drukbezochte opstellingen draait de cron elke minuut om de directory klein te houden.

Diagnose en monitoring

Ik herken GC-pieken aan verhoogde responstijden en opvallende I/O-pieken in de Controle. Tools in de WordPress-context, zoals Query Monitor, helpen bij het identificeren van traag werkende hooks, plug-ins en admin-aanroepen. Een blik in de toegangs- en foutenlogboeken laat zien wanneer verzoeken aanzienlijk langer duren. Veel kleine pieken van 200 ms zijn normaal, maar uitschieters van enkele seconden duiden op locking of GC. Als je ook het aantal bestanden en de grootte van de map in de gaten houdt, zie je hoe de sessiemap volloopt en waarom een geplande Opruimen nodig is.

Praktische hulpmiddelen voor het opsporen van oorzaken:

  • Activeer php-fpm slowlog en request_slowlog_timeout om blokkerende punten te zien.
  • iotop, iostat, pidstat en vmstat om I/O-druk en contextwisselingen te detecteren.
  • strace -p kortstondig om geopende bestanden en vergrendelingen te bekijken.
  • find | wc -l op het sessiepad om de hoeveelheid bestanden te meten.
  • TTFB- en p95/p99-latenties in APM om verbeteringen na de overstap te kwantificeren.

WordPress-specifieke controles

Ik controleer plug-ins die session_start() vroeg aanroepen en vervang kandidaten met onnodig sessiegebruik door Alternatieven. In Admin verminder ik de heartbeat-frequentie of beperk ik deze tot de redactiepagina's. Caches mogen sessies niet omzeilen, anders gaat het effect verloren; daarom controleer ik uitzonderingen zorgvuldig. Ook belangrijk: geen sessie voor gasten als daar geen reden voor is. Zo neemt de hoeveelheid bestanden per dag merkbaar af en wordt de geplande GC heeft minder te doen.

In WooCommerce-omgevingen let ik vooral op winkelwagen- en fragmentfuncties die sessies voor anonieme gebruikers genereren. Vaak is het voldoende om sessies pas te starten bij echte interacties (inloggen, afrekenen). Daarnaast zorg ik ervoor dat WP-Cron niet parallel veel belasting veroorzaakt: ik laat WP-Cron door een systeem-Cron activeren en deactiveer de uitvoering per verzoek. Dit voorkomt dat Cron-taken conflicteren met sessiebewerkingen.

Veiligheid, levensduur en gebruikerservaring

Langere levensduur houdt gebruikers ingelogd, maar verhoogt de hoeveelheid oude Sessies. Kortere waarden verlagen de belasting, maar kunnen aanmeldingen eerder beëindigen. Ik kies daarom periodes die risico en comfort in evenwicht houden, bijvoorbeeld 30-60 minuten in de admin en korter voor anonieme gebruikers. Bij bijzonder gevoelige inhoud stel ik strikte modi in en beveilig ik cookies tegen XSS en transportfouten. Zo blijven gegevens beschermd, terwijl de Prestaties blijft betrouwbaar.

Na het inloggen roteer ik sessie-ID's (session_regenerate_id(true)) om fixatie te voorkomen en gebruik ik consequent cookie_same_site, httponly en secure. In single-sign-on-scenario's plan ik bewust de SameSite-keuze (Lax vs. None) om de gebruikerservaring stabiel te houden.

Clusters, load balancers en sticky sessions

Wie meerdere app-servers beheert, moet alleen bestandsgebaseerde sessies met sticky sessions gebruiken, anders raken gebruikers hun status kwijt. Een centrale RAM-opslag is beter. Ik controleer de latentie tussen de app en de opslag, stel time-outs kort maar niet agressief in en plan een failover (bijv. Sentinel/Cluster bij Redis). Bij onderhoud is het belangrijk om TTL's zo te kiezen dat een korte storing niet onmiddellijk leidt tot massale uitloggingen.

Economische afweging en migratietraject

Overstappen op Redis of Memcached kost geld, maar levert ook besparingen op. Tijd per verzoek en vermindert het aantal supportcases. Wie vaak in Admin werkt, merkt het verschil meteen. Ik beoordeel de besparingen door snellere implementaties, minder frustratie en minder onderbrekingen. Als de belasting toeneemt, plan ik de migratie vroeg in plaats van laat om knelpunten te voorkomen. Een duidelijk stappenplan omvat tests, uitrol en monitoring totdat de Latency stabiel en de GC-runs blijven onopvallend.

Ik ga stapsgewijs te werk bij de overstap: in staging activeer ik de RAM-store, voer ik synthetische belasting uit en controleer ik p95/p99-latenties. Vervolgens rol ik met behulp van feature flags in kleine percentages uit en observeer ik foutpercentages en time-outs. Een rollback blijft eenvoudig als ik session.name parallel kan variëren, zodat sessies tussen de oude en nieuwe backend niet met elkaar in conflict komen. Belangrijke indicatoren zijn: sessiebestanden per uur (moet dalen), mediane TTFB (moet dalen), 5xx-percentage (moet stabiel blijven) en percentage verzoeken met sessielock van meer dan 100 ms (moet sterk dalen).

Kort samengevat

De php session gc veroorzaakt vertragingen omdat willekeurig gestarte opruimingsprocessen lange bestandsbewerkingen en vergrendelingen veroorzaken. activeren. Ik verminder dit door de waarschijnlijkheid in verzoeken op nul te zetten, de opschoning via cron te plannen en sessies in RAM-opslagplaatsen te plaatsen. Hostingbronnen met snelle NVMe en voldoende RAM verminderen de blokkering nog verder. WordPress profiteert merkbaar wanneer Heartbeat wordt getemperd, plug-ins worden gecontroleerd en onnodige sessies worden vermeden. Wie deze stappen in acht neemt, verkort de responstijden, voorkomt blokkades en houdt de Admin-Reactief oppervlak, ook bij veel verkeer.

Huidige artikelen