Am redus TTFB la PHP 8.1 mutând sesiunile din fișiere în Redis

这篇内容暂时只有 Română 版本,以下是原文。

Pe un PHP 8.1 cu PHP-FPM (procese statice, 24 de copii) și un Apache în față, un endpoint de dashboard răspundea în 1,4–1,8 s la TTFB, deși interogările SQL luau sub 40 ms fiecare. Trafic de ~90 req/s, sesiuni salvate implicit în /var/lib/php/sessions pe același disc cu logurile. Vârful era la login și la primele accesări dimineața, când mii de utilizatori își reînnoiau sesiunea.

Primul pas a fost să măsor, nu să ghicesc. Am pornit un strace pe un worker și am văzut că majoritatea timpului se ducea în open/read/close pe fișiere de sesiune, nu în aplicație. Apoi am confirmat cu un test mic:

# câte fișiere de sesiune și cât ocupă
find /var/lib/php/sessions -type f | wc -l
du -sh /var/lib/php/sessions
# latența unui read de sesiune
php -r '$t=microtime(true); for($i=0;$i<5000;$i++){session_id("test".$i); session_start(); session_write_close();} echo microtime(true)-$t, "\n";'

Media era ~2,3 ms per ciclu, dar coada pe disc la vârf o împingea spre 15–25 ms. Am mutat sesiunile în Redis, care rula deja pentru cache, cu o configurație minimă:

; php.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?database=2&timeout=0.5&read_timeout=0.5"
session.gc_maxlifetime = 1440
session.lock_strict = 1

Și am adăugat un control de sănătate ca să nu pic tot site-ul când Redis nu răspunde:

if (!@fsockopen('127.0.0.1', 6379, $errno, $errstr, 0.2)) {
    ini_set('session.save_handler', 'files');
}
session_start();

TTFB a scăzut la 380–520 ms pe același trafic. Mecanismul e simplu: handlerul de fișiere serializează accesul prin lock pe inode, iar pe un disc partajat cu scrieri de log apar cozi. Redis ține sesiunea în memorie și nu mai atinge discul, dar schimbi un cost: latența rețelei și dependența de un serviciu în plus. La 90 req/s a meritat; la 5 req/s nu aș fi făcut-o.

Unde se strică: dacă Redis e pe alt host fără timeout scurt, un hiccup de rețea blochează toate cererile care așteaptă lock-ul de sesiune. Am pățit-o o dată cu timeout implicit și am avut 40 de secunde de 502. De asemenea, session.lock_strict nu ajută dacă aplicația ține sesiunea deschisă toată cererea; atunci serializezi pe Redis în loc de disc. Și nu uitați de maxmemory-policy: cu allkeys-lru puteți pierde sesiuni active fără nicio eroare în log.

Voi ce handler de sesiune folosiți în producție și ați măsurat vreodată costul lock-ului pe fișier la vârf?

0
赞同度 100% · 0 条评论 · 5 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。