Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

See on jätk pikale loole meie keerulisest teest võimsa ja suure koormusega süsteemi loomisel, mis tagab Börsi toimimise. Esimene osa on siin: habr.com/en/post/444300

Salapärane viga

Pärast arvukaid katsetusi pandi uuenenud kauplemis- ja arveldussüsteem tööle ning puutusime kokku veaga, millest sai kirjutada detektiivi-müstilise loo.

Varsti pärast põhiserveris käivitamist töödeldi ühte tehingutest veaga. Varuserveris oli aga kõik korras. Selgus, et lihtne matemaatiline operatsioon astendaja arvutamiseks põhiserveris andis tegelikust argumendist negatiivse tulemuse! Jätkasime uurimistööd ja SSE2 registris leidsime erinevuse ühes bitis, mis vastutab ujukomaarvudega töötamisel ümardamise eest.

Kirjutasime lihtsa testutiliidi, et arvutada astendaja koos ümardusbittide komplektiga. Selgus, et RedHat Linuxi versioonis, mida kasutasime, esines ebaõnnestunud biti sisestamisel matemaatilise funktsiooniga töötamisel viga. Teatasime sellest RedHatile, mõne aja pärast saime neilt plaastri ja rullisime selle välja. Viga enam ei ilmnenud, kuid jäi arusaamatuks, kust see bitt üldse pärit on? Funktsioon vastutas selle eest fesetround keelest C. Analüüsisime oletatava vea otsimiseks hoolikalt oma koodi: kontrollisime kõiki võimalikke olukordi; vaatas kõiki funktsioone, mis kasutasid ümardamist; püüdis reprodutseerida ebaõnnestunud seanssi; kasutatud erinevaid kompilaatoreid erinevate võimalustega; Kasutati staatilist ja dünaamilist analüüsi.

Vea põhjust ei leitud.

Seejärel hakati riistvara kontrollima: viidi läbi protsessorite koormustestid; kontrollis RAM-i; Tegime isegi teste väga ebatõenäolise mitmebitise vea stsenaariumi jaoks ühes lahtris. Kasutult.

Lõpuks põhinesime suure energiaga füüsika maailmast pärit teoorial: mõni suure energiaga osake lendas meie andmekeskusesse, läbistas korpuse seina, tabas protsessorit ja pani päästiku riivi just sellesse tükki kinni. Seda absurdset teooriat nimetati "neutriinoks". Kui olete osakeste füüsikast kaugel: neutriinod peaaegu ei suhtle välismaailmaga ega suuda kindlasti protsessori tööd mõjutada.

Kuna tõrke põhjust ei õnnestunud leida, eemaldati “rikkuv” server igaks juhuks tööst.

Mõne aja pärast hakkasime kuuma varusüsteemi täiustama: võtsime kasutusele nn soojad reservid (soojad) - asünkroonsed koopiad. Nad said tehingute voogu, mis võisid asuda erinevates andmekeskustes, kuid soojad ei suhelnud aktiivselt teiste serveritega.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Miks seda tehti? Kui varuserver ebaõnnestub, saab peaserveriga soojalt seotud uueks varukoopiaks. See tähendab, et pärast riket ei jää süsteem ühele põhiserverile kuni kauplemisseansi lõpuni.

Ja kui süsteemi uut versiooni testiti ja kasutusele võeti, tekkis taas ümardusbiti viga. Veelgi enam, soojade serverite arvu suurenemisega hakkas tõrge ilmnema sagedamini. Samal ajal polnud müüjal midagi ette näidata, kuna puudusid konkreetsed tõendid.

Järgmise olukorra analüüsi käigus tekkis teooria, et probleem võib olla seotud OS-iga. Kirjutasime lihtsa programmi, mis kutsub funktsiooni lõputu tsüklina fesetround, jätab hetkeseisu meelde ja kontrollib seda unerežiimis ning seda tehakse paljudes konkureerivates lõimedes. Olles valinud unerežiimi parameetrid ja lõimede arvu, hakkasime pärast umbes 5-minutilist utiliidi käivitamist bititõrget järjekindlalt reprodutseerima. Red Hati tugi aga ei suutnud seda reprodutseerida. Meie teiste serverite testimine on näidanud, et ainult need, millel on teatud protsessorid, on vastuvõtlikud veale. Samal ajal lahendas probleemi uuele kernelile üleminek. Lõpuks vahetasime lihtsalt OS-i välja ja vea tegelik põhjus jäi ebaselgeks.

Ja äkki avaldati eelmisel aastal artikkel Habré kohta "Kuidas ma leidsin vea Intel Skylake'i protsessorites" Selles kirjeldatud olukord oli väga sarnane meie omaga, kuid autor viis uurimist edasi ja esitas teooria, et viga on mikrokoodis. Ja kui Linuxi tuumasid värskendatakse, värskendavad tootjad ka mikrokoodi.

Süsteemi edasiarendus

Kuigi saime veast lahti, sundis see lugu meid süsteemi arhitektuuri uuesti läbi vaatama. Lõppude lõpuks polnud me selliste vigade kordumise eest kaitstud.

Järgmised põhimõtted olid broneerimissüsteemi järgmiste täiustuste aluseks:

  • Sa ei saa kedagi usaldada. Serverid ei pruugi korralikult töötada.
  • Enamuse reservatsioon.
  • Konsensuse tagamine. Loogilise täiendusena enamuse reservatsioonile.
  • Võimalikud on topeltrikked.
  • Elujõud. Uus kuuma ooterežiimi skeem ei tohiks olla eelmisest halvem. Kauplemine peaks jätkuma katkematult kuni viimase serverini.
  • Väike latentsusaja suurenemine. Iga seisak toob kaasa suuri rahalisi kaotusi.
  • Minimaalne võrgu suhtlus, et hoida latentsusaeg võimalikult madalal.
  • Uue peaserveri valimine sekunditega.

Ükski turul saadaolevatest lahendustest meile ei sobinud ja Raft protokoll oli alles lapsekingades, nii et lõime oma lahenduse.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Võrgustiku loomine

Lisaks broneerimissüsteemile alustasime võrgusuhtluse kaasajastamist. I/O alamsüsteem koosnes paljudest protsessidest, millel oli kõige halvem mõju värinale ja latentsusele. Kuna TCP-ühendusi käsitlesid sadu protsesse, olime sunnitud nende vahel pidevalt ümber lülituma ja mikrosekundi skaalal on see üsna aeganõudev toiming. Kuid kõige hullem on see, et kui protsess sai töötlemiseks paketi, saatis ta selle ühte SystemV järjekorda ja ootas seejärel sündmust teisest SystemV järjekorrast. Kui aga sõlmede arv on suur, tähistab uue TCP-paketi saabumine ühes protsessis ja andmete järjekorda vastuvõtmine teises OS-i kahte konkureerivat sündmust. Sel juhul, kui mõlema ülesande jaoks pole ühtegi füüsilist protsessorit saadaval, töödeldakse ühte ja teine ​​asetatakse ootejärjekorda. Selle tagajärgi on võimatu ennustada.

Sellistes olukordades saab kasutada dünaamilist protsessi prioriteedi juhtimist, kuid see nõuab ressursimahukate süsteemikutsete kasutamist. Selle tulemusena läksime klassikalise epolli abil üle ühele lõimele, see suurendas oluliselt kiirust ja vähendas tehingute töötlemise aega. Samuti vabanesime eraldiseisvatest võrgusuhtlusprotsessidest ja SystemV kaudu suhtlemisest, vähendasime oluliselt süsteemikõnede arvu ja hakkasime kontrollima toimingute prioriteete. Ainuüksi I/O alamsüsteemil oli olenevalt stsenaariumist võimalik säästa umbes 8-17 mikrosekundit. Seda ühe keermega skeemi on sellest ajast peale kasutatud muutmata kujul, kõigi ühenduste teenindamiseks piisab ühest veerisega epolli keermest.

Tehingute töötlemine

Meie süsteemi kasvav koormus nõudis peaaegu kõigi selle komponentide uuendamist. Kuid kahjuks pole viimastel aastatel protsessorite taktsageduste kasvu stagnatsioon enam võimaldanud protsesse mastaapida. Seetõttu otsustasime jagada Engine’i protsessi kolmeks tasandiks, millest kõige aktiivsem on riskikontrollisüsteem, mis hindab kontodel olevate rahaliste vahendite olemasolu ja loob ise tehingud. Kuid raha võib olla erinevates valuutades ja tuli välja mõelda, mille alusel taotluste menetlemine jagada.

Loogiline lahendus on jagada see valuuta järgi: üks server kaupleb dollarites, teine ​​naeltega ja kolmas eurodes. Kuid kui selle skeemi abil saadetakse kaks tehingut erinevate valuutade ostmiseks, siis tekib rahakoti desünkroniseerimise probleem. Kuid sünkroonimine on keeruline ja kallis. Seetõttu oleks õige killustada eraldi rahakottide ja eraldi instrumentide kaupa. Muide, enamikul lääne börsidel pole ülesannet nii kiiresti riske kontrollida kui meil, nii et enamasti tehakse seda võrguühenduseta. Peame rakendama veebipõhise kinnitamise.

Selgitame näitega. Kaupleja soovib osta 30 dollarit ja päring läheb tehingu kinnitamiseks: kontrollime, kas sellel kauplejal on see kauplemisrežiim lubatud ja kas tal on selleks vajalikud õigused. Kui kõik on korras, läheb päring riskikontrolli süsteemi, s.o. kontrollida rahaliste vahendite piisavust tehingu tegemiseks. Seal on märge, et vajalik summa on hetkel blokeeritud. Seejärel edastatakse päring kauplemissüsteemile, kes tehingu heaks kiidab või tagasi lükkab. Oletame, et tehing on kinnitatud – siis märgib riskikontrollisüsteem, et raha on blokeeringust vabastatud ja rublad muutuvad dollariteks.

Üldiselt sisaldab riskikontrollisüsteem keerulisi algoritme ja teeb suurel hulgal väga ressursimahukaid arvutusi, mitte ei kontrolli lihtsalt “kontojääki”, nagu esmapilgul võib tunduda.

Kui alustasime mootori protsessi tasemeteks jagamist, tekkis probleem: sel ajal saadaval olnud kood kasutas valideerimise ja kontrollimise etapis aktiivselt sama andmemassiivi, mis nõudis kogu koodibaasi ümberkirjutamist. Selle tulemusena laenasime kaasaegsetelt protsessoritelt käskude töötlemise tehnika: igaüks neist on jagatud väikesteks etappideks ja ühes tsüklis tehakse mitu toimingut paralleelselt.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Pärast koodi väikest kohandamist lõime paralleelseks tehingute töötlemiseks torujuhtme, milles tehing jaotati 4 konveieri etappi: võrgu interaktsioon, valideerimine, täitmine ja tulemuse avaldamine.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Vaatame näidet. Meil on kaks töötlemissüsteemi, jada- ja paralleelne. Esimene tehing saabub ja saadetakse mõlemasse süsteemi kinnitamiseks. Kohe saabub teine ​​tehing: paralleelsüsteemis võetakse see kohe tööle ja järjestikuses süsteemis järjekorda, mis ootab, et esimene tehing jooksva töötlemisetapi läbiks. See tähendab, et konveieri töötlemise peamine eelis on see, et töötleme tehingujärjekorda kiiremini.

Nii jõudsime ASTS+ süsteemini.

Tõsi, ka konveieritega pole kõik nii sujuv. Oletame, et meil on tehing, mis mõjutab naabertehingu andmemassiive; see on tüüpiline börsi olukord. Sellist tehingut ei saa teha konveier, kuna see võib mõjutada teisi. Seda olukorda nimetatakse andmeohuks ja selliseid tehinguid töödeldakse lihtsalt eraldi: kui järjekorras olevad "kiired" tehingud saavad otsa, konveier peatub, süsteem töötleb "aeglast" tehingut ja käivitab seejärel konveieri uuesti. Õnneks on selliste tehingute osakaal üldises voos väga väike, mistõttu torujuhe peatub nii harva, et see ei mõjuta üldist jõudlust.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Seejärel hakkasime lahendama kolme täitmise lõime sünkroonimise probleemi. Tulemuseks oli süsteem, mis põhineb fikseeritud suurusega rakkudega rõngaspuhveril. Selles süsteemis allub kõik töötlemiskiirusele, andmeid ei kopeerita.

  • Kõik sissetulevad võrgupaketid sisenevad jaotusfaasi.
  • Asetame need massiivi ja märgime need 1. etapi jaoks saadaolevateks.
  • Teine tehing on saabunud, see on taas saadaval etapile nr 1.
  • Esimene töötlemislõng näeb saadaolevaid tehinguid, töötleb neid ja viib need teise töötlemise lõime järgmisse etappi.
  • Seejärel töötleb see esimest tehingut ja märgistab vastava lahtri deleted — see on nüüd uueks kasutamiseks saadaval.

Sel viisil töödeldakse kogu järjekorda.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Iga etapi töötlemine võtab aega ühikuid või kümneid mikrosekundeid. Ja kui kasutame standardseid OS-i sünkroonimisskeeme, kaotame sünkroonimisele endale rohkem aega. Seetõttu hakkasime kasutama spinlocki. Kuid see on reaalajas süsteemis väga halb vorm ja RedHat ei soovita seda rangelt teha, seega rakendame 100 ms-ks spinlocki ja seejärel lülitame ummikseisu välistamiseks semaforirežiimi.

Selle tulemusel saavutasime umbes 8 miljoni tehingu sekundis. Ja sõna otseses mõttes kaks kuud hiljem siit LMAX Disruptori kohta nägime sama funktsionaalsusega vooluringi kirjeldust.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Nüüd võib ühes etapis olla mitu täitmise lõime. Kõik tehingud töödeldi ükshaaval, nende laekumise järjekorras. Selle tulemusena kasvas tipptulemus 18 tuhandelt 50 tuhande tehinguni sekundis.

Börsiriski juhtimise süsteem

Täiuslikkusel pole piire ja peagi alustasime taas moderniseerimisega: ASTS+ raames alustasime riskijuhtimis- ja arveldusoperatsioonide süsteemide viimist autonoomsetesse komponentidesse. Töötasime välja paindliku kaasaegse arhitektuuri ja uue hierarhilise riskimudeli ning püüdsime kasutada klassi igal võimalusel fixed_point asemel double.

Kuid kohe tekkis probleem: kuidas sünkroniseerida kogu aastaid töötanud äriloogika ja viia see uude süsteemi? Seetõttu tuli uue süsteemi prototüübi esimesest versioonist loobuda. Teine versioon, mis hetkel töötab tootmises, põhineb samal koodil, mis töötab nii kauplemis- kui ka riskiosas. Arendamise ajal oli kõige raskem teha kahe versiooni git-ühendamist. Meie kolleeg Jevgeni Mazurenok tegi seda operatsiooni igal nädalal ja kirus iga kord väga pikka aega.

Uue süsteemi valimisel tuli koheselt lahendada interaktsiooni probleem. Andmesiini valikul oli vaja tagada stabiilne värin ja minimaalne latentsus. Selleks sobis kõige paremini InfiniBand RDMA võrk: keskmine töötlemisaeg on 4 korda väiksem kui 10 G Etherneti võrkudes. Kuid see, mis meid tõeliselt võlus, oli protsentiilide erinevus – 99 ja 99,9.

Muidugi on InfiniBandil oma väljakutsed. Esiteks teistsugune API – soklite asemel ibverbid. Teiseks pole peaaegu üldse laialdaselt kättesaadavaid avatud lähtekoodiga sõnumside lahendusi. Proovisime teha oma prototüüpi, kuid see osutus väga keeruliseks, mistõttu valisime kommertslahenduse – Confinity Low Latency Messaging (endine IBM MQ LLM).

Siis tekkis ülesanne riskisüsteem õigesti jaotada. Kui eemaldate lihtsalt riskimootori ja ei loo vahesõlme, saab kahest allikast pärinevaid tehinguid segada.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Nn Ultra Low Latency lahendustel on reordering režiim: kahest allikast saabuvaid tehinguid saab nende laekumisel korraldada vajalikus järjekorras, see realiseeritakse tellimuse info vahetamiseks eraldi kanalit kasutades. Kuid me ei kasuta seda režiimi veel: see muudab kogu protsessi keeruliseks ja paljudes lahendustes ei toetata seda üldse. Lisaks tuleks igale tehingule omistada vastavad ajatemplid ja meie skeemis on seda mehhanismi väga keeruline õigesti rakendada. Seetõttu kasutasime klassikalist skeemi koos sõnumi vahendajaga ehk dispetšeriga, mis jagab sõnumeid riskimootori vahel.

Teine probleem oli seotud kliendi juurdepääsuga: kui riskilüüsi on mitu, peab klient neist igaühega ühenduse looma ja see nõuab kliendikihi muutmist. Tahtsime sellest praeguses etapis lahti saada, nii et praegune Risk Gateway disain töötleb kogu andmevoogu. See piirab oluliselt maksimaalset läbilaskevõimet, kuid lihtsustab oluliselt süsteemi integreerimist.

Dubleerimine

Meie süsteemil ei tohiks olla ühte tõrkepunkti, see tähendab, et kõik komponendid peavad olema dubleeritud, sealhulgas sõnumivahendaja. Selle probleemi lahendasime CLLM-süsteemi abil: see sisaldab RCMS-klastrit, milles kaks dispetšerit saavad töötada ülem-alluv-režiimis ja kui üks ebaõnnestub, lülitub süsteem automaatselt teisele.

Töötamine varuandmekeskusega

InfiniBand on optimeeritud töötama kohaliku võrguna, st rack-mount seadmete ühendamiseks ja InfiniBand võrku ei saa paigutada kahe geograafiliselt hajutatud andmekeskuse vahele. Seetõttu rakendasime silla/dispetšeri, mis ühendub tavaliste Etherneti võrkude kaudu sõnumisalvestusega ja edastab kõik tehingud teise IB võrku. Kui peame andmekeskusest üle minema, saame valida, millise andmekeskusega praegu töötada.

Tulemused

Kõike ülaltoodut ei tehtud korraga, uue arhitektuuri väljatöötamiseks kulus mitu kordamist. Prototüübi lõime kuu ajaga, kuid selle töökorda saamiseks kulus üle kahe aasta. Püüdsime saavutada parimat kompromissi tehingute töötlemise aja pikendamise ja süsteemi töökindluse suurendamise vahel.

Kuna süsteemi uuendati põhjalikult, rakendasime andmete taastamise kahest sõltumatust allikast. Kui sõnumisalv mingil põhjusel korralikult ei tööta, saate tehingulogi võtta teisest allikast – riskimootorist. Seda põhimõtet järgitakse kogu süsteemis.

Muuhulgas suutsime säilitada kliendi API nii, et ei maaklerid ega keegi teine ​​ei nõuaks uue arhitektuuri jaoks olulist ümbertegemist. Pidime muutma mõningaid liideseid, kuid olulisi muudatusi töömudelis ei olnud vaja teha.

Nimetasime oma platvormi praeguse versiooni Rebus - kahe kõige märgatavama arhitektuuri uuenduse lühendina Risk Engine ja BUS.

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Algselt tahtsime eraldada ainult puhastusosa, kuid tulemuseks oli tohutu hajutatud süsteem. Kliendid saavad nüüd suhelda kas Trade Gateway, Clearing Gateway või mõlemaga.

Mida me lõpuks saavutasime:

Moskva börsi kauplemis- ja arveldussüsteemi arhitektuuri areng. 2. osa

Vähendas latentsusaega. Väikese tehingute mahu korral töötab süsteem samamoodi nagu eelmine versioon, kuid talub samas palju suuremat koormust.

Maksimaalne jõudlus kasvas 50 tuhandelt 180 tuhande tehinguni sekundis. Edasist kasvu takistab ainus tellimuste sobitamise voog.

Edasiseks täiustamiseks on kaks võimalust: sobitamise paralleelsus ja Gatewayga töötamise muutmine. Nüüd töötavad kõik lüüsid replikatsiooniskeemi järgi, mis sellise koormuse korral lakkab normaalselt töötamast.

Lõpetuseks võin anda nõu neile, kes viimistlevad ettevõtte süsteeme:

  • Olge alati valmis halvimaks. Probleemid tekivad alati ootamatult.
  • Arhitektuuri kiiresti ümber teha on tavaliselt võimatu. Eriti kui teil on vaja saavutada maksimaalne usaldusväärsus mitme näitaja osas. Mida rohkem sõlme, seda rohkem on toeks vaja ressursse.
  • Kõik kohandatud ja patenteeritud lahendused nõuavad täiendavaid ressursse uurimise, toe ja hoolduse jaoks.
  • Ärge lükake süsteemi töökindluse ja tõrgetejärgse taastumise probleemide lahendamist edasi; võtke neid arvesse esialgses projekteerimisetapis.

Allikas: www.habr.com

Lisa kommentaar