Den svagaste länken: hur kedjade beroenden påverkar systemrisk
När man bedömer riskscenarier för system är det väldigt lätt att förbise “kedjade” beroenden. Vi är tränade att se på risk på “nodnivå” och fråga “hur sannolikt är det att just den här saken fallerar.” Men systemrisk är långt mer komplicerad än så.
I de flesta system finns det komponenter som är beroende av andra komponenter. Den vanligaste platsen där vi ser detta är i utformningen av lagring för servrar, men det förekommer i all systemdesign. Ett annat bra exempel är hur webbapplikationer behöver både applikationsvärdar och databasvärdar för att fungera.
Det är enklast att förklara kedjade beroenden med ett exempel. Vi ska titta på en standardiserad virtualiseringsdesign med SAN-lagring för att förstå var gränserna för feldomäner går, var kedjade beroenden finns och vilken roll redundans spelar i riskreducering på systemnivå.
I en standardiserad SAN-design (storage area network) för virtualisering har du virtualiseringsvärdar (som vi för enkelhetens skull kallar “servrarna”), SAN-switchar (switchar dedikerade för lagringsnätverket) och själva diskmatriserna. Vart och ett av dessa tre “lager” är beroende av de andra för att systemet som helhet ska fungera. Om vi hade den enklast möjliga uppsättningen med en server, en switch och en diskmatris har vi mycket tydligt tre enheter som representerar tre distinkta felpunkter. Om någon av de tre fallerar slutar hela systemet att fungera. Ingen enskild del är användbar på egen hand. Detta är ett kedjat beroende, och kedjan är bara så stark som sin svagaste länk.
I vårt förenklade exempel representerar varje enhet en feldomän. Vi kan reducera risken genom att förbättra tillförlitligheten i varje domän. Vi kan lägga till en andra server och införa en strategi för hög tillgänglighet eller feltolerans i virtualiseringslagret för att minska risken för serverfel. Detta förbättrar tillförlitligheten i en feldomän men lämnar två orörda och precis lika riskfyllda som de var tidigare. Vi kan sedan ta itu med switchlagret genom att lägga till en redundant switch och konfigurera en multipathing-strategi som hanterar förlusten av en enskild switchväg, vilket minskar risken i det lagret. Nu har två feldomäner åtgärdats. Slutligen måste vi ta itu med lagringsfeldomänen, vilket görs på liknande sätt genom att lägga till redundans via en andra diskmatris som speglas mot den första och kan ta över transparent i händelse av ett fel.
Nu när vi har förstärkt vårt system har vi fortfarande tre feldomäner i en beroendekedja. Det vi har gjort är att göra varje “länk” i kedjan, varje feldomän, extra motståndskraftig på egen hand. Men kedjan finns fortfarande kvar. Detta innebär att systemet som helhet är långt mindre tillförlitligt än vad någon enskild feldomän i kedjan är på egen hand. Vi har skapat något som är långt bättre än där vi började, men vi har fortfarande många feldomäner. Dessa risker adderas.
Det som är svårt när man ska fastställa den totala risken är att vi måste bedöma risken för varje del, sedan fastställa den nya risken efter reducering (genom tillägg av redundans) och därefter finna den kumulativa risken för var och en av feldomänerna tillsammans i en kedja för att kunna fastställa den totala risken för hela systemet. Det är ytterst svårt att fastställa risken inom varje feldomän eftersom sättet att reducera risken spelar en betydande roll. Till exempel kan ett kluster av disklagringsmatriser som tar över för långsamt resultera i ett övergripande systemfel, även när själva lagringsklustret förefaller ha fungerat korrekt. Att ens definiera ett tydligt fel kan därför vara en utmaning.
Det är ofta frestande att anlägga ett riskperspektiv “uppifrån”, vilket är mycket farligt men mycket vanligt bland personer som inte regelbundet arbetar med riskbedömning. Tendensen här är att betrakta risken genom att enbart se på den “översta” feldomänen – i ett fall som detta i allmänhet servrarna – och bortse från eventuella risker som ligger under den punkten, betraktande dessa som “under huven” snarare än som en del av riskbedömningen. Det är lätt att ignorera de mer tekniska, mindre exponerade och sämre förstådda komponenterna som nätverk och lagring och i stället fokusera på de relativt lättförståeliga och kraftigt marknadsförda tillförlitlighetsaspekterna i det översta lagret. Detta “uppifrånperspektiv” innebär att riskerna under den översta nivån döljs och i allmänhet ignoreras, vilket leder till hög risk utan en god förståelse för varför.
Att förstå begreppet kedjade beroenden förklarar varför komplexa system, även med komplexa strategier för riskreducering, ofta blir långt skörare än enklare system. I vårt exempel ovan skulle vi kunna göra flera saker för att “kollapsa” kedjan och därmed få ett mer tillförlitligt system som helhet.
Den mest uppenbara komponenten som kan kollapsas är nätverksfeldomänen. Om vi skulle ta bort switcharna helt och ansluta lagringen direkt till servrarna (vilket förstås inte alltid är möjligt) skulle vi i praktiken eliminera en hel feldomän och ta bort en länk ur vår kedja. Nu har vi i stället för tre länkar, som var och en har viss risk att fallera, endast två. Enklare är bättre, allt annat lika.
Vi skulle teoretiskt sett även kunna kollapsa lagringsfeldomänen genom att gå från extern lagring till att använda lagring lokalt i servrarna själva, vilket i princip tar oss från två feldomäner ner till en enda feldomän – den enda kvarvarande domänen bär förstås mer komplexitet än den gjorde före kollapsen, men den övergripande systemkomplexiteten är kraftigt reducerad. Återigen gäller detta med alla övriga faktorer oförändrade.
Ett annat tillvägagångssätt att överväga är att göra enskilda noder mer tillförlitliga på egen hand. Det är trendigt idag att titta på större system och angripa riskreducering på det sättet, genom att lägga till redundanta noder med låg kostnad för att öka tillförlitligheten i feldomäner. Men traditionellt var detta inte den självklara vägen till tillförlitlighet. Det var långt vanligare förr, vilket framgår av den tidigare utbredningen av stordatorer och liknande klassade system, att bygga in höga grader av tillförlitlighet i en enskild nod. Stordatorer och avancerade lagringssystem, till exempel, gör fortfarande detta idag. Detta kan faktiskt vara ett ytterst effektivt tillvägagångssätt men misslyckas med att hantera många scenarier och är i allmänhet ytterst kostsamt, ofta förstärkt av ett behov av att systemen helt eller delvis underhålls av leverantören. Detta tenderar att fungera väl endast under särskilda nischade omständigheter och är inte praktiskt i ett mer allmänt sammanhang.
Så i alla system av detta slag har vi tre centrala strategier för riskreducering att överväga: förbättra tillförlitligheten hos en enskild nod, förbättra tillförlitligheten hos en enskild domän eller minska antalet feldomäner (länkar) i beroendekedjan. Att kombinera dessa på ett klokt sätt kan hjälpa oss att uppnå den nivå av riskreducering som är lämplig för vårt affärsscenario.
Där den verkliga svårigheten finns, och kommer att förbli, är i jämförelsen mellan olika strategier för riskreducering. Risken för en enskild nod kan i allmänhet uppskattas med viss grad av säkerhet. En redundansstrategi inom en enskild domän går långt sämre att uppskatta – vissa redundansstrategier är högst effektiva och skapar ytterst tillförlitliga feldomäner medan andra faktiskt kan slå tillbaka och minska tillförlitligheten hos en domän! Den komplexitet som ofta följer med redundansstrategier är aldrig utan förbehåll, och även om den vanligtvis lönar sig medför den sällan den grad av tillförlitlighetsvinst som man initialt förväntar sig. Att uppskatta risken för en beroendekedja är därför desto svårare eftersom det kräver en tydlig förståelse för de risker som är förknippade med var och en av feldomänerna individuellt samt en förståelse för den felmöjlighet som finns vid domängränserna (såsom det fel vid fördröjd lagringsövertagning som nämndes tidigare).
Låt oss utforska problematiken kring att fastställa risk i två mycket vanliga tillvägagångssätt för samma scenario, med utgångspunkt i det vi har diskuterat ovan.
Två extrema exempel på samma situation som vi har diskuterat är en enskild server med intern lagring som används för att vara värd för virtuella maskiner kontra en sexenhetskedja med två servrar och en lösning för hög tillgänglighet i serverlagret, två switchar med redundans i switchlagret och två diskmatriser som ger hög tillgänglighet i lagringslagret. Om vi ändrar någon större faktor här kan vi i allmänhet ge en ganska tydlig uppskattning av den relativa risken – om till exempel någon av feldomänerna saknar tillförlitlig redundans – kan vi ganska tydligt fastställa att den enskilda servern är det mer tillförlitliga systemet totalt sett, utom i fall där en extrem grad av tillförlitlighet på enskild nod tilldelas en enskild nod, vilket i allmänhet är en finansiellt opraktisk strategi. Men med varje feldomän som upprätthåller redundans tvingas vi jämföra de relativa riskerna för intra-domäntillförlitlighet (den redundanta kedjan) mot inter-domäntillförlitlighet (den kollapsade kedjan, en enskild server).
Med de två helt olika tillvägagångssätten finns det inget rimligt sätt att bedöma de jämförande riskerna hos de två metoderna för riskreducering. Det är allmänt vedertaget att tillvägagångssättet med sex (eller fler) noder med omfattande riskreducering inom domänerna är det mer tillförlitliga av de två, och detta är nästan säkert allmänt sant. Men det är inte alltid sant, och sällan överträffar detta tillvägagångssätt strategin med en enskild nod med någon verkligt betydande marginal, samtidigt som det vanligen kostar fyra till tio gånger så mycket som strategin med en enskild server. Det är potentiellt en mycket hög kostnad för vad som sannolikt är en liten vinst i tillförlitlighet och en liten potentiell risk för en förlust i tillförlitlighet. Varje ytterligare del av redundans tillför komplexitet som en människa måste införa, övervaka och underhålla, och med komplexitet och mänsklig inblandning följer mer och mer risk. Att undvika mänskliga fel kan ofta vara viktigare än att undvika mekaniska fel.
Vi måste också beakta kostnaden för återställning. Om ett fel skulle inträffa är det i allmänhet trivialt att återställa efter ett fel i ett enkelt system. Ett ytterst komplext system som har fallerat kan kräva en stor grad av ansträngning för att återställas till ett fungerande skick. Komplexa system kräver också mycket bredare och djupare grad av erfarenhet och säkerhet för att underhållas.
Det finns inget enkelt svar på hur man fastställer tillförlitligheten hos system. Moderna system för informationsleverans är helt enkelt för stora och för komplexa med för många obestämbara faktorer för att kunna utvärderas i samtliga fall. Med en god förståelse för kedjade beroenden, och en förståelse för strategier för riskreducering, kan vi dock vidta praktiska steg för att grovt fastställa relativa risknivåer, se var likartade riskscenarier står i förhållande till varandra i kostnad, identifiera punkter av skörhet, känna igen feldomäner och beroendekedjor och uppskatta hur förändringar i systemdesignen rör oss tydligt mot eller från tillförlitlighet.
