Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Tämä on jatkoa pitkälle tarinallemme hankalasta tiestämme luoda tehokas, kuormitettu järjestelmä, joka varmistaa Exchangen toiminnan. Ensimmäinen osa löytyy täältä: habr.com/en/post/444300

Mystinen virhe

Lukuisten testien jälkeen päivitetty kaupankäynti- ja selvitysjärjestelmä otettiin käyttöön ja törmäsimme bugiin, josta saatoimme kirjoittaa salapoliisi-mystisen tarinan.

Pian pääpalvelimella käynnistyksen jälkeen yksi tapahtumista käsiteltiin virheellä. Varapalvelimella kaikki oli kuitenkin hyvin. Kävi ilmi, että yksinkertainen matemaattinen operaatio eksponentin laskemiseksi pääpalvelimella antoi negatiivisen tuloksen todellisesta argumentista! Jatkoimme tutkimusta ja SSE2-rekisteristä löysimme eron yhdessä bitissä, joka vastaa pyöristyksestä liukulukujen kanssa työskennellessä.

Kirjoitimme yksinkertaisen testiapuohjelman eksponentin laskemiseksi pyöristysbitillä. Kävi ilmi, että käyttämässämme RedHat Linux -versiossa matemaattisen funktion kanssa työskentelyssä oli virhe, kun huonoonninen bitti lisättiin. Ilmoitimme tästä RedHatille, jonkin ajan kuluttua saimme heiltä korjaustiedoston ja julkaisimme sen. Virhe ei enää ilmennyt, mutta oli epäselvää, mistä tämä bitti tuli? Toiminto oli vastuussa siitä fesetround C-kielestä Analysoimme koodimme huolellisesti etsiessämme oletettua virhettä: tarkistimme kaikki mahdolliset tilanteet; katsoi kaikkia pyöristystä käyttäviä toimintoja; yritti toistaa epäonnistuneen istunnon; käytti erilaisia ​​kääntäjiä eri vaihtoehdoilla; Käytettiin staattista ja dynaamista analyysiä.

Virheen syytä ei löytynyt.

Sitten he alkoivat tarkistaa laitteistoa: suorittivat prosessorien kuormitustestaukset; tarkistanut RAM-muistin; Suoritimme jopa testejä erittäin epätodennäköiselle skenaariolle, jossa monibittinen virhe tapahtuisi yhdessä solussa. turhaan.

Lopulta päädyimme korkeaenergisen fysiikan maailmasta tulevaan teoriaan: suurienerginen hiukkanen lensi palvelinkeskukseemme, lävisti kotelon seinämän, osui prosessoriin ja sai liipaisimen lukkiutumaan juuri siihen. Tätä absurdia teoriaa kutsuttiin "neutriinoksi". Jos olet kaukana hiukkasfysiikasta: neutriinot eivät melkein ole vuorovaikutuksessa ulkomaailman kanssa eivätkä todellakaan pysty vaikuttamaan prosessorin toimintaan.

Koska vian syytä ei voitu selvittää, "loukkaava" palvelin poistettiin toiminnasta varmuuden vuoksi.

Jonkin ajan kuluttua aloimme parantaa kuumaa varmuuskopiointijärjestelmää: otimme käyttöön niin sanottuja "lämpimiä reservejä" (lämpimiä) - asynkronisia kopioita. He saivat virran tapahtumia, jotka saattoivat sijaita eri palvelinkeskuksissa, mutta lämpimät eivät olleet aktiivisesti vuorovaikutuksessa muiden palvelimien kanssa.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Miksi tämä tehtiin? Jos varmuuskopiopalvelin epäonnistuu, pääpalvelimeen sidottu lämmin varmuuskopio tulee uudeksi varmuuskopioksi. Eli vian jälkeen järjestelmä ei jää yhteen pääpalvelimeen kaupankäyntiistunnon loppuun asti.

Ja kun järjestelmän uusi versio testattiin ja otettiin käyttöön, pyöristysbittivirhe tapahtui uudelleen. Lisäksi lämpimien palvelimien määrän lisääntyessä virhe alkoi ilmaantua useammin. Samaan aikaan myyjällä ei ollut mitään näytettävää, koska konkreettisia todisteita ei ollut.

Seuraavassa tilanneanalyysissä nousi esiin teoria, että ongelma voisi liittyä käyttöjärjestelmään. Kirjoitimme yksinkertaisen ohjelman, joka kutsuu funktiota loputtomassa silmukassa fesetround, muistaa nykyisen tilan ja tarkistaa sen lepotilassa, ja tämä tehdään monissa kilpailevissa säikeissä. Kun olet valinnut parametrit lepotilalle ja säikeiden lukumäärälle, aloimme jatkuvasti toistaa bittivirhettä noin 5 minuutin apuohjelman ajon jälkeen. Red Hat -tuki ei kuitenkaan pystynyt toistamaan sitä. Muiden palvelimiemme testaus on osoittanut, että vain ne, joissa on tietyt prosessorit, ovat alttiita virheelle. Samaan aikaan vaihtaminen uuteen ytimeen ratkaisi ongelman. Lopulta vaihdoimme vain käyttöjärjestelmän, ja virheen todellinen syy jäi epäselväksi.

Ja yhtäkkiä viime vuonna julkaistiin artikkeli Habresta "Kuinka löysin vian Intel Skylake -suorittimissa" Siinä kuvattu tilanne oli hyvin samanlainen kuin meillä, mutta kirjoittaja vei tutkimusta pidemmälle ja esitti teorian, että virhe oli mikrokoodissa. Ja kun Linux-ytimet päivitetään, valmistajat päivittävät myös mikrokoodin.

Järjestelmän jatkokehitys

Vaikka pääsimme eroon virheestä, tämä tarina pakotti meidät harkitsemaan järjestelmäarkkitehtuuria uudelleen. Loppujen lopuksi emme olleet suojassa tällaisten vikojen toistumiselta.

Seuraavat periaatteet muodostivat perustan varausjärjestelmän seuraaville parannuksille:

  • Et voi luottaa kehenkään. Palvelimet eivät ehkä toimi kunnolla.
  • Enemmistön varaus.
  • Konsensuksen varmistaminen. Loogisena lisäyksenä enemmistön varaukseen.
  • Kaksinkertaiset epäonnistumiset ovat mahdollisia.
  • Elinvoimaisuus. Uusi kuuma valmiustila ei saa olla huonompi kuin edellinen. Kaupan pitäisi jatkua keskeytyksettä viimeiseen palvelimeen asti.
  • Pientä latenssin nousua. Kaikki seisokit aiheuttavat suuria taloudellisia tappioita.
  • Minimaalinen verkkovuorovaikutus, jotta latenssi pysyy mahdollisimman alhaisena.
  • Uuden pääpalvelimen valinta sekunneissa.

Mikään markkinoilla olevista ratkaisuista ei sopinut meille, ja Raft-protokolla oli vielä lapsenkengissään, joten loimme oman ratkaisumme.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Verkostoituminen

Varausjärjestelmän lisäksi aloitimme verkkovuorovaikutuksen modernisoinnin. I/O-alijärjestelmä koostui monista prosesseista, joilla oli pahin vaikutus jitteriin ja latenssiin. Satojen TCP-yhteyksiä käsittelevien prosessien vuoksi jouduimme jatkuvasti vaihtamaan niiden välillä, ja mikrosekunnin mittakaavassa tämä on melko aikaa vievä toimenpide. Mutta pahinta on, että kun prosessi vastaanotti paketin käsittelyä varten, se lähetti sen yhteen SystemV-jonoon ja sitten odotti tapahtumaa toisesta SystemV-jonosta. Kuitenkin, kun solmuja on suuri määrä, uuden TCP-paketin saapuminen yhdessä prosessissa ja tiedon vastaanottaminen jonossa toisessa edustavat kahta kilpailevaa tapahtumaa käyttöjärjestelmälle. Tässä tapauksessa, jos fyysisiä prosessoreita ei ole saatavilla molemmille tehtäville, toinen käsitellään ja toinen sijoitetaan odotusjonoon. On mahdotonta ennustaa seurauksia.

Tällaisissa tilanteissa voidaan käyttää dynaamista prosessien prioriteetin ohjausta, mutta tämä edellyttää resurssiintensiivisten järjestelmäkutsujen käyttöä. Tämän seurauksena vaihdoimme yhteen säiettä käyttämällä klassista epollia, mikä lisäsi huomattavasti nopeutta ja lyhensi tapahtuman käsittelyaikaa. Pääsimme myös eroon erillisistä verkkoviestintäprosesseista ja SystemV:n kautta tapahtuvasta kommunikaatiosta, vähensimme merkittävästi järjestelmäpuheluiden määrää ja ryhdyimme kontrolloimaan toiminnan prioriteetteja. Pelkästään I/O-alijärjestelmässä säästyi noin 8-17 mikrosekuntia skenaariosta riippuen. Tätä yksisäikeistä järjestelmää on käytetty sen jälkeen muuttumattomana, yksi epoll-säie marginaalilla riittää palvelemaan kaikkia yhteyksiä.

Tapahtuman käsittely

Järjestelmämme kasvava kuormitus vaati lähes kaikkien sen komponenttien päivittämistä. Mutta valitettavasti prosessorien kellotaajuuksien kasvun pysähtyminen viime vuosina ei ole enää mahdollistanut prosessien skaalaamista. Siksi päätimme jakaa Engine-prosessin kolmeen tasoon, joista vilkkain on riskien tarkistusjärjestelmä, joka arvioi tilien varojen saatavuuden ja luo tapahtumat itse. Mutta rahaa voi olla eri valuutoissa, ja oli tarpeen selvittää, millä perusteella pyyntöjen käsittely tulisi jakaa.

Looginen ratkaisu on jakaa se valuutan mukaan: yksi palvelin käy kauppaa dollareilla, toinen punteilla ja kolmas euroilla. Mutta jos tällaisella järjestelmällä lähetetään kaksi tapahtumaa eri valuuttojen ostamiseksi, lompakon synkronoinnin ongelma syntyy. Mutta synkronointi on vaikeaa ja kallista. Siksi olisi oikein sirpaloida erikseen lompakoittain ja erikseen soittimien mukaan. Muuten, useimpien länsimaisten pörssien tehtävänä ei ole tarkistaa riskejä yhtä tarkasti kuin meillä, joten useimmiten tämä tehdään offline-tilassa. Meidän piti ottaa käyttöön verkkovahvistus.

Selitetäänpä esimerkillä. Elinkeinonharjoittaja haluaa ostaa 30 dollaria, ja pyyntö siirtyy tapahtuman validointiin: tarkistamme, onko tällä kauppiaalla oikeus tähän kaupankäyntitilaan ja onko hänellä tarvittavat oikeudet. Jos kaikki on kunnossa, pyyntö siirtyy riskien varmistusjärjestelmään, ts. tarkistaakseen varojen riittävyyden kaupan tekemiseen. On huomautus, että vaadittu summa on tällä hetkellä estetty. Pyyntö välitetään sitten kaupankäyntijärjestelmään, joka hyväksyy tai hylkää tapahtuman. Oletetaan, että kauppa hyväksytään - sitten riskinvahvistusjärjestelmä merkitsee, että rahat on vapautettu ja rupla muuttuu dollareiksi.

Yleensä riskintarkistusjärjestelmä sisältää monimutkaisia ​​algoritmeja ja suorittaa suuren määrän erittäin resurssiintensiivisiä laskelmia, eikä vain tarkista "tilin saldoa", kuten ensi silmäyksellä saattaa tuntua.

Kun aloitimme jakaa Engine-prosessin tasoihin, törmäsimme ongelmaan: tuolloin saatavilla oleva koodi käytti aktiivisesti samaa tietojoukkoa validointi- ja varmistusvaiheessa, mikä vaati koko koodikannan uudelleenkirjoittamista. Tämän seurauksena lainasimme tekniikan käskyjen käsittelyyn nykyaikaisista prosessoreista: jokainen niistä on jaettu pieniin vaiheisiin ja useita toimintoja suoritetaan rinnakkain yhdessä syklissä.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Pienen koodin muokkauksen jälkeen loimme rinnakkaisten tapahtumien käsittelyyn putkilinjan, jossa tapahtuma jaettiin putken neljään vaiheeseen: verkkovuorovaikutus, validointi, suoritus ja tuloksen julkaiseminen.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Katsotaanpa esimerkkiä. Meillä on kaksi käsittelyjärjestelmää, sarja- ja rinnakkainen. Ensimmäinen tapahtuma saapuu ja lähetetään tarkistettavaksi molemmissa järjestelmissä. Toinen tapahtuma saapuu välittömästi: rinnakkaisjärjestelmässä se otetaan välittömästi töihin, ja peräkkäisessä järjestelmässä se asetetaan jonoon odottamaan, että ensimmäinen tapahtuma käy läpi nykyisen käsittelyvaiheen. Eli putkikäsittelyn tärkein etu on, että käsittelemme tapahtumajonon nopeammin.

Näin keksimme ASTS+-järjestelmän.

Totta, kaikki ei ole niin sujuvaa myöskään kuljettimilla. Oletetaan, että meillä on tapahtuma, joka vaikuttaa naapuritapahtuman tietoryhmiin; tämä on tyypillinen tilanne pörssille. Tällaista tapahtumaa ei voida suorittaa putkeen, koska se voi vaikuttaa muihin. Tätä tilannetta kutsutaan datavaaraksi, ja tällaiset tapahtumat käsitellään yksinkertaisesti erikseen: kun jonon "nopeat" tapahtumat loppuvat, liukuhihna pysähtyy, järjestelmä käsittelee "hidas" tapahtuman ja käynnistää sitten liukuhihnan uudelleen. Onneksi tällaisten tapahtumien osuus kokonaisvirrasta on hyvin pieni, joten putkisto pysähtyy niin harvoin, ettei se vaikuta kokonaissuorituskykyyn.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Sitten aloimme ratkaista kolmen suoritussäikeen synkronoinnin ongelmaa. Tuloksena oli järjestelmä, joka perustui rengaspuskuriin, jossa oli kiinteäkokoisia soluja. Tässä järjestelmässä kaikki on käsittelynopeuden alaista, tietoja ei kopioida.

  • Kaikki saapuvat verkkopaketit siirtyvät allokointivaiheeseen.
  • Sijoitamme ne taulukkoon ja merkitsemme ne käytettävissä oleviksi vaiheessa #1.
  • Toinen tapahtuma on saapunut, se on jälleen saatavilla vaiheessa nro 1.
  • Ensimmäinen käsittelysäie näkee käytettävissä olevat tapahtumat, käsittelee ne ja siirtää ne toisen käsittelysäikeen seuraavaan vaiheeseen.
  • Sitten se käsittelee ensimmäisen tapahtuman ja merkitsee vastaavan solun deleted – Se on nyt saatavilla uuteen käyttöön.

Koko jono käsitellään tällä tavalla.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Kunkin vaiheen käsittely kestää yksiköitä tai kymmeniä mikrosekunteja. Ja jos käytämme tavallisia käyttöjärjestelmän synkronointimalleja, menetämme enemmän aikaa itse synkronointiin. Siksi aloimme käyttää spinlockia. Tämä on kuitenkin erittäin huono muoto reaaliaikaisessa järjestelmässä, eikä RedHat ehdottomasti suosittele tämän tekemistä, joten käytämme spinlockia 100 ms:n ajaksi ja siirrymme sitten semaforitilaan umpikujan mahdollisuuden poistamiseksi.

Tuloksena saavutimme noin 8 miljoonan tapahtuman suorituskyvyn sekunnissa. Ja kirjaimellisesti kaksi kuukautta myöhemmin статье LMAX Disruptorista näimme kuvauksen piiristä, jolla on samat toiminnot.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Nyt yhdessä vaiheessa voi olla useita toteutussäikeitä. Kaikki tapahtumat käsiteltiin yksitellen saapumisjärjestyksessä. Tämän seurauksena huippusuorituskyky kasvoi 18 tuhannesta 50 tuhanteen tapahtumaan sekunnissa.

Valuuttariskien hallintajärjestelmä

Täydellisyydellä ei ole rajaa, ja pian aloitimme modernisoinnin uudelleen: ASTS+:n puitteissa aloimme siirtää riskienhallinta- ja selvitystoimintajärjestelmiä itsenäisiksi komponenteiksi. Kehitimme joustavan modernin arkkitehtuurin ja uuden hierarkkisen riskimallin ja yritimme hyödyntää luokkaa aina kun mahdollista fixed_point sen sijasta double.

Mutta heti syntyi ongelma: kuinka synkronoida kaikki vuosia toiminut liiketoimintalogiikka ja siirtää se uuteen järjestelmään? Tämän seurauksena uuden järjestelmän prototyypin ensimmäinen versio jouduttiin luopumaan. Toinen, parhaillaan tuotannossa toimiva versio perustuu samaan koodiin, joka toimii sekä kaupankäynti- että riskiosassa. Kehityksen aikana vaikein asia oli git-fuusio kahden version välillä. Kollegamme Evgeniy Mazurenok suoritti tämän leikkauksen joka viikko ja joka kerta hän kirosi erittäin pitkän ajan.

Uutta järjestelmää valittaessa jouduimme välittömästi ratkaisemaan vuorovaikutusongelman. Dataväylää valittaessa oli tarpeen varmistaa vakaa jitter ja minimaalinen latenssi. InfiniBand RDMA -verkko sopi tähän parhaiten: keskimääräinen käsittelyaika on 4 kertaa lyhyempi kuin 10 G Ethernet-verkoissa. Mutta mikä todella kiehtoi meitä, oli ero prosenttipisteissä - 99 ja 99,9.

Tietysti InfiniBandilla on haasteensa. Ensinnäkin erilainen API - ibverbit sockettien sijaan. Toiseksi avoimen lähdekoodin viestintäratkaisuja ei ole juurikaan laajalti saatavilla. Yritimme tehdä oman prototyyppimme, mutta se osoittautui erittäin vaikeaksi, joten valitsimme kaupallisen ratkaisun - Confinity Low Latency Messaging (aiemmin IBM MQ LLM).

Sitten syntyi tehtävä jakaa riskijärjestelmä oikein. Jos yksinkertaisesti poistat riskimoottorin etkä luo välisolmua, kahdesta lähteestä tulevat tapahtumat voidaan sekoittaa.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Ns. Ultra Low Latency -ratkaisuissa on uudelleenjärjestelytila: kahdesta lähteestä tulevat tapahtumat voidaan järjestää haluttuun järjestykseen vastaanotettaessa, mikä toteutetaan erillisellä kanavalla tilauksen tietojen vaihtoon. Mutta emme vielä käytä tätä tilaa: se monimutkaistaa koko prosessia, ja useissa ratkaisuissa sitä ei tueta ollenkaan. Lisäksi jokaiselle tapahtumalle olisi osoitettava vastaavat aikaleimat, ja järjestelmässämme tätä mekanismia on erittäin vaikea toteuttaa oikein. Siksi käytimme klassista menetelmää viestivälittäjän kanssa, eli lähettäjän kanssa, joka jakaa viestejä Risk Enginen välillä.

Toinen ongelma liittyi asiakaspääsyyn: jos riskiyhdyskäytäviä on useita, asiakkaan täytyy muodostaa yhteys jokaiseen, mikä edellyttää muutoksia asiakastasoon. Halusimme päästä eroon tästä tässä vaiheessa, joten nykyinen Risk Gateway -suunnittelu käsittelee koko tietovirran. Tämä rajoittaa suuresti suurinta suorituskykyä, mutta yksinkertaistaa huomattavasti järjestelmän integrointia.

jäljentäminen

Järjestelmässämme ei pitäisi olla yhtä vikakohtaa, eli kaikkien komponenttien on oltava monistettuja, mukaan lukien viestinvälittäjä. Ratkaisimme tämän ongelman CLLM-järjestelmällä: se sisältää RCMS-klusterin, jossa kaksi dispatcheria voi työskennellä master-slave-tilassa, ja kun toinen epäonnistuu, järjestelmä vaihtaa automaattisesti toiseen.

Työskentely varmuuskopiointikeskuksen kanssa

InfiniBand on optimoitu toimimaan paikallisverkona, eli telineeseen asennettavien laitteiden kytkemiseen, eikä InfiniBand-verkkoa voi muodostaa kahden maantieteellisesti hajautetun datakeskuksen välille. Siksi otimme käyttöön sillan/välittäjän, joka kytkeytyy viestivarastoon tavallisten Ethernet-verkkojen kautta ja välittää kaikki tapahtumat toiseen IB-verkkoon. Kun meidän on siirryttävä palvelinkeskuksesta, voimme valita, minkä palvelinkeskuksen kanssa työskentelemme nyt.

Tulokset

Kaikkea yllä olevaa ei tehty kerralla, vaan uuden arkkitehtuurin kehittämiseen tarvittiin useita iteraatioita. Teimme prototyypin kuukaudessa, mutta kesti yli kaksi vuotta saada se käyttökuntoon. Yritimme saavuttaa parhaan kompromissin transaktioiden käsittelyajan pidentämisen ja järjestelmän luotettavuuden lisäämisen välillä.

Koska järjestelmää päivitettiin voimakkaasti, toteutimme tietojen palautuksen kahdesta riippumattomasta lähteestä. Jos viestivarasto ei jostain syystä toimi oikein, voit ottaa tapahtumalokin toisesta lähteestä - Risk Enginestä. Tätä periaatetta noudatetaan koko järjestelmässä.

Pystyimme muun muassa säilyttämään asiakasrajapinnan niin, ettei välittäjät tai kukaan muu tarvitsisi merkittävää uudistusta uuteen arkkitehtuuriin. Joitakin rajapintoja jouduttiin muuttamaan, mutta toimintamalliin ei tarvinnut tehdä merkittäviä muutoksia.

Kutsuimme alustamme nykyistä versiota Rebusiksi - lyhenteenä kahdesta arkkitehtuurin huomattavimmasta innovaatiosta, Risk Engine ja BUS.

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Aluksi halusimme allokoida vain selvitysosan, mutta tuloksena oli valtava hajautettu järjestelmä. Asiakkaat voivat nyt olla vuorovaikutuksessa joko Trade Gatewayn, Clearing Gatewayn tai molempien kanssa.

Mitä lopulta saavutimme:

Moskovan pörssin kaupankäynti- ja selvitysjärjestelmän arkkitehtuurin kehitys. Osa 2

Pienensi latenssitasoa. Pienellä tapahtumamäärällä järjestelmä toimii samalla tavalla kuin edellinen versio, mutta kestää samalla paljon suuremman kuormituksen.

Huippusuorituskyky kasvoi 50 tuhannesta 180 tuhanteen tapahtumaan sekunnissa. Lisäkasvua vaikeuttaa ainoa tilausten täsmäytysvirta.

On olemassa kaksi tapaa parantaa edelleen: rinnastaa vastaavuus ja muuttaa tapaa, jolla se toimii Gatewayn kanssa. Nyt kaikki yhdyskäytävät toimivat replikointimallin mukaisesti, joka tällaisella kuormituksella lakkaa toimimasta normaalisti.

Lopuksi voin antaa neuvoja niille, jotka viimeistelevät yritysjärjestelmiä:

  • Valmistaudu aina pahimpaan. Ongelmat tulevat aina yllättäen.
  • Arkkitehtuuria on yleensä mahdotonta tehdä nopeasti uudelleen. Varsinkin jos sinun on saavutettava suurin luotettavuus useilla indikaattoreilla. Mitä enemmän solmuja, sitä enemmän tukea tarvitaan.
  • Kaikki mukautetut ja patentoidut ratkaisut vaativat lisäresursseja tutkimukseen, tukeen ja ylläpitoon.
  • Älä lykkää järjestelmän luotettavuuteen ja vikojen jälkeiseen palautumiseen liittyvien ongelmien ratkaisemista, vaan ota ne huomioon suunnittelun alkuvaiheessa.

Lähde: will.com

Lisää kommentti