Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Tai ilgos istorijos apie mūsų sudėtingą kelią kuriant galingą, didelės apkrovos sistemą, užtikrinančią Biržos veiklą, tęsinys. Pirmoji dalis čia: habr.com/en/post/444300

Paslaptinga klaida

Po daugybės bandymų buvo pradėta eksploatuoti atnaujinta prekybos ir kliringo sistema ir susidūrėme su klaida, apie kurią galėjome parašyti detektyvinę-mistinę istoriją.

Netrukus po paleidimo pagrindiniame serveryje viena iš operacijų buvo apdorota su klaida. Tačiau atsarginiame serveryje viskas buvo gerai. Paaiškėjo, kad paprasta matematinė veiksnio skaičiavimo operacija pagrindiniame serveryje davė neigiamą tikrojo argumento rezultatą! Tęsėme tyrimą ir SSE2 registre radome skirtumą viename bite, kuris yra atsakingas už apvalinimą dirbant su slankiojo kablelio skaičiais.

Parašėme paprastą testavimo priemonę, skirtą eksponentui apskaičiuoti su apvalinimo bitų rinkiniu. Paaiškėjo, kad mūsų naudojamoje „RedHat Linux“ versijoje buvo klaida dirbant su matematine funkcija, kai buvo įdėtas nelemtas bitas. Pranešėme apie tai RedHat, po kurio laiko gavome iš jų pleistrą ir išvyniojome. Klaida nebeįvyko, bet buvo neaišku, iš kur šis bitas atsirado? Funkcija buvo už tai atsakinga fesetround Iš kalbos C. Kruopščiai išanalizavome savo kodą, ieškodami tariamos klaidos: patikrinome visas įmanomas situacijas; peržiūrėjo visas funkcijas, kurios naudojo apvalinimą; bandė atkurti nepavykusią seansą; naudojo skirtingus kompiliatorius su skirtingomis parinktimis; Naudota statinė ir dinaminė analizė.

Klaidos priežasties nepavyko rasti.

Tada jie pradėjo tikrinti techninę įrangą: atliko procesorių apkrovos testavimą; patikrino RAM; Mes netgi atlikome labai mažai tikėtino kelių bitų klaidos scenarijaus bandymus viename langelyje. Be jokios naudos.

Galų gale apsistojome ties didelės energijos fizikos pasaulio teorija: didelės energijos dalelė įskrido į mūsų duomenų centrą, pramušė korpuso sienelę, pataikė į procesorių ir paleidimo skląstis įstrigo. Ši absurdiška teorija buvo vadinama „neutrinu“. Jei esate toli nuo dalelių fizikos: neutrinai beveik nesąveikauja su išoriniu pasauliu ir tikrai negali paveikti procesoriaus veikimo.

Kadangi nepavyko rasti gedimo priežasties, „pažeidžiantis“ serveris buvo pašalintas iš darbo bet kuriuo atveju.

Po kurio laiko pradėjome tobulinti karštąją atsarginę sistemą: pristatėme vadinamąsias „šiltąsias atsargas“ (šiltas) - asinchronines kopijas. Jie gavo srautą operacijų, kurios galėjo būti skirtinguose duomenų centruose, tačiau šiltieji nebendravo su kitais serveriais.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Kodėl tai buvo padaryta? Jei atsarginės kopijos serveris sugenda, tada šiltas susietas su pagrindiniu serveriu tampa nauja atsargine kopija. Tai yra, po gedimo sistema nelieka su vienu pagrindiniu serveriu iki prekybos sesijos pabaigos.

O kai nauja sistemos versija buvo išbandyta ir pradėta eksploatuoti, vėl pasireiškė apvalinimo bitų klaida. Be to, didėjant šiltų serverių skaičiui, klaida pradėjo atsirasti dažniau. Tuo pačiu metu pardavėjas neturėjo ką parodyti, nes nebuvo konkrečių įrodymų.

Kitos situacijos analizės metu iškilo teorija, kad problema gali būti susijusi su OS. Parašėme paprastą programą, kuri iškviečia funkciją begaliniu ciklu fesetround, prisimena dabartinę būseną ir patikrina ją miego režimu, ir tai daroma daugelyje konkuruojančių gijų. Pasirinkę miego parametrus ir gijų skaičių, pradėjome nuosekliai atkurti bitų gedimą praėjus maždaug 5 minutėms nuo programos paleidimo. Tačiau „Red Hat“ palaikymas negalėjo to atkurti. Kitų mūsų serverių bandymai parodė, kad klaida gali atsirasti tik tiems, kurie turi tam tikrus procesorius. Tuo pačiu metu perjungimas į naują branduolį išsprendė problemą. Galų gale mes tiesiog pakeitėme OS, o tikroji klaidos priežastis liko neaiški.

Ir staiga praėjusiais metais buvo paskelbtas straipsnis apie Habré “Kaip radau „Intel Skylake“ procesorių klaidą“ Jame aprašyta situacija buvo labai panaši į mūsų, tačiau autorius tęsė tyrimą ir iškėlė teoriją, kad klaida yra mikrokode. O kai Linux branduoliai atnaujinami, gamintojai atnaujina ir mikrokodą.

Tolesnis sistemos tobulinimas

Nors klaidos atsikratėme, ši istorija privertė persvarstyti sistemos architektūrą. Juk nebuvome apsaugoti nuo tokių klaidų pasikartojimo.

Šie principai sudarė pagrindą kitiems rezervavimo sistemos patobulinimams:

  • Jūs negalite niekuo pasitikėti. Serveriai gali neveikti tinkamai.
  • Daugumos rezervacija.
  • Konsensuso užtikrinimas. Kaip logiškas daugumos išlygos papildymas.
  • Galimi dvigubi gedimai.
  • Gyvybingumas. Nauja karšto budėjimo režimo schema neturėtų būti prastesnė nei ankstesnė. Prekyba turėtų vykti nepertraukiamai iki paskutinio serverio.
  • Nedidelis delsos padidėjimas. Bet koks prastovos laikas sukelia didelių finansinių nuostolių.
  • Minimali tinklo sąveika, kad delsa būtų kuo mažesnė.
  • Naujo pagrindinio serverio pasirinkimas per kelias sekundes.

Nė vienas iš rinkoje esančių sprendimų mums netiko, o „Raft“ protokolas buvo dar tik formuojantis, todėl sukūrėme savo sprendimą.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Tinklo kūrimas

Be rezervavimo sistemos, pradėjome modernizuoti tinklų sąveiką. Įvesties / išvesties posistemį sudarė daug procesų, kurie turėjo didžiausią įtaką virpesiui ir vėlavimui. Šimtai procesų, tvarkančių TCP ryšius, buvome priversti nuolat juos keisti, o mikrosekundžių skalėje tai yra gana daug laiko reikalaujanti operacija. Tačiau blogiausia yra tai, kad kai procesas gavo paketą apdoroti, jis nusiuntė jį į vieną SystemV eilę ir laukė įvykio iš kitos SystemV eilės. Tačiau kai yra daug mazgų, naujo TCP paketo atėjimas viename procese ir duomenų gavimas į eilę kitame reiškia du konkuruojančius OS įvykius. Tokiu atveju, jei nėra fizinių procesorių abiem užduotims atlikti, vienas bus apdorotas, o antrasis bus įtrauktas į laukiančią eilę. Neįmanoma numatyti pasekmių.

Tokiose situacijose gali būti naudojamas dinaminis proceso prioriteto valdymas, tačiau tam reikės naudoti daug išteklių reikalaujančius sistemos iškvietimus. Dėl to perėjome prie vienos gijos naudodami klasikinį epoll, tai labai padidino greitį ir sumažino operacijų apdorojimo laiką. Taip pat atsikratėme atskirų tinklo ryšio procesų ir komunikacijos per SystemV, gerokai sumažinome sistemos skambučių skaičių ir pradėjome kontroliuoti operacijų prioritetus. Vien I/O posistemyje, priklausomai nuo scenarijaus, buvo galima sutaupyti apie 8-17 mikrosekundžių. Ši vieno sriegio schema nuo to laiko naudojama nepakitusi, užtenka vienos epoll gijos su parašte, kad būtų galima aptarnauti visas jungtis.

Sandorių apdorojimas

Didėjant mūsų sistemos apkrovai, reikėjo atnaujinti beveik visus jos komponentus. Tačiau, deja, pastaraisiais metais sustojus procesoriaus dažnių augimui, procesų staigiai didinti nebuvo įmanoma. Todėl nusprendėme Engine procesą suskirstyti į tris lygius, iš kurių aktyviausias yra rizikos tikrinimo sistema, kuri įvertina lėšų prieinamumą sąskaitose ir sukuria pačias operacijas. Tačiau pinigai gali būti skirtingomis valiutomis, todėl reikėjo išsiaiškinti, kuo remiantis turėtų būti padalintas užklausų apdorojimas.

Logiška išeitis – padalyti pagal valiutą: vienas serveris prekiauja doleriais, kitas – svarais, trečias – eurais. Bet jei naudojant tokią schemą siunčiamos dvi operacijos skirtingoms valiutoms įsigyti, tada iškils piniginės desinchronizavimo problema. Tačiau sinchronizuoti yra sunku ir brangu. Todėl būtų teisinga skaldyti atskirai pagal pinigines ir atskirai pagal instrumentus. Beje, dauguma Vakarų biržų neturi užduoties taip aštriai tikrinti riziką kaip mes, todėl dažniausiai tai daroma neprisijungus. Mums reikėjo įdiegti internetinį patvirtinimą.

Paaiškinkime pavyzdžiu. Prekybininkas nori nusipirkti 30 USD, o užklausa eina į sandorio patvirtinimą: mes patikriname, ar šis prekiautojas turi šį prekybos režimą ir ar jis turi reikiamas teises. Jei viskas tvarkoje, užklausa patenka į rizikos tikrinimo sistemą, t.y. patikrinti, ar pakanka lėšų sandoriui sudaryti. Yra pastaba, kad reikiama suma šiuo metu užblokuota. Tada užklausa persiunčiama į prekybos sistemą, kuri patvirtina arba nepatvirtina sandorio. Tarkime, sandoris patvirtinamas – tada rizikos tikrinimo sistema pažymi, kad pinigai atblokuoti, o rubliai paverčiami doleriais.

Apskritai rizikos tikrinimo sistemoje yra sudėtingi algoritmai ir atliekama daug labai daug resursų reikalaujančių skaičiavimų, o ne tik tikrinamas „sąskaitos likutis“, kaip gali pasirodyti iš pirmo žvilgsnio.

Pradėję skirstyti Engine procesą į lygius, susidūrėme su problema: tuo metu turimas kodas tikrinimo ir tikrinimo etapuose aktyviai naudojo tą patį duomenų masyvą, todėl reikėjo perrašyti visą kodo bazę. Dėl to instrukcijų apdorojimo techniką pasiskolinome iš šiuolaikinių procesorių: kiekvienas iš jų suskirstytas į mažus etapus ir vienu ciklu lygiagrečiai atliekami keli veiksmai.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Po nedidelio kodo pritaikymo sukūrėme lygiagrečiam transakcijų apdorojimui skirtą konvejerį, kuriame operacija buvo padalinta į 4 konvejerio etapus: tinklo sąveika, patvirtinimas, vykdymas ir rezultato paskelbimas.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Pažiūrėkime į pavyzdį. Turime dvi apdorojimo sistemas – nuosekliąją ir lygiagrečiąją. Pirmoji operacija gaunama ir siunčiama patvirtinti abiejose sistemose. Iš karto ateina antrasis sandoris: lygiagrečioje sistemoje ji iškart pradedama dirbti, o nuoseklioje sistemoje – į eilę laukiant, kol pirmoji transakcija praeis einamajame apdorojimo etape. Tai yra, pagrindinis dujotiekio apdorojimo privalumas yra tai, kad operacijų eilę apdorojame greičiau.

Taip sugalvojome ASTS+ sistemą.

Tiesa, ir su konvejeriais ne viskas taip sklandžiai. Tarkime, kad turime operaciją, kuri paveikia gretimos operacijos duomenų masyvus; tai yra tipiška mainų situacija. Toks sandoris negali būti vykdomas iš anksto, nes jis gali turėti įtakos kitiems. Tokia situacija vadinama duomenų pavojumi ir tokios operacijos tiesiog apdorojamos atskirai: pasibaigus eilėje esančioms „greitoms“ operacijoms, konvejeris sustoja, sistema apdoroja „lėtą“ operaciją ir vėl paleidžia konvejerį. Laimei, tokių sandorių dalis bendrame sraute yra labai maža, todėl dujotiekis sustoja taip retai, kad tai neturi įtakos bendram veikimui.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Tada pradėjome spręsti trijų vykdymo gijų sinchronizavimo problemą. Rezultatas buvo sistema, pagrįsta žiediniu buferiu su fiksuoto dydžio ląstelėmis. Šioje sistemoje viskas priklauso nuo apdorojimo greičio, duomenys nėra kopijuojami.

  • Visi gaunami tinklo paketai patenka į paskirstymo etapą.
  • Dedame juos į masyvą ir pažymime kaip prieinamus 1 etapui.
  • Atėjo antrasis sandoris, jis vėl prieinamas 1 etapui.
  • Pirmoji apdorojimo gija mato galimas operacijas, jas apdoroja ir perkelia į kitą antrojo apdorojimo gijos etapą.
  • Tada jis apdoroja pirmąją operaciją ir pažymi atitinkamą langelį deleted – dabar galima naudoti naujai.

Tokiu būdu apdorojama visa eilė.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Kiekvieno etapo apdorojimas trunka vienetus arba keliasdešimt mikrosekundžių. O jei naudosime standartines OS sinchronizavimo schemas, tai sugaišime daugiau laiko pačiam sinchronizavimui. Štai kodėl mes pradėjome naudoti spinlock. Tačiau realaus laiko sistemoje tai yra labai bloga forma, o RedHat griežtai nerekomenduoja to daryti, todėl taikome sukimosi blokavimą 100 ms, o tada perjungiame į semaforo režimą, kad pašalintume aklavietės galimybę.

Dėl to pasiekėme apie 8 mln. operacijų per sekundę našumą. Ir tiesiog po dviejų mėnesių straipsnis apie LMAX Disruptor matėme grandinės su tomis pačiomis funkcijomis aprašymą.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Dabar viename etape gali būti kelios vykdymo gijos. Visos operacijos buvo vykdomos po vieną, tokia tvarka, kokia buvo gautos. Dėl to didžiausias našumas padidėjo nuo 18 tūkst. iki 50 tūkst. operacijų per sekundę.

Valiutos rizikos valdymo sistema

Tobulumui ribų nėra ir netrukus vėl pradėjome modernizaciją: ASTS+ rėmuose rizikos valdymo ir atsiskaitymų operacijų sistemas pradėjome perkelti į savarankiškus komponentus. Sukūrėme lanksčią modernią architektūrą ir naują hierarchinį rizikos modelį ir stengėmės naudoti klasę, kur tik įmanoma fixed_point vietoj double.

Tačiau iškart iškilo problema: kaip sinchronizuoti visą daugelį metų veikiančią verslo logiką ir perkelti ją į naują sistemą? Dėl to teko atsisakyti pirmosios naujosios sistemos prototipo versijos. Antroji versija, kuri šiuo metu veikia gamyboje, yra paremta tuo pačiu kodu, kuris veikia tiek prekybinėje, tiek rizikos dalyje. Kūrimo metu sunkiausia buvo sujungti dvi versijas. Mūsų kolega Jevgenijus Mazurenok šią operaciją atlikdavo kiekvieną savaitę ir kiekvieną kartą labai ilgai keikdavosi.

Renkantis naują sistemą, iš karto turėjome išspręsti sąveikos problemą. Renkantis duomenų magistralę, reikėjo užtikrinti stabilų virpėjimą ir minimalų delsą. Tam geriausiai tiko InfiniBand RDMA tinklas: vidutinis apdorojimo laikas yra 4 kartus trumpesnis nei 10 G Ethernet tinkluose. Tačiau mus tikrai sužavėjo procentilių skirtumas – 99 ir 99,9.

Žinoma, „InfiniBand“ turi savo iššūkių. Pirma, kitokia API – ibverbs vietoj sockets. Antra, beveik nėra plačiai prieinamų atvirojo kodo pranešimų siuntimo sprendimų. Bandėme sukurti savo prototipą, tačiau tai pasirodė labai sunku, todėl pasirinkome komercinį sprendimą – Confinity Low Latency Messaging (anksčiau IBM MQ LLM).

Tada iškilo užduotis tinkamai padalinti rizikos sistemą. Jei tiesiog pašalinsite rizikos variklį ir nesukursite tarpinio mazgo, operacijos iš dviejų šaltinių gali būti maišomos.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Vadinamieji Ultra Low Latency sprendimai turi pertvarkymo režimą: sandorius iš dviejų šaltinių galima sutvarkyti reikiama tvarka gavus, tai įgyvendinama naudojant atskirą informacijos apie užsakymą apsikeitimo kanalą. Tačiau mes dar nenaudojame šio režimo: jis apsunkina visą procesą, o daugelyje sprendimų jis visiškai nepalaikomas. Be to, kiekvienai operacijai reikėtų priskirti atitinkamas laiko žymas, o mūsų schemoje šį mechanizmą labai sunku teisingai įgyvendinti. Todėl mes naudojome klasikinę schemą su pranešimų tarpininku, tai yra su dispečeriu, kuris paskirsto pranešimus tarp rizikos variklio.

Antroji problema buvo susijusi su kliento prieiga: jei yra keli Rizikos šliuzai, klientas turi prisijungti prie kiekvieno iš jų ir tam reikės pakeisti kliento sluoksnį. Šiame etape norėjome to atsikratyti, todėl dabartinis „Risk Gateway“ dizainas apdoroja visą duomenų srautą. Tai labai apriboja didžiausią pralaidumą, tačiau labai supaprastina sistemos integravimą.

Kopijavimas

Mūsų sistemoje neturėtų būti vieno gedimo taško, ty visi komponentai turi būti dubliuoti, įskaitant pranešimų tarpininką. Šią problemą išsprendėme naudodamiesi CLLM sistema: joje yra RCMS klasteris, kuriame gali dirbti du dispečeriai pagrindiniu-slave režimu, o vienam sugedus sistema automatiškai persijungia į kitą.

Darbas su atsarginiu duomenų centru

„InfiniBand“ yra optimizuotas veikti kaip vietinis tinklas, ty prijungti ant stovo montuojamą įrangą, o „InfiniBand“ tinklo negalima nutiesti tarp dviejų geografiškai paskirstytų duomenų centrų. Todėl įdiegėme tiltą / dispečerį, kuris jungiasi prie pranešimų saugyklos per įprastus Ethernet tinklus ir perduoda visas operacijas į antrąjį IB tinklą. Kai mums reikia pereiti iš duomenų centro, galime pasirinkti, su kuriuo duomenų centru dirbti dabar.

rezultatai

Visa tai, kas išdėstyta pirmiau, nebuvo atlikta iš karto, prireikė kelių pakartojimų kuriant naują architektūrą. Prototipą sukūrėme per mėnesį, tačiau prireikė daugiau nei dvejų metų, kad jis taptų darbingas. Stengėmės pasiekti geriausią kompromisą tarp ilgesnio operacijų apdorojimo laiko ir sistemos patikimumo didinimo.

Kadangi sistema buvo labai atnaujinta, įdiegėme duomenų atkūrimą iš dviejų nepriklausomų šaltinių. Jei pranešimų saugykla dėl kokių nors priežasčių neveikia tinkamai, operacijų žurnalą galite paimti iš antrojo šaltinio – iš rizikos variklio. Šio principo laikomasi visoje sistemoje.

Be kita ko, sugebėjome išsaugoti kliento API, kad nei brokeriai, nei kas nors kitas nereikalautų didelio naujos architektūros perdarymo. Teko keisti kai kurias sąsajas, tačiau esminių veiklos modelio pakeitimų nereikėjo.

Dabartinę savo platformos versiją pavadinome Rebus - kaip dviejų labiausiai pastebimų architektūros naujovių santrumpa, Risk Engine ir BUS.

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Iš pradžių norėjome skirti tik kliringo dalį, bet rezultatas buvo didžiulė paskirstyta sistema. Dabar klientai gali bendrauti su „Trade Gateway“, „Clearing Gateway“ arba abiem.

Ką mes galiausiai pasiekėme:

Maskvos biržos prekybos ir kliringo sistemos architektūros raida. 2 dalis

Sumažino delsos lygį. Esant nedidelei operacijų apimčiai, sistema veikia taip pat, kaip ir ankstesnė versija, tačiau tuo pačiu gali atlaikyti daug didesnę apkrovą.

Didžiausias našumas išaugo nuo 50 tūkst. iki 180 tūkst. operacijų per sekundę. Tolesnį augimą stabdo vienintelis užsakymų derinimo srautas.

Yra du tolesnio tobulinimo būdai: lygiagrečiai suderinti ir pakeisti jos veikimo būdą su „Gateway“. Dabar visi šliuzai veikia pagal replikacijos schemą, kuri, esant tokiai apkrovai, nustoja normaliai veikti.

Galiausiai galiu duoti patarimų tiems, kurie baigia kurti įmonės sistemas:

  • Būkite visada pasiruošę blogiausiam. Problemos visada iškyla netikėtai.
  • Paprastai greitai perdaryti architektūros neįmanoma. Ypač jei reikia pasiekti maksimalų kelių rodiklių patikimumą. Kuo daugiau mazgų, tuo daugiau išteklių reikia palaikymui.
  • Visiems individualiems ir patentuotiems sprendimams reikės papildomų išteklių tyrimams, palaikymui ir priežiūrai.
  • Neatidėliokite sistemos patikimumo ir atkūrimo po gedimų problemų sprendimo, į jas atsižvelkite pradiniame projektavimo etape.

Šaltinis: www.habr.com

Добавить комментарий