Användning av reglerteknik i Apache HTTP

Användning av reglerteknik i Apache HTTP-servern
Erik Lindegren
Idag när användning av datorsystem är större än någonsin har också kraven på dessa ökat. I
synnerhet har vi blivit mer beroende av Internet och de många olika typer av servicesystem som
finns där. Internet används för att bland annat hantera bankärenden, boka resor och läsa nyheter.
Enligt Statistiska centralbyrån hade över 80% av alla människor i Sverige i åldrarna 16-74 tillgång
till Internet på något sätt i sina hem under 2007. Eftersom vi blivit så pass beroende av dessa
system är det viktigt att vi kan förlita oss på dem. Det gäller i synnerhet vid en krissituation. Som
exempel kan man ta 11:e september-attacken i New York 2001, mordet på utrikesminister Anna
Lindh 2003 och tsunami-katastrofen 2004. Vid dessa tillfällen har trycket på information varit så
stort att vissa system blivit överbelastade och således ej varit tillgängliga.
För servicesystem så brukar man mäta kvalitén av servicen som erbjuds klienten i följande
tre parametrar: svarstid, genomströmning och tillgänglighet. Problemen som uppkommer i dessa
system beror på ett antal begränsade resurser i systemet, vilka leder till att köer bildas. Vid
hög belastning kan det leda till att systemet slutar fungera. Det man vill åstadkomma med att
använda reglerteknik i dessa system kan vara att göra systemet mer robust genom att undvika
överbelastning, få en bra svarstid eller genomströmning genom att förbättra användningen av
systemets resurser.
I mitt arbete har jag fokuserat på hur man skulle kunna göra det möjligt att applicera reglerteknik på Apache HTTP-servern. Till skillnad från mekaniska system där man oftast har en god
intuitition om var problemen uppstår kan det vara svårt att få samma översikt för ett datorsystem.
Därför börjar jag med att gå igenom var köerna bildas, dvs. vilka de begränsade resurserna är.
Sedan berättar jag om vad jag har gjort för att kunna styra användningen av dessa resurser.
Som operativsystem använde jag Linux, vilket innebär att alla beskrivningar i den här artikeln
är relaterade till den plattformen. Anledningen till att jag valt Apache som webbserver och Linux
som operativsystem är för att det är den vanligaste serverkonfigurationen men främst för att de
båda är projekt med öppen källkod vilket gjorde det möjligt för mig att studera och att förändra
koden.
Bakgrund
En HTTP-server, eller det mer vanliga namnet webbserver, är något som många av oss använder dagligen. När vi använder en webbläsare för att hämta information från en annan dator på
Internet, så är det HTTP-servern som kör på den datorn som är ansvarig för att leverera informationen. Webbläsaren skickar förfrågan till servern i form av en HTTP-begäran. HTTP (HyperText-Transfer-Protocol) är ett nätverksprotokoll och används av webbläsaren för att specificera
vilket dokument på servern den vill hämta. HTTP är inte ansvarigt för att leverera själva datan
mellan servern och webbläsaren utan det görs istället av nätverksprotokollet TCP som även är
ansvarigt för att etablera anslutningen mellan webbläsaren och servern.
För att en webbläsares begäran ska kunna nå fram till rätt dator används en IP-adress för att
unikt identifiera varje dator på Internet. En dator kan i sin tur köra flera nätverksapplikationer
förutom en webbserver, så för att avgöra till vilken applikation en begäran är tänkt tilldelas varje
nätverksapplikation ett unikt heltal som kallas portnummer. Vanligtvis används portnummer 80
för en HTTP-server.
Webbservern får tillgång till operativsystemets TCP gränssnitt genom att använda två olika
typer av TCP socklar:
Lyssningssockel används för att etablera en anslutning till klienten. Det är lyssningssockeln som
är kopplad till datorns IP-adress och nätverksapplikationens portnummer och agerar därför
som en unik identifierare för HTTP-servern.
Anslutningssockel används för datautbyte med klienten.
1
1. Etablering av anslutningen
Webbläsare
HTTP-server
Lyssnar
Anslutningssockel
Lyssningssockel
IP: 130.235.83.17
Port: 80
Öppna kön
Backlog kön
Ny öppen begäran
2. Anslutningen etablerad
3. Begäran accepterad
Lyssningssockel
Lyssningssockel
IP: 130.235.83.17
Port: 80
IP: 130.235.83.17
Port: 80
HTTP-server
accepterar
4. Begäran behandlas
Webbläsare
HTTP-server
Anslutningssockel
Anslutningssockel
Figur 1: En kort beskrivning av hur en HTTP-server bestående av en enda process skulle kunna
använda en lyssningssockel och en anslutningssockel för att behandla en klients begäran.
1. Klientens webbläsare använder en anslutningssockel för att etablera en anslutning med servern, se Figur 1. På serversidan tas begäran hand om av en lyssningssockel. Under tiden
anslutningen sätts upp placerar lyssningssockeln den öppna begäran i en special kö som jag
har valt att kalla öppna kön.
2. När båda sidor har bekräftat anslutningen flyttas den öppna begäran från öppna kön till en
kö som kallas backlog. När begäran placeras i den kön så betyder det att den är redo att tas
hand om av nätverksapplikationen, som i detta fall är HTTP-servern.
3. När en begäran läggs till i backlog kön informerar lyssningssockeln processen (som den är
kopplad till), att det finns en begäran som är redo att bli behandlad. Processen kan sedan
välja att acceptera begäran och i och med det ta bort den från kön.
4. När HTTP-processen accepterar begäran returneras en anslutningssockel som den använder
för att behandla begäran.
En viktig funktionalitet för en webbserver, som både stöds av HTTP och TCP, är beständiga
anslutningar. Innan de fanns blev alltid den etablerade anslutningen till klienten nedkopplad så
fort servern var klar med behandlingen av klientens begäran. Om samma klient skickade en ny
begäran var servern tvungen att ännu en gång gå igenom alla de fyra stegen beskrivna i Figur 1.
Det ledde till onödiga fördröjningar när en webbsida innehöll många bilder, eftersom varje bild
då krävde en ny HTTP-begäran. För att lösa detta problem skapades beständiga anslutningar.
När dessa används kommer inte anslutningen mellan servern och klienten kopplas ned direkt efter
servern är klar med klientens begäran. Istället kommer anlutningen att hållas öppen och låta fler
begäranden från samma klienten använda samma anslutning. Vanligtvis specificeras ett värde för
hur länge den etablerade anslutning kan vara inaktiv innan den stängs ned.
I exemplet i Figur 1 existerar bara en server process. Vanligtvis används ett större antal processer
2
för att forma en webbserver för att kunna bearbeta flera HTTP-begäranden parallellt. Dessa processer kommer dela på samma lyssningssockel men använda olika anslutningssocklar. Ett exempel
på detta syns i Figur 2.
HTTP-server
ställ i kö
Sysslolös
process
Arbetande
process
Anslutningssockel
Anslutningssockel
Webbläsare
Arbetande
process
Anslutningssockel
Anslutningssockel
Webbläsare
Arbetande
process
Anslutningssockel
Anslutningssockel
Webbläsare
Sysslolös
process
Sysslolös
process
Lyssnare
behandla
begäran
Lyssningssockel
Öppna kön
TCP/IP kommunikationsservice
Backlog kön
Figur 2: Webbserver med parallellbearbetning.
De flesta datorer som används för att köra en HTTP-server har bara en centralprocessor, så för
att göra det möjligt för flera HTTP-processer att köra samtidigt måste de turas om att använda
processorn (tidsdelning) vilket leder till att ännu en slags kö uppkommer i systemet (se Figur 3).
En annan viktig resurs som kommer delas av processerna är internminnet. Eftersom centralprocessorn och internminnet är de viktigaste resurserna är det viktigt att kunna reglera antalet
HTTP-processer.
Server-processer
Centralprocessor
Figur 3: Delning av centralprocessorn.
Apache HTTP-servern
Apache HTTP-servern har varit den mest populära webbservern sedan 1995 och finns tillgänglig
för de flesta plattformar. Apache har stöd för parallellbearbetning vilket betyder att den kan
hantera flera begäranden samtidigt. Hur parallellbearbetningen är implementerad beror mycket
på vilket operativsystem servern körs på. Därför har implementationen för detta brutits ut i ett
antal laddningsbara moduler, så kallad Multi-Processing-Modules. Den förvalda modulen för Linux
och den jag använde heter Prefork, se Figur 4.
Med Prefork-modulen skapas alla serverprocesser (barnprocesser) som kopior av en grundprocess
(förälderprocess). Förälderprocessen är ansvarig för att reglera antalet sysslolösa barnprocesser.
Barnprocesserna är i sin tur ansvariga för att behandla HTTP-begäranden från klienter. Ett antal
sysslolösa barnprocesser finns alltid redo för att snabbt kunna ta hand om nya begäranden, så att
servern slipper skapa nya processer för varje begäran. Bara en barnprocess i taget är tillåten att
3
Scoreboard
process
status
Förälderprocess
...
ställ i kö
Sysslolös
process
Apache
HTTP-servern
delat
minne
Arbetande
process
Arbetande
process
Barnprocessernas
huvudloop
Sysslolös
process
Sysslolös
process
Lyssnare
Arbetande
process
behandla
begäran
Figur 4: Parallellbearbetningsstrukturen för Apache servern när Prefork-modulen används.
använda lyssningssockeln för att lyssna efter inkommande begäranden. När en begäran anländer
omvandlas den lyssnande processen till en arbetande process och hanterar begäran. Efter det att
begäran har blivit färdigbehandlad går den arbetande processen tillbaka till att bli en sysslolös
process och ställer sig i kö för att få tillgång till lyssningssockeln.
Påverkan
För att kunna reglera ett system måste man ha möjlighet att mäta hur det beter sig och utifrån
det kunna påverka systemet för att förändra dess beteende. Förälderprocessen använder en datastruktur som kallas scoreboard för detta. Den innehåller information om varje enskild barnprocess
och lagras i delat minne, vilket leder till att både förälder- och barnprocesserna har tillgång till
den. Förälderprocessen reglerar antalet sysslolösa barnprocesser utifrån följande tre parametrar
som är möjliga att ändra i Apaches konfigurationsfil:
MinSpareServers Minsta antalet sysslolösa barnprocesser
MaxSpareServers Maximala antalet sysslolösa barnprocesser
MaxClients Maximala antalet barnprocesser
Regleringen försöker hålla antalet sysslolösa barnprocesser mellan MinSpareServers och MaxSpareServers värdena utan att få det totala antalet barnprocesser att övergå MaxClients värdet.
Jag ville ha en mer direkt kontroll över det totala antalet barnprocesser, dvs inte enbart över
de sysslolösa processerna, så jag avaktiverade Apaches inbyggda reglering och skapade en egen.
För att göra det möjligt var jag tvungen att ändra i källkoden för Apache servern och lägga till
följande parametrar:
want running Antalet barnprocesser som ska finnas i systemet
running Antalet barnprocesser som finns
running idle Antalet sysslolösa barnprocesser
Med den här uppsättningen är det bara en parameter, nämligen want running, som används för
att påverka det totala antalet barnprocesser i systemet. Jag gjorde det möjligt att ändra värdet på
den parametern under körningens gång. De andra två parametrarna är bara informationsvariabler,
som kan användes till att bestämma ett värde på want running parametern. Exempelvis skulle
en regulator som har tillgång till dessa tre parametrar fortfarande ha möjlighet att reglera antalet
4
sysslolösa barnprocesser i systemet precis som Apaches inbyggda reglering.
Förutom att jag ändrade Apaches inbyggda reglering av sina barnprocesser gjorde jag det även
möjligt att ändra följande parametrar i realtid:
KeepAliveTimeout Antalet sekunder som servern ska vänta på en ny begäran från samma klient
innan den beständiga anslutningen mellan servern och klienten stängs ned.
ListenBackLog Maximala antalet öppna begäranden i lyssningssockelns backlog kö.
Dessa två parametrar tillsammans med want running parametern gör att man med en regulator
har stora möjligheter att påverka serverns beteende och prestanda.
Mätningar
För att en regulator ska kunna fatta några beslut om vad för återgärder den ska ta måste den veta
hur väl servern fungerar. Därför la jag till följande mätvariabler i Apaches källkod och gjorde de
tillgängliga i realtid:
Apaches svarstid Medeltiden det tar för Apache att behandla en begäran från det att en barnprocess accepterar en begäran tills den är färdigbehandlad.
Genomströmning Antalet begäranden som servern klarar av att behandla per sekund.
Uppskattade RTT (Round-Trip Time) värdet Det uppskattade värdet på tiden det kommer ta att skicka ett TCP-segment och få ett svar på det.
Centralprocessoranvändning Hur mycket av centralprocessorns kapacitet, uttryckt i procent,
som för närvarande används.
Minnesanvändning Hur mycket av datorns minne, uttrycket i Mb, som för närvarande används.
Antalet öppna begäranden i backlog kön Antalet öppna begäranden i lyssningssockelns backlog kö som väntar på att bli accepterade av någon av Apaches barnprocesser.
Loggnings- och regulatorprocessen
Jag skapade en kopia av förälderprocessen som jag kallade för logger, vars uppgift var att skriva
värdena av mätvariablerna till separata filer för ett givet tidsintervall. Stöd för automatisk testning
byggdes in i processen, vilket innebar att jag kunde sätta igång en grupp med olika tester och efteråt
studera serverns beteende för de olika fallen.
Grundstrukturen för regulatorn skapades på samma sätt som loggninsprocessen, som en kopia
av föräldern, se Figur 5. Den här processen körde en regleringsalgoritm för ett givet tidsintervall
och hade tillgång till alla parametrar som nämnts tidigare. Mitt huvudmål var inte att undersöka
olika reglerstrategier för Apache HTTP-servern, utan att skapa en bas för att göra det möjligt att
genomföra sådana undersökningar. Därför skapade jag en enkel regleralgoritm mest för att visa att
allting fungerade. Algoritmen utformades precis som Apaches egna reglering, dvs den reglerade
antalet sysslolösa barnprocesser mellan en övre och en undre gräns. En testkörning av hur väl
regulatorn fungerade finns i Figur 6.
Resultat
De förändringar jag gjorde av Apache HTTP-servern innebär att relevant mätdata om serverns
prestanda finns tillgänglig under körningens gång samt att möjligheten finns att påverka serverns
beteende genom att uppdatera viktiga konfigurationsparametrar i realtid. Alltså är det nu möjligt
att använda reglertekniska metoder för att reglera Apache serverns prestanda.
5
Scoreboard
process
Förälderprocess
logger
status
controller
...
ställ i kö
Sysslolös
process
Apache
HTTP-servern
delat
minne
Arbetande
process
Arbetande
process
Barnprocessernas
huvudloop
Sysslolös
process
Sysslolös
process
Lyssnare
Arbetande
process
behandla
begäran
Figur 5: En förenklad modell över servern då processerna logger och controller lagts till.
60
Antalet sysslolösa barnprocesser
50
40
30
20
10
0
0
100
200
300
Tid i sekunder
400
500
600
Figur 6: Resultatet av en testkörning med regulatorn vars uppgift var att hålla antalet sysslolösa
barnprocesser mellan värdena 32-64.
6