Andreas Bergman

Icon

Högtrafikerade webbsidor med Nginx och PHP-FPM

Nginx och PHP-FPM har blivit något av en standard för högtrafikerade webbsidor, kombinationen en lättviktig webbserver och en vertikalt skalbar scriptmotor med relativt litet avtryck gör att det är ett prisvärt och smidigt sätt att driva sin webbsida.

Av någon anledning så kommer dom flesta linuxdistributioner, och de programpaket som skeppas med en minimal konfiguration, vilket gör att man ganska snabbt stöter på problem och flaskhalsar på grund av lågt satta begränsningar i operativsystemet.

En av de begränsningar man stöter på är att antalet tillåtna file descriptors (FD) för användaren som webbservern och eller PHP-FPM körs som är för lågt satta. Debian 6 skeppas med 1024 file descriptors / användare, och maxantalet i systemet brukar vara runt 3 miljoner. Exakt vilket antal FD man bör ha på användaren är svårt att säga, men förutsatt att servern inte kör fler applikationer än Nginx och PHP-FPM så kan man ta i ganska rejält, på en stor installation jag jobbar med så har användaren en gräns på runt 300 000, men jag kan inte se något fel i att öka den ännu mer.

Att felsöka filedescriptors

Till att börja med så vill man veta hur många FDs som systemet får ha som mest.

# sysctl fs.file-max
fs.file-max = 70000

Nu vet vi att systemet som mest kan ha 70 000 FDs. Hur många FDs används då?

#sysctl fs.file-nr
fs.file-nr = 1020 0 70000

Där 1020 är antalet aktiva filer (file handles), 0 antalet allokerade men inaktiva filer, och 70 000 är max antal. För att ta reda på max antal FDs för en specifik annvändare, logga in som användaren och kör:

#ulimit -Sn
1024
#ulimit -Hn
1024

ulimit talar om för dig hur många FDs som användaren får lov att ha öppna, 1024 är lagom för de flesta, men har du högt trafikerade servrar så kommer du behöva höja, det gör du genom att ändra gränsen i /etc/security/limits.conf

abergman                soft    nofile          65535
abergman                hard    no file          65535

Det gör att min användare, abergman får lov att ha 65535 file descriptors, för att ändringen ska slå igenom så måste webbservern och PHP-FPM startas om.

Referenser för dig som vill läsa mer, även ett stort tack till Tom för att han pekade mig i rätt riktning vad gäller mod_limits i PAM.
http://www.cs.uwaterloo.ca/~brecht/servers/openfiles.html
http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/
http://research.cs.wisc.edu/condor/condorg/linux_scalability.html

Nginx Cache och WordPress

Använder du nginx inbyggda cache för att minska loaden på din server? Då är det här en plugin för dig, http://wordpress.org/extend/plugins/nginx-manager/

Den purgear automatiskt relevanta delar av Nginx cache när du postar ett nytt inlägg i din wordpress.

Skapa användningsgrafer för Nginx

I en tidigare post(http://www.abergman.se/hall-koll-pa-din-nginx-servers-status/) skrev jag om en modul för att hålla koll på Nginx status.

Alla som vet något om sälj, vet att säljare och chefer älskar statistik, dessutom så är det ganska smidigt för att se trender över tid, så man kan motivera att köpa in en ny server.

För att göra det så har en smart snubbe(http://kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/) skrivit ett litet RRD script för att skapa grafer.

Ladda ner scriptet: http://kovyrin.net/files/mrtg/rrd_nginx.pl.txt

Innan du provar köra det, installera de här paketen om du inte redan har dem:

librrds-perl
libwww-perl

Anpassa inställningarna i scriptet så de passar dig, så bilderna landar där du vill ha dem etc. Sedan lägger du in en rad i cron för att köra scriptet en gång i minuten.

* *     * * *   root    /some/path/rrd_nginx.pl

Jag använde crontab -e, så jag uteslöt “root” ur min fil.

Om allt funkar kommer scriptet nu att spotta ur sin finfina grafer, som du tex kan infoga på en HTMLsida för att kunna kika på dem via webbläsaren, eller så kan du använda dem i nästa rapport där du ber om en ny server.


			

Håll koll på din Nginx servers status

Vill du veta hur många anslutningar som din nginxserver har aktiva just nu? Eller hur många anslutningar den har tagot emot totalt? Eller vill du skapa en asfet graf i ditt övervakningssystem på hur mycket last Nginx tar?

Oavsett så löser du det såhär:

location /nginx_status { 
  stub_status on;
  access_log   off;
  allow EN.IP.ADRESS;
  deny all;
}

Det ska skrivas i en site-config och inte direkt i nginx.conf. Om du inte riktigt bryr dig om vem som tittar på dina stats, eller om du kanske rent utav vill visa upp dem så kan du ju alltid sätta “allow all” och ta bort “deny all”.

Förhindra att PHP-FPM sänker din server

Igår kväll hade jag problem med att en av våra servrar höll på att gå under, vi har nyligen satt igång ett ganska prestandakrävande script på maskinen, och av någon anledning så verkar det ha hängt sig. Eftersom jag inte är skaparen av scriptet så låter jag det förbli osagt varför.

För att förhindra att PHP-FPM sänker din server så finns det en inbyggd funktion för att sätta max_execution_time, PHP har en egen variabel för det i php.ini, men om den inte funkar så kommer FPM döda workern åt dig. Det finns också en fin funktion som loggar vilka phpscript som kör för länge, på så sätt kan man hålla utkik och enkelt felsöka sina applikationer.

request_terminate_timeout = 30m
; The timeout for serving a single request after which a PHP backtrace will be
; dumped to the 'slowlog' file. A value of '0s' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_slowlog_timeout = 5s

; The log file for slow requests
; Default Value: /var/log/php5-fpm.log.slow
slowlog = /var/log/php5-fpm.log.slow

Jag väljer att ha 30minuters gräns för hur länge ett script får lov att köra, och det loggas i php5-fpm.log.slow efter 5s, på så sätt får jag snabbt information om ifall det är något som gått snett. Glöm inte starta om php5-fpm för att ändringarna ska slå igenom.


			

Benchmarktest Nginx vs Apache2 och Cherokee

Jag ska under natten och morgondagen företa mig att göra benchmarktester av Nginx, Apache2 och Cherokee. De två första är jag väldigt bekant med, men Cherokee bli en ny bekantskap för mig. Cherokee ska jag också passa på att presentera lite mer utförligt och se hur det fungerar med PHP, så det blir en benchmark av WordPress och PHP också, precis om i den här posten: http://www.abergman.se/w3-total-cache-och-nginx/

Precis som förra gången så kommer jag att publicera resultatet dels här och på www.cmsdirekt.se, stay tuned!

Nginx och dess loggar

Jag kom idag på en sak som jag förbisett tidigare, nämligen debug-flaggans potential att skapa gigantiska loggfiler, debugflaggan kan man slå på för errorloggarna och då får man fram massor av fantastisk information, tex vilka regler i vhosten som slår på aktuell request eller vilka fel som php-genererar. Dock så blir det ganska stora filer, så det rekomenderas att antingen hålla ordentlig koll på filerna, eller slå av flaggan om du inte jobbar med att debugga siten.

Då jag har så många siter igång och inte orkar ändra alla vhostar så valde jag att skriva om reglerna för logrotate samt sätta maxfile size kontroller på filerna, eftersom en bra errorlog är en tom errorlog:) så nu får jag ett larm om någon fil överstiger 1Mb.

W3 total cache och Nginx

Inom kort kommer www.cmsdirekt.se att publicera en jämförelse mellan apache2 och Nginx prestanda på en wordpress installation, dock så kan jag redan nu(eftersom det var jag som gjorde testerna) avslöja att skillanden i prestanda på siten med och utan W3 total cache är några 100%, sedan följer siege resultat från Nginx.

Med W3 total cache:

Transactions:                    1888 hits
Availability:                  100 %
Elapsed time:                  60.24 secs
Data transferred:               8.30 MB
Response time:                  0.84 secs
Transaction rate:              31.31 trans/sec
Throughput:                     0.14 MB/sec
Concurrency:                   26.22
Successful transactions:        1888
Failed transactions:               0
Longest transaction:           29.90
Shortest transaction:           0.05

Utan W3 total cache

Transactions:                      90 hits
Availability:                 100.00 %
Elapsed time:                  60.10 secs
Data transferred:               0.39 MB
Response time:                 16.57 secs
Transaction rate:               1.50 trans/sec
Throughput:                     0.01 MB/sec
Concurrency:                   24.81
Successful transactions:          90
Failed transactions:               0
Longest transaction:           21.02
Shortest transaction:          15.08

Som tydligt framgår så är det en enorm skillnad! Mer detaljer kommer dock i artikeln på www.cmsdirekt.se. Se det här som en liten preview:)

Konfigurera Nginx och Varnish

I mitt lilla projekt om att sätta upp ett eget CDN, Content Delivery Network så har jag nu konfigurerat om Nginx samt installerat Varnish. Det funkar så att Varnish ligger som gateway på port 80 och går igenom alla inkommande requests, om någon request matchar konfigurationen i Varnish så hanterar den det enligt gällande regler. För att uppnå det måste Nginx konfigureras om för att lyssna på en annan port, jag valde för enkelhetens skull port 8080.

 Om du inte redan har installerat Nginx, så finns en guide här

Konfiguration av Nginx, ändra nedan i alla dina vhostar:

Listen 8080

Det gör att Nginx kommer att lyssna på port 8080 istället för 80, det är viktigt att ställa om det på alla vhostar, annars kommer nginx eller varnish inte starta om ordentligt. vill du kan du även skriva 127.0.0.1:8080 så kommer Nginx att bara lyssna på requests som kommer internt på maskinen och inte externt, jag väljer att inte skriva det då jag vill kunna komma åt webbservern direkt externt också, i testsyften.

Installation av Varnish

Varnish finns i Debian stabels paketförråd och installeras med:

apt-get install varnish

Sedan så är det mer eller mindre klart, varnish startas med /etc/init.d/varnish och loggdemonen med /etc/varnishlog start, med största sannolikhet är de redan startade. 

Nu börjar det roliga, men samtidigt besvärliga, vad är det jag vill cacha? Jag har ett enkelt exempel där jag bara cachar statiska filer på en viss domän:

backend default {
        set backend.host = “127.0.0.1″;
        set backend.port = “8080″;
}

sub vcl_recv {
           if (req.http.host ~ “http://cdn.sngw.se“) {
             pass;
           } else {
             if (req.request != “GET” && req.request != “HEAD”) {
                 pipe;
             }
             if (req.request == “POST”) {
                 pass;
             }
             if (req.request == “GET” && req.url ~ “\.(jpg|jpeg|gif|ico|png)$”) {
                 lookup;
             }
             if (req.request == “GET” && req.url ~ “\.(css|js)$”) {

 lookup;
             }

             if (req.request == “GET”) {
                 lookup;
             }
             lookup;
          }
        }
         sub vcl_pipe {
             pipe;
         }

         sub vcl_pass {
             pass;
         }

         sub vcl_hit {
             if (!obj.cacheable) {
                 pass;
             }
             if (req.http.Cookie) {
                pass;
             }
             deliver;
         }

         sub vcl_miss {

fetch;
         }

         sub vcl_fetch {
             if (!obj.valid) {
                 error;
             }
             if (!obj.cacheable) {
                 pass;
             }
             insert;
         }

         sub vcl_deliver {
             deliver;
         }

         sub vcl_timeout {
             discard;
         }

         sub vcl_discard {

     discard;

         }

 

De här reglerna  cache:ar bara statiska filer och gör ingenting konstigt med dem. Nu är du redo att fortsätta upptäcka mer fantastiska grejer med Varnish ocg nginx, lycka till!

Optimering med CDN (Content Delivery Network)

När man optimerar sidor jobbar man i många fall med att separera statiskt innehåll som bilder, javscript och css från dynamiska filer som .php. Eftersom de olika filtyperna har olika sätt att hanteras och olika uppdaterings/åldrigstid så väljer man ofta att leverera de olika filtyperna med olika webbservrar med olika cacheinställningar.

I många fall är det helt värdelöst att ha en dubbel uppsättning webbservrar att hålla koll på utan man väljer att lägga sina statiskafiler hos någon som kan leverera dem åt dig, ett så kallt Content Delivery Network(CDN).  Exempel på sådana är Amazon S3 och även flickr.

Ibland vill man själv ha koll på sitt innehåll och då kan det vara en idé att bygga ett eget CDN, hur man uppnår det på bästa sätt kan diskuteras men det alldra enklaste är helt enkelt att lägga dina filer på en annan server och länka in dem i dina dynamiska sidor.  För att sedan få lite kräm och hastighet på filerna bör du välja en webbserver som ärbra på statiska filer, tex nginx. Vill spara ännu mer kraft kan man även lägga en cache framför, som Varnish.

De stora CMS:erna WordPress och Drupal stöjder båda distribution av filerna till ett CDN, med häjlp av W3 Total Cache-modulen till WordPress kan du även lägga alla dina nyuppladdade filer på CDN:et mha FTP, helt sömlöst utan att dina användare och besökare märker det.

Inomkort kommer det en praktisk guide här på www.abergman.se på hur man bygger ett eget CDN, eller ett PCDN, Private CDN.

Den här bloggen

skriver jag, Andreas Bergman, vilket i sig inte bör vara så förvånande. Jag driver en SMS tjänst och jobbar som tekniker/allt i allo på SEA där jag bland annat driftar en stor bloggportal och ett webbhotell. Vi håller även på att bygga ett datacenter.


Jag har några microsoft titlar, ett gäng DELL certifikat och jobbar dagligen med hårt belastade webbservrar. Utöver det jobbar jag också med virtualisering och server/storage. Någon gång ibland säljer jag även server och storagelösningar.

Maila mig gärna om något av ovan, eller annat, jag är ganska trevlig sägs det. andreas@abergman.se.