Det svageste led: Hvordan kædede afhængigheder påvirker systemrisiko
Når man vurderer systemrisikoscenarier, er det meget nemt at overse “kædede” afhængigheder. Vi er oplært til at se på risiko på et “node”-niveau og spørge “hvor sandsynligt er det, at denne ene ting fejler.” Men systemrisiko er langt mere kompliceret end det.
I de fleste systemer er der komponenter, der er afhængige af andre komponenter. Det mest almindelige sted, vi kigger på dette, er i designet af storage til servere, men det forekommer i ethvert systemdesign. Et andet godt eksempel er, hvordan webapplikationer har brug for både applikationshosts og databasehosts for at fungere.
Det er nemmest at forklare kædede afhængigheder med et eksempel. Vi vil se på et standard virtualiseringsdesign med SAN-storage for at forstå, hvor grænser for fejldomæner eksisterer, og hvor kædede afhængigheder eksisterer, og hvilken rolle redundans spiller i risikoreduktion på systemniveau.
I et standard SAN (storage area network)-design til virtualisering har du virtualiseringshosts (som vi for enkelheds skyld vil kalde “servere”), SAN-switche (switche dedikeret til storage-netværket) og selve diskarkerne. Hvert af disse tre “lag” er afhængigt af de andre for, at systemet som helhed kan fungere. Hvis vi havde det simplest mulige sæt med én server, én switch og én diskarray, har vi tydeligvis tre enheder, der repræsenterer tre distinkte fejlpunkter. Fejl i en af de tre forårsager, at hele systemet fejler. Ingen enkelt del er nyttig alene. Dette er en kædet afhængighed, og kæden er kun så stærk som sit svageste led.
I vores enkle eksempel repræsenterer hver enhed et fejldomæne. Vi kan reducere risikoen ved at forbedre pålideligheden af hvert domæne. Vi kan tilføje en anden server og implementere en virtualiseringslags high availability- eller fault tolerance-strategi for at reducere risikoen for serverfejl. Dette forbedrer pålideligheden af ét fejldomæne, men efterlader to uberørte og lige så risikofyldte som før. Vi kan derefter adressere switch-laget ved at tilføje en redundant switch og konfigurere en multipathing-strategi til at håndtere tabet af en enkelt switching-sti, hvilket reducerer risikoen på det lag. Nu er to fejldomæner blevet adresseret. Endelig skal vi adressere storage-fejldomænet, hvilket gøres på lignende vis ved at tilføje redundans via en anden diskarray, der er spejlet til den første og i stand til transparent failover i tilfælde af fejl.
Nu hvor vi har styrket vores system, har vi stadig tre fejldomæner i en afhængighedskæde. Det, vi har gjort, er at gøre hvert “led” i kæden – hvert fejldomæne – ekstra modstandsdygtigt i sig selv. Men kæden eksisterer stadig. Det betyder, at systemet som helhed er langt mindre pålideligt end noget enkelt fejldomæne inden for kæden alene er. Vi har gjort noget langt bedre end der, hvor vi startede, men vi har stadig mange fejldomæner. Disse risici lægger sig oven i hinanden.
Det vanskelige ved at bestemme den samlede risiko er, at vi skal vurdere risikoen for hvert element, derefter bestemme den nye risiko efter risikoreduktion (gennem tilføjelse af redundans) og derefter finde den kumulative risiko for hvert af fejldomænerne tilsammen i en kæde for at bestemme den samlede risiko for hele systemet. Det er ekstremt vanskeligt at bestemme risikoen inden for hvert fejldomæne, da risikoreduktionsmåden spiller en betydelig rolle. For eksempel kan en klynge af storage diskarray, der fejler over for langsomt, resultere i en samlet systemfejl, selv når storage-klyngen selv ser ud til at have fungeret korrekt. Selv at definere en klar fejl kan derfor være udfordrende.
Det er ofte fristende at foretage en “top-ned” risikovurdering, hvilket er meget farligt, men meget almindeligt for folk, der ikke er faste risikopraktikere. Tendensen her er at se på risikoen kun ved at betragte det “øverste” fejldomæne – generelt serverne i et sådant tilfælde – og ignorere eventuelle risici, der befinder sig under det punkt, og betragte disse som “under motorhjelmen” snarere end en del af risikovurderingen. Det er nemt at ignorere de mere tekniske, mindre eksponerede og dårligere forstå komponenter som netværk og storage og fokusere på de relativt let forståelige og stærkt markedsførte pålideligheds-aspekter i det øverste lag. Denne “top-visning” betyder, at risici under topniveauet er sløret og generelt ignoreret, hvilket fører til høj risiko uden en god forståelse af hvorfor.
At forstå begrebet kædede afhængigheder forklarer, hvorfor komplekse systemer – selv med komplekse risikoreduktionsstrategier – ofte ender med at være langt mere skrøbelige end enklere systemer. I vores eksempel ovenfor kunne vi gøre flere ting for at “kollapse” kæden, hvilket resulterer i et mere pålideligt system som helhed.
Den mest oplagte komponent, der kan kollapses, er netværksfejldomænet. Hvis vi fjernede switchene helt og forbandt storage direkte til serverne (ikke altid muligt, selvfølgelig), ville vi effektivt eliminere ét helt fejldomæne og fjerne et led fra vores kæde. Nu i stedet for tre kæder, der hver har et vist fejlpotentiale, har vi kun to. Simplere er bedre, alt andet lige.
Vi kunne i teorien også kollapse storage-fejldomænet ved at gå fra ekstern storage til at bruge storage, der er lokalt på selve serverne, og i realiteten tage os fra to fejldomæner ned til et enkelt fejldomæne – det ene tilbageværende domæne bærer naturligvis mere kompleksitet, end det gjorde før kollapset, men den samlede systemkompleksitet er stærkt reduceret. Igen, med alle andre faktorer uændrede.
En anden tilgang at overveje er at gøre enkelt-noder mere pålidelige i sig selv. Det er trendy i dag at se på større systemer og nærme sig risikoreduktion på den måde, ved at tilføje redundante, billige noder for at tilføje pålidelighed til fejldomæner. Men traditionelt set var dette ikke den foretrukne vej til pålidelighed. Det var langt mere almindeligt i fortiden, som det fremgår af den tidligere udbredelse af mainframe og lignende systemer, at bygge høje grader af pålidelighed ind i en enkelt node. Mainframe og high-end storage-systemer gør f.eks. stadig dette i dag. Dette kan faktisk være en ekstremt effektiv tilgang, men den formår ikke at adressere mange scenarier og er generelt ekstremt dyr, ofte forstærket af et behov for at have systemer delvist eller endda fuldstændigt vedligeholdt af leverandøren. Dette har tendens til kun at fungere i særlige nicheomstændigheder og er ikke praktisk i mere generel skala.
Så i ethvert system af denne art har vi tre centrale risikoreduktionsstrategier at overveje: forbedre pålideligheden af en enkelt node, forbedre pålideligheden af et enkelt domæne eller reducere antallet af fejldomæner (led) i afhængighedskæden. At sætte disse sammen, som det er klogt, kan hjælpe os med at opnå det risikoreduktionsniveau, der er passende for vores forretningsscenarie.
Hvor den sande vanskelighed eksisterer – og vil forblive – er i sammenligningen af forskellige risikoreduktionsstrategier. Risikoen for en enkelt node kan generelt estimeres med en vis grad af tillid. En redundansstrategi inden for et enkelt domæne har langt mindre evne til at estimeres – nogle redundansstrategier er meget effektive og skaber ekstremt pålidelige fejldomæner, mens andre faktisk kan skyde bagud og reducere pålideligheden af et domæne! Den kompleksitet, der ofte følger med redundansstrategier, er aldrig uden forbehold, og selvom det typisk vil betale sig, bærer det sjældent den grad af pålideligheds-fordel, der i første omgang forventes. At estimere risikoen for en afhængighedskæde er derfor endnu vanskeligere, da det kræver en klar forståelse af risiciene forbundet med hvert af fejldomænerne individuelt samt en forståelse af den fejlmulighed, der eksisterer ved domænegrænserne (som den tidligere nævnte forsinkelse ved storage-failover).
Lad os udforske problemerne ved at bestemme risiko i to meget almindelige tilgange til det samme scenario, bygget på det, vi har diskuteret ovenfor.
To ekstreme eksempler på den samme situation, vi har diskuteret, er en enkelt server med intern storage, der bruges til at hoste virtuelle maskiner, versus en seks-enheds “kæde” med to servere og en high availability-løsning på serverlaget, to switche med redundans på switch-laget og to diskarrays, der leverer high availability på storage-laget. Hvis vi ændrer en stor faktor her, kan vi generelt give et rimeligt klart estimat af relativ risiko – hvis et af fejldomænerne mangler pålidelig redundans, for eksempel – kan vi ret klart bestemme, at den enkelt server er det mere pålidelige samlede system, undtagen i tilfælde, hvor en ekstrem mængde pålidelighed for enkelt-node tildeles en enkelt node, hvilket generelt er en upraktisk strategi finansielt. Men med hvert fejldomæne, der opretholder redundans, er vi tvunget til at sammenligne de relative risici ved intra-domæne pålidelighed (den redundante kæde) versus inter-domæne pålidelighed (den kollapsede kæde, enkelt server).
Med de to helt forskellige tilgange er der ingen rimelig måde at vurdere de sammenlignende risici ved de to midler til risikoreduktion. Det er generelt accepteret, at seks (eller flere) node-tilgangen med omfattende intra-domæne risikoreduktion er den mest pålidelige af de to tilgange, og dette er næsten sikkert generelt sandt. Men det er ikke altid sandt, og sjældent overpræsterer denne tilgang enkelt-node-strategien med en virkelig betydelig margin, mens den typisk koster fire til ti gange så meget som enkelt-server-strategien. Det er potentielt en meget høj pris for det, der sandsynligvis er en lille gevinst i pålidelighed og en lille potentiel risiko for tab af pålidelighed. Hver ekstra redundansdel tilføjer kompleksitet, som et menneske skal implementere, overvåge og vedligeholde, og med kompleksitet og menneskelig interaktion følger mere og mere risiko. At undgå menneskelige fejl kan ofte være vigtigere end at undgå mekaniske fejl.
Vi skal også overveje omkostningerne ved genopretning. Hvis der opstår fejl, er det generelt trivielt at genoprette efter fejlen i et simpelt system. Et ekstremt komplekst system, der har fejlet, kan kræve en stor indsats for at gendanne til en fungerende tilstand. Komplekse systemer kræver også langt bredere og dybere grader af erfaring og kompetence for at vedligeholde.
Der er ikke noget nemt svar på at bestemme pålideligheden af systemer. Moderne informationsleveringssystemer er simpelthen for store og for komplekse med for mange ubestemmelige faktorer til at kunne evalueres i alle tilfælde. Med en god forståelse af kædede afhængigheder, imidlertid, og en forståelse af risikoreduktionsstrategier kan vi tage praktiske skridt til at bestemme omtrentlige relative risikoniveauer, se, hvor lignende risikoscenarier sammenligner sig i omkostninger, identificere skrøbelighedspunkter, genkende fejldomæner og afhængighedskæder, og sætte pris på, hvordan ændringer i systemdesign vil flytte os klart mod eller væk fra pålidelighed.
