Tehtäväkriittinen ohjelmisto on kategoria, jota ei määritä monimutkaisuus vaan seuraukset. Kun yrityssovellus epäonnistuu, käyttäjät kohtaavat virheilmoituksen ja odottavat korjausta. Kun tehtäväkriittinen ohjelmisto epäonnistuu — taistelukentän komentojärjestelmä, lennonohjauskäyttöliittymä, lääketieteellinen laiteohjain — seuraukset voivat sisältää tilannekuvan menetyksen, vanhentuneeseen dataan perustuvat väärät päätökset tai välittömän fyysisen vahingon. Arkkitehtuuri, joka estää nämä viat, eroaa perustavanlaatuisesti siitä, mikä riittää tavanomaisessa ohjelmistossa.
Tässä artikkelissa tarkastellaan arkkitehtuurimalleja ja insinöörityön lähestymistapoja, joita käytetään puolustuksessa ja muissa korkean panoksen toimialoilla saavuttamaan luotettavuus, saatavuus ja vikasietoisuus, joita tehtäväkriittiset järjestelmät vaativat. Näiden mallien ymmärtäminen on olennaista sekä järjestelmiä rakentaville kehittäjille että ohjelmapäälliköille, jotka arvioivat, sopiiko ehdotettu arkkitehtuuri tehtäväprofiiliin.
Mikä erottaa tehtäväkriittisen ohjelmiston yrityssovelluksista
Ero ei ole ensisijaisesti ominaisuuksien monimutkaisuudessa tai tietomäärässä. Tehtäväkriittinen ohjelmisto eroaa yrityssovelluksista kolmen akselin suhteen, jotka muovaavat suoraan arkkitehtuuripäätöksiä.
Vikaantumisen seuraukset. Yrityssovellukset epäonnistuvat tyypillisesti korjattavilla tavoilla: käyttäjä kohtaa haittaa, transaktio peruutetaan, SLA rikotaan. Tehtäväkriittinen ohjelmisto voi epäonnistua tavoilla, joista ei voi palautua — sensorfuusiojärjestelmä, joka menettää seurannan kriittisessä vaiheessa, ei voi rekonstruoida menetettyä dataa. Tämä seurauksien asymmetria tarkoittaa, että vikojen estäminen on huomattavasti enemmän insinöörityöinvestoinnin arvoinen kuin niistä toipuminen.
Käyttöympäristö. Yrityssovellukset toimivat tyypillisesti hallituissa, redundanteissa datakeskusympäristöissä, joissa on hallittu laitteisto, luotettava virransyöttö ja laajakaistainen yhteys. Puolustusohjelmistot toimivat usein heikentyneissä ympäristöissä: ajoneuvoasennetut järjestelmät karkealla maastolla, etulinjaan sijoitettu laitteisto äärimmäisissä lämpötiloissa, satelliittiviestintä korkealla viiveellä ja rajallisella kaistanleveydellä. Arkkitehtuurin on otettava huomioon ympäristöolosuhteet, joita yrityssovellukset eivät koskaan kohtaa.
Reaaliaikavaatimukset. Monilla tehtäväkriittisillä järjestelmillä on kovat reaaliaikavaatimukset: sensoridataa on käsiteltävä määritetyssä aikaikkunassa, päätöksiä on tuotettava ennen määräaikaa ja ohjauksen ulostulot on sovellettava määritellyn viivebudjetin sisällä. Yrityssovelluksilla on tyypillisesti korkeintaan pehmeät reaaliaikavaatimukset — suorituskyky heikkenee sulavasti kuorman alla. Reaaliaikavaatimuksia omaavalla tehtäväkriittisellä ohjelmistolla on täytettävä määräajat deterministisesti, ei tilastollisesti.
Ydinaarkkitehtuurimallit
Useita malleja esiintyy johdonmukaisesti tehtäväkriittisissä järjestelmäarkkitehtuureissa. Ne eivät ole toisiaan poissulkevia; kypsät järjestelmät yhdistävät tyypillisesti useita malleja vaaditun luotettavuusprofiilin saavuttamiseksi.
Aktiivi-aktiivi-redundanssi. Aktiivi-aktiivi-konfiguraatiossa useita palvelun instansseja ajetaan samanaikaisesti, kaikki käsittelevät pyyntöjä ja ylläpitävät synkronoitua tilaa. Jos yksi instanssi epäonnistuu, muut jatkavat ilman keskeytystä — ei ole vikasietoisuusjaksoa, jonka aikana pyyntöjä pudotetaan tai viivästetään. Aktiivi-aktiivi on korkein saatavuuskonfiguraatio, mutta se kantaa korkeimman monimutkaisuuskustannuksen: tilan synkronointi instanssien välillä on teknisesti haastavaa, erityisesti verkon partitiotilanteissa, ja järjestelmän on käsiteltävä tilanne, jossa instanssit ovat eri mieltä tilasta. Puolustuksen komento- ja ohjausjärjestelmissä, joissa jatkuva saatavuus on ensisijaista, aktiivi-aktiivi on tyypillisesti tavoitearkkitehtuuri tästä monimutkaisuudesta huolimatta.
Aktiivi-passiivi-redundanssi. Aktiivi-passiivi-konfiguraatiossa primääri-instanssi käsittelee kaiken liikenteen, kun taas toissijainen instanssi pidetään lämpimänä vastaanottaen tilapäivityksiä mutta ei käsitellen pyyntöjä. Kun primääri epäonnistuu, toissijainen ottaa vastuun — prosessi, joka vie mitattavan ajan (tyypillisesti sekunteista kymmeniin sekunteihin) ja voi sisältää lyhyen palvelukeskeytyksen. Aktiivi-passiivi on yksinkertaisempi toteuttaa kuin aktiivi-aktiivi, koska passiivinen instanssi ei koskaan käsittele pyyntöjä samanaikaisesti, mikä eliminoi synkronointiristiriidat. Järjestelmille, joissa lyhyt vikasietoisuusaika on hyväksyttävä ja jatkuva tilan yhtenäisyys on vaikea ylläpitää, aktiivi-passiivi on usein pragmaattinen valinta.
Katkaisijamalli. Sähkötekniikasta lainattu katkaisijamalli käsittelee tietyn vikamoodin: kasautuvat viat, jotka johtuvat siitä, että komponentti yrittää kommunikoida saavuttamattoman riippuvuuden kanssa, estäytyy tai aikakatkeaa ja heikentää siten omaa saatavuuttaan. Katkaisija seuraa kutsuja riippuvuuteen; kun viat ylittävät kynnyksen, se "avautuu" ja palauttaa välittömästi virheen tai välimuistissa olevan varavasteen sen sijaan, että yrittäisi kutsua. Tämä estää kutsukomponenttia muodostumasta pullonkaulaksi riippuvuuskatkoksen aikana. Puolustusjärjestelmissä, joissa komponentit voivat kommunikoida useiden ulkoisten tietolähteiden (sensoriverkot, tietokannat, ulkoiset palvelut) kanssa, katkaisijat ovat olennainen mekanismi vikojen rajoittamiseen.
Lohkoseinämalli. Nimetty laivojen vesitiiviitten osastojen mukaan, jotka estävät tulvimisen leviämistä aluksen läpi, lohkoseinämalli eristää komponentit toisistaan niin, että yhden epäonnistuminen ei kuluta muiden tarvitsemia resursseja. Käytännössä tämä tarkoittaa tyypillisesti erillisten säiepoolien tai yhteyspoolien allokointia eri alijärjestelmille, jotta korkeasta viiveestä tai kuormasta kärsivä komponentti ei voi kuluttaa kaikkia käytettävissä olevia resursseja ja näännyttää muita komponentteja. C2-järjestelmässä, jossa on useita riippumattomia tehtäväfunktioita, lohkoseinät estävät epäonnistumisen yhdessä tehtäväfunktiossa heikentämästä muita.
Arkkitehtuuriperiaate: Vikasietoisuuden tavoite ei ole estää kaikkia vikoja — se on mahdotonta todellisissa käyttöympäristöissä. Tavoite on varmistaa, että viat pysyvät paikallisina eikä leviä, heikkeneminen on sulavaa eikä katastrofaalista, ja palautuminen on automaattista tai ohjattua eikä vaadi manuaalista toimenpidettä stressin alla.
Sulave heikkeneminen verkkokatkoksen aikana
Puolustusjärjestelmät toimivat usein ympäristöissä, joissa yhteys keskusjärjestelmiin on ajoittaista tai olematonta. Vain yhteydelliseen toimintaan suunniteltu järjestelmä epäonnistuu täysin yhteyden katketessa. Tehtäväkriittiset järjestelmät on suunniteltava eksplisiittisillä heikentyneen tilan toimintakyvyillä — järjestelmällä on oltava määritelty, testattu käyttäytyminen jokaisessa mahdollisessa yhteydentilassa.
Sulave heikkenemissuunnittelu alkaa kykyinventaariosta: mitkä kyvyt vaativat yhteyttä, mitkä voivat toimia välimuistissa olevalla datalla hyväksyttävällä vanhenemisella ja mitkä voivat toimia täysin offline-tilassa. Tämä inventaario ohjaa sitten arkkitehtuuripäätöksiä siitä, mitä dataa on replikoitava paikallisesti, mitä operaatioita voidaan jonottaa synkronointia varten yhteyden palautuessa ja mitkä operaatiot vaativat yhteyttä ja tulisi poistaa eksplisiittisesti käytöstä eikä epäonnistua hiljaisesti.
Tilan synkronointi yhteyden muodostamisen jälkeen on yksi vaikeimmista ongelmista yhteydetöntä toimintaa koskien. Kun laite muodostaa yhteyden pitkän offline-jakson jälkeen, sen on soviteltava paikallinen tilansa palvelimen tilan kanssa — käsitellen ristiriitoja, toistellen jonotetuet operaatiot oikeassa järjestyksessä ja hylkäämällä vanhentuneet tiedot, jotka on korvattu offline-aikana tehdyillä päivityksillä. Tämä sovittelulogiikka on lähes aina monimutkaisempi kuin ensisijainen sovelluslogiikka, ja sitä testataan lähes aina liian vähän, koska testaus vaatii tarkoituksellista verkon partitioiden aiheuttamista.
Konfliktinratkaisupolitiikat on määriteltävä eksplisiittisesti suunnitteluhetkellä, eikä niitä saa käsitellä ad hoc -logiikalla toteutushetkellä. Yleisiä politiikkoja ovat viimeisin kirjoitus voittaa (viimeksi aikaleimalla merkitty päivitys voittaa), palvelin on auktoritatiivinen (palvelimen tila on aina kanoninen) ja yhdistäminen (molemmat tilat säilytetään ja ihmisoperaattori ratkaisee ristiriidan). Sopiva politiikka riippuu tietotyypistä ja operatiivisesta kontekstista.
Testaus: kaaosinsuunnittelu, vikasyöttö ja stressitestaus
Kestävyysarkkitehtuuri, jota ei ole validoitu vikaolosuhteissa, on hypoteesi, ei insinöörityön tosiasia. Tehtäväkriittiset järjestelmät vaativat tiukkaa vikamoodien testausta — ei vain toiminnallista testausta normaaliolosuhteissa.
Vikasyöttötestaus tuo tarkoituksellisesti vikoja käynnissä olevaan järjestelmään varmistaakseen, että vianhallinnan käyttäytyminen vastaa spesifikaatiota. Tähän sisältyy verkon viiveiden ja pakettihäviöiden syöttäminen, prosessien kaataminen, vioittuneen datan lisääminen ja laitevikojenpien simulointi. Vikasyöttöä voidaan suorittaa infrastruktuuritasolla (käyttämällä työkaluja, jotka kaappaavat verkkokutsuja tai lopettavat prosesseja) tai sovellustasolla (käyttämällä virhesyöttökoukut koodissa). Puolustusjärjestelmille vikasyöttötestauksen tulisi kattaa järjestelmällisesti jokainen järjestelmän vikamoodipuuanalyysissä tunnistettu vikamood.
Kaaosinsuunnittelu laajentaa vikasyöttöä tuotantomaisiin ympäristöihin tuomalla tarkoituksellisesti satunnaisia vikoja paljastaakseen heikkouksia, joita deterministinen vikasyöttö saattaa jäädä huomaamatta. Netflixin Chaos Monkey — joka satunnaisesti lopettaa tuotantoinstansseja — on tunnetuin esimerkki. Puolustuskontekstissa kaaosinsuunnittelu on tehtävä edustavissa testiympäristöissä eikä tuotannossa, ja vikaskenaariot on rajattava todellisten operatiivisten vaikutusten välttämiseksi. Käytäntö on siitä huolimatta arvokasta: järjestelmät, joille on tehty hallittu kaaostestaus, ovat johdonmukaisesti osoittautuneet kestävämmiksi todellisissa katkostilanteissa kuin järjestelmät, joita on testattu vain normaalissa toiminnassa.
Stressitestaus arvioi järjestelmän käyttäytymistä resurssirajojen lähestymistä tai ylittämistä koskien. Tehtäväkriittisillä järjestelmillä on oltava määritelty käyttäytyminen kuormaolosuhteissa, jotka ylittävät normaalit käyttöparametrit — ei määrittelemätöntä käyttäytymistä tai hiljaista heikkenemistä, vaan eksplisiittinen rajoittaminen, kuorman pudottaminen tai sulave epäonnistuminen asianmukaisella hälytyksellä. Stressitestien tulisi ajaa järjestelmä rajoilleen ja varmistaa, että suunniteltu heikkenemiskäyttäytyminen tapahtuu odotetulla tavalla, ja että palautuminen on automaattista kuorman palatessa normaalille tasolle.
Yhdessä nämä testauslähestymistavat täyttävät tehtävän todentamista pidemmältä: ne rakentavat operatiivista luottamusta. Tehtäväkriittisten järjestelmien operaattoreiden on tiedettävä, mitä odottaa vikojen sattuessa. Järjestelmät, joille on tehty tiukka vikatestaus, ovat järjestelmiä, joiden vikakäyttäytyminen on tunnettu ja dokumentoitu — operaattorit voivat reagoida harjoitelluilla menettelyillä sen sijaan, että improvisoisivat vastauksena odottamattomaan käyttäytymiseen.