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