Kodėl serverio greitis tapo kritiškai svarbus
Prisimenu, kaip prieš keletą metų dirbau projekte, kur klientas skundėsi, kad svetainė „kažkaip lėtai veikia”. Pasitikrinom – serverio atsakymo laikas siekė 4 sekundes. Keturias! Šiandien tokį rezultatą Google PageSpeed Insights pažymėtų raudonu indikatorium ir pasiūlytų rimtai susimąstyti apie karjeros keitimą.
Realybė tokia, kad vartotojai tapo nekantrūs kaip niekad. Jei puslapis neužsikrauna per 2-3 sekundes, didelė dalis jų tiesiog išeina. O paieškos sistemos? Jos serverio atsakymo laiką (TTFB – Time To First Byte) vertina kaip vieną iš svarbiausių SEO faktorių. Taigi optimizavimas čia nėra malonumas, o būtinybė.
Kas iš tikrųjų lėtina serverį
Prieš šokant į sprendimus, reikia suprasti problemos šaknis. Dažniausiai susiduriau su tokiais „nusikaltėliais”:
Neoptimizuotos duomenų bazės užklausos – tai klasika. Matai kodą, kur vykdoma 50+ SQL užklausų vienam puslapiui užkrauti, ir supranti, kad kažkas čia labai ne taip. N+1 problema yra viena populiariausių – kai cikle kiekvienam elementui daroma atskira užklausa vietoj vienos bendros su JOIN.
Serverio resursų trūkumas – kai PHP procesas bando apdoroti 200 vienu metu atėjusių užklausų su 512MB RAM, rezultatas būna… liūdnas. Panašiai kaip bandyti paleisti Cyberpunk 2077 ant 2010-ųjų kompiuterio.
Išorinio turinio užkrovimas – API užklausos į lėtus trečiųjų šalių servisus, socialinių tinklų widgetai, reklamos skriptai. Vienas lėtas išorinis šaltinis gali sulėtinti visą puslapį.
Nepakankamas kešavimas – arba jo visiškas nebuvimas. Kai serveris kiekvieną kartą generuoja tą patį turinį iš naujo, nors jis nesikeičia savaitėmis.
Duomenų bazės optimizavimas – pirmasis žingsnis
Pradėkim nuo to, kas dažniausiai sukelia didžiausią problemą – duomenų bazės. MySQL ar PostgreSQL – nesvarbu, principai panašūs.
Pirmiausia įjunk slow query log. MySQL atveju tai daroma my.cnf faile:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-queries.log
long_query_time = 2
Tai leis identifikuoti užklausas, kurios užtrunka ilgiau nei 2 sekundės. Tikėkitės nustebti – kartais randi užklausas, kurios vyksta 30+ sekundžių.
Toliau – indeksai. Tai kaip knygos turinys – be jo tenka vartyti visas puslapius, ieškant reikiamos informacijos. Patikrink EXPLAIN OUTPUT savo lėtoms užklausoms:
EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
Jei matai „type: ALL” – tai reiškia full table scan, ir tau reikia indekso. Sukurk jį:
CREATE INDEX idx_email ON users(email);
Bet atsargiai – per daug indeksų taip pat bloga. Kiekvienas indeksas lėtina INSERT ir UPDATE operacijas. Reikia balanso.
Dar vienas dažnas kostiumas – SELECT * naudojimas. Nedaryk to. Jei reikia tik 3 stulpelių, tai ir paprašyk tik jų. Serveris bus dėkingas, kad nereikia tempti 50 stulpelių duomenų, kai tau reikia tik id, name ir email.
Kešavimo strategijos, kurios realiai veikia
Kešavimas – tai kaip turėti paruoštus atsakymus į dažniausiai užduodamus klausimus. Yra keletas lygių, kur galima kešuoti.
OPcache PHP – jei naudoji PHP ir dar neįjungei OPcache, sustok skaityti ir daryk tai dabar. Rimtai. Tai kompiliuoja PHP kodą į bytecode ir laiko atmintyje, vietoj to, kad kiekvieną kartą kompiliuotų iš naujo. Greičio padidėjimas – 2-3 kartus, be jokių kodo pakeitimų.
php.ini nustatymai:
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
Paskutinė eilutė production serveriuose išjungia failo pakeitimų tikrinimą – dar didesnis greitis.
Redis arba Memcached – tai jau kitas lygis. Čia kešuoji duomenų bazės užklausų rezultatus, sesijas, bet kokius duomenis, kuriuos brangiai „pagaminti”. Pavyzdžiui, Laravel projekte:
$users = Cache::remember('active_users', 3600, function () {
return DB::table('users')->where('active', 1)->get();
});
Pirmą kartą vykdoma užklausa, rezultatas išsaugomas 3600 sekundžių (1 valandai). Kiti užklausos gaunami iš kešo per milisekundes.
HTTP kešavimas – naudok Varnish arba bent jau Nginx fastcgi_cache. Tai leidžia kešuoti pilnus HTML atsakymus ir atiduoti juos net nepaleidžiant PHP. Greitis? Nuo 200ms iki 5ms. Jausti skirtumą.
Serverio konfigūracija ir resursai
Kartais problema ne kode, o pačiame serveryje. Jei naudoji shared hosting už 3 eurus per mėnesį, nesitikėk stebuklų. Bet net su geresniu serveriu reikia teisingai sukonfigūruoti.
PHP-FPM nustatymai – tai kritiškai svarbu. Daugelis naudoja default nustatymus, kurie skirtiems serveriam su 16GB RAM, o turi tik 2GB. Rezultatas – swap’inimas ir lėtumas.
Patikrinom, kiek RAM sunaudoja vienas PHP procesas:
ps aux | grep php-fpm | awk '{sum+=$6} END {print sum/NR/1024 " MB"}'
Tarkime, gavai 50MB. Jei turi 2GB RAM, saugiai gali turėti ~30 procesų (palikdamas vietos kitoms programoms). Tuomet www.conf faile:
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
Nginx worker procesai – paprastai turėtų būti tiek, kiek turi CPU core’ų:
worker_processes auto;
worker_connections 1024;
Ir labai svarbus dalykas – keepalive timeout. Per ilgas timeout laiko atvirą connection’ą, nors jis nebereikalingas. Per trumpas – verčia kiekvieną užklausą kurti naują. Aš paprastai naudoju:
keepalive_timeout 15;
CDN ir statinio turinio optimizavimas
Net jei serveris atsakinėja žaibiškai, didelis statinis turinys gali viską sugadinti. Čia padeda CDN (Content Delivery Network).
Cloudflare – nemokama versija jau duoda daug. Jie kešuoja statinį turinį savo serveriuose visame pasaulyje. Vartotojas iš Lietuvos gauna failus iš Varšuvos ar Frankfurto, ne iš tavo serverio Amerikoje.
Bet prieš tai – optimizuok pačius failus. Paveikslėlius konvertuok į WebP formatą, naudok lazy loading. CSS ir JS failus minifikuok ir sujunk. Webpack, Vite ar kiti build tools tai daro automatiškai.
Dar vienas trikis – HTTP/2 arba HTTP/3. Jei dar naudoji HTTP/1.1, prarandi daug greičio. Naujesni protokolai leidžia siųsti kelis failus vienu metu per vieną connection’ą. Nginx su Let’s Encrypt sertifikatu HTTP/2 įjungiamas paprastai:
listen 443 ssl http2;
Monitoringas ir nuolatinis tobulinimas
Optimizavimas nėra vienkartinis veiksmas. Tai nuolatinis procesas. Reikia stebėti, kaip serveris veikia realybėje.
New Relic arba Blackfire.io – profesionalūs įrankiai, kurie rodo, kur tiksliai leidžiamas laikas. Matai, kad 80% laiko eina vienai funkcijai? Žinai, ką optimizuoti.
Nemokama alternatyva – Xdebug profiling, nors jis labiau development’ui. Production’e geriau naudoti ką nors lengvesnio.
Paprastas bet efektyvus būdas – application logging. Įdėk laiko matavimus į kritines vietas:
$start = microtime(true);
// tavo kodas
$time = microtime(true) - $start;
Log::info('Function X took: ' . $time . ' seconds');
Peržiūrėdamas logus, greitai pamatysi, kas lėtina.
Taip pat naudok Google PageSpeed Insights ir GTmetrix. Jie ne tik parodo problemą, bet ir pasiūlo konkrečius sprendimus. Kartais net su kodo pavyzdžiais.
Kada verta investuoti į horizontalų skalėjimą
Kartais optimizavimas pasiekia ribą. Vienas serveris, kad ir kaip gerai sukonfigūruotas, turi fizinį limitą. Tuomet reikia galvoti apie skalėjimą.
Load balancer su keliais aplikacijos serveriais – klasikinis sprendimas. Nginx arba HAProxy paskirsto apkrovą tarp kelių serverių. Jei vienas sugenda, kiti tęsia darbą.
Atskiras duomenų bazės serveris – kai aplikacija ir DB yra skirtinguose serveriuose, abi gali naudoti pilnus resursus. Dar geriau – master-slave setup, kur read operacijos eina į slave, write – į master.
Mikroservisų architektūra – jei tam tikros aplikacijos dalys labai resursų reiklios (pvz., video konvertavimas), iškelk jas į atskirą servisą. Pagrindinis aplikacijos serveris nedirbs sunkaus darbo.
Bet prieš šokant į tokius sprendimus, įsitikink, kad išnaudojai visas optimizavimo galimybes vienoje mašinoje. Horizontalus skalėjimas prideda kompleksiškumo – deployment’as, monitoring’as, debugging’as tampa sudėtingesni.
Kai greitis tampa verslo pranašumu
Grįžkim prie to projekto, kurį minėjau pradžioje. Po dviejų savaičių optimizavimo – duomenų bazės indeksai, Redis kešavimas, PHP-FPM konfigūracija, CDN – serverio atsakymo laikas nukrito nuo 4 sekundžių iki 400 milisekundžių. Dešimt kartų greičiau.
Rezultatai? Conversion rate pakilo 23%, bounce rate sumažėjo 31%, o Google reitingai pradėjo kilti. Klientas buvo laimingas, vartotojai – dar labiau.
Optimizavimas nereikalauja stebuklų ar raketų mokslo. Reikia sisteminio požiūrio: identifikuoti problemą, išmatuoti, optimizuoti, patikrinti rezultatą. Ir kartoti. Pradėk nuo paprasčiausių dalykų – duomenų bazės užklausų, OPcache, Redis. Tai duos didžiausią efektą mažiausiomis pastangomis.
Atmink, kad kiekviena sutaupyta milisekundė – tai geresnė vartotojo patirtis, didesnis konversijos rodiklis ir geresni paieškos rezultatai. Šiuolaikiniame internete greitis nėra prabanga – tai standartas, kurio visi tikisi. Tad neatidėliok, pasitikrinom savo serverio atsakymo laiką ir pradėk optimizuoti. Tavo vartotojai ir Google tau padėkos.

