De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Dit is in fuortsetting fan in lang ferhaal oer ús thorny paad nei it meitsjen fan in krêftich, hege-load systeem dat soarget foar de wurking fan de Exchange. It earste diel is hjir: habr.com/en/post/444300

Mysterieuze flater

Nei tal fan tests waard it bywurke hannels- en ferwideringssysteem yn wurking brocht, en wy waarden konfrontearre mei in brek dêr't wy in detective-mystyk ferhaal oer skriuwe koene.

Koart nei it lansearjen op 'e haadtsjinner waard ien fan' e transaksjes ferwurke mei in flater. Alles wie lykwols goed op 'e reservekopytsjinner. It die bliken dat in ienfâldige wiskundige operaasje fan it berekkenjen fan de eksponint op 'e haadtsjinner in negatyf resultaat joech fan it echte argumint! Wy sette ús ûndersyk troch, en yn it SSE2-register fûnen wy in ferskil yn ien bit, dy't ferantwurdlik is foar ôfrûning by it wurkjen mei driuwende puntnûmers.

Wy hawwe in ienfâldich testprogramma skreaun om de eksponint te berekkenjen mei it rûningsbit set. It die bliken dat yn 'e ferzje fan RedHat Linux dy't wy brûkten, d'r in brek wie yn it wurkjen mei de wiskundige funksje doe't it ûngelokkige bit waard ynfoege. Wy melde dit oan RedHat, nei in skoftke wy krigen in patch fan harren en rôle it út. De flater kaam net mear foar, mar it wie ûndúdlik wêr't dit bytsje sels wei kaam? De funksje wie dêr ferantwurdlik foar fesetround út de taal C. Wy hawwe ús koade soarchfâldich analysearre op syk nei de sabeare flater: wy hawwe alle mooglike situaasjes kontrolearre; seach nei alle funksjes dy't rûning brûkten; besocht in mislearre sesje te reprodusearjen; brûkte ferskate gearstallers mei ferskate opsjes; Statyske en dynamyske analyze waarden brûkt.

De oarsaak fan de flater koe net fûn wurde.

Doe begûnen se de hardware te kontrolearjen: se hawwe loadtesten fan 'e processors útfierd; kontrolearre de RAM; Wy hawwe sels tests útfierd foar it heul ûnwierskynlike senario fan in multi-bit flater yn ien sel. Om 'e nocht.

Uteinlik hawwe wy fêstlein op in teory út 'e wrâld fan' e hege-enerzjyfysika: ien of oare hege-enerzjy-partikel fleach yn ús datasintrum, pierde de case-muorre, sloech de prosessor en feroarsake de trekkerslot yn dat heulendal. Dizze absurde teory waard de "neutrino" neamd. As jo ​​​​fier binne fan dieltsjefysika: neutrino's hawwe hast gjin ynteraksje mei de bûtenwrâld, en binne wis net yn steat om de wurking fan 'e prosessor te beynfloedzjen.

Om't it net mooglik wie om de oarsaak fan 'e mislearring te finen, waard de "beledigende" tsjinner út 'e operaasje fuortsmiten foar it gefal.

Nei in skoft begûnen wy it heule reservekopysysteem te ferbetterjen: wy yntrodusearre saneamde "waarme reserves" (waarm) - asynchrone replika's. Se krigen in stream fan transaksjes dy't yn ferskate datasintra lizze koenen, mar waarmte net aktyf ynteraksje mei oare servers.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Wêrom is dit dien? As de reservekopytsjinner mislearret, wurdt waarm ferbûn oan de haadtsjinner de nije reservekopy. Dat is, nei in mislearring, bliuwt it systeem net mei ien haadtsjinner oant it ein fan 'e hannelssesje.

En doe't de nije ferzje fan it systeem waard hifke en yn wurking, de rûning bit flater barde wer. Boppedat, mei it tanimmen fan it oantal waarme tsjinners, de flater begûn te ferskine faker. Tagelyk hie de ferkeaper neat te sjen, om't der gjin konkreet bewiis wie.

Tidens de folgjende analyze fan 'e situaasje ûntstie in teory dat it probleem kin wurde relatearre oan it OS. Wy hawwe in ienfâldich programma skreaun dat in funksje yn in einleaze loop neamt fesetround, ûnthâldt de hjoeddeiske steat en kontrolearret it troch sliep, en dit wurdt dien yn in protte konkurrearjende triedden. Nei't se de parameters foar sliep en it oantal triedden selektearre hawwe, begûnen wy konsekwint de bitfaling te reprodusearjen nei sawat 5 minuten fan it útfieren fan it hulpprogramma. Red Hat-stipe koe it lykwols net reprodusearje. Testen fan ús oare servers hat oantoand dat allinich dejingen mei bepaalde processors gefoelich binne foar de flater. Tagelyk hat it wikseljen nei in nije kernel it probleem oplost. Op it lêst hawwe wy gewoan it OS ferfongen, en de wiere oarsaak fan 'e brek bleau ûndúdlik.

En ynienen ferskynde ferline jier in artikel op Habré “Hoe't ik in brek fûn yn Intel Skylake-processors" De dêryn beskreaune sitewaasje wie tige te ferlykjen mei ús, mar de skriuwer naam it ûndersyk fierder en sette in teory nei foaren dat de flater yn de mikrokoade siet. En as Linux-kernels wurde bywurke, fernije fabrikanten ek de mikrokoade.

Fierdere ûntwikkeling fan it systeem

Hoewol wy de flater kwytrekke, twong dit ferhaal ús om de systeemarsjitektuer opnij te besjen. Wy wiene ommers net beskerme tsjin de werhelling fan sokke bugs.

De folgjende prinsipes foarmen de basis foar de folgjende ferbetterings oan it reservaatsysteem:

  • Jo kinne gjinien fertrouwe. Servers kinne miskien net goed funksjonearje.
  • Mearderheid reservearring.
  • It garandearjen fan konsensus. As logyske oanfolling op mearderheidsreservearing.
  • Dûbele mislearrings binne mooglik.
  • Vitality. It nije hot standby-skema moat net slimmer wêze as it foarige. Hannelje moat ûnûnderbrutsen trochgean oant de lêste tsjinner.
  • Lichte ferheging fan latency. Elke downtime bringt enoarme finansjele ferliezen mei.
  • Minimale netwurkynteraksje om de latency sa leech mooglik te hâlden.
  • Selektearje in nije masterserver yn sekonden.

Gjin fan 'e beskikbere oplossingen op' e merk paste ús, en it Raft-protokol wie noch yn 'e berneskuon, dat wy makken ús eigen oplossing.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Netwurking

Neist it reservearringssysteem binne wy ​​begûn mei it modernisearjen fan netwurkynteraksje. It I / O-subsysteem bestie út in protte prosessen, dy't de minste ynfloed hiene op jitter en latency. Mei hûnderten prosessen dy't TCP-ferbiningen behannelje, waarden wy twongen om konstant tusken har te wikseljen, en op in mikrosekonde skaal is dit in nochal tiidslinend operaasje. Mar it slimste diel is dat as in proses in pakket krige foar ferwurking, stjoerde it it nei ien SystemV-wachtrige en wachte dan op in evenemint fan in oare SystemV-wachtrige. As d'r lykwols in grut oantal knopen binne, fertsjintwurdigje de komst fan in nij TCP-pakket yn ien proses en de ûntfangst fan gegevens yn 'e wachtrige yn in oar twa konkurrearjende eveneminten foar it OS. Yn dit gefal, as der gjin fysike processors beskikber binne foar beide taken, sil ien wurde ferwurke, en de twadde wurdt pleatst yn in wachtrige. It is ûnmooglik om de gefolgen te foarsizzen.

Yn sokke situaasjes kin dynamyske proses prioriteit kontrôle brûkt wurde, mar dit sil fereaskje it brûken fan boarne-yntinsive systeem calls. As gefolch hawwe wy oerstapt nei ien tried mei klassike epoll, dit fergrutte de snelheid sterk en fermindere de ferwurkingstiid fan transaksjes. Wy hawwe ek loslitten fan aparte netwurkkommunikaasjeprosessen en kommunikaasje fia SystemV, it oantal systeemoproppen signifikant fermindere en begon de prioriteiten fan operaasjes te kontrolearjen. Op it I / O-subsysteem allinich wie it mooglik om sa'n 8-17 mikrosekonden te bewarjen, ôfhinklik fan it senario. Dit single-threaded skema is sûnt dy tiid ûnferoare brûkt; ien epoll-thread mei in marzje is genôch om alle ferbiningen te tsjinjen.

Transaksje ferwurkjen

De tanimmende lading op ús systeem fereasket it opwurdearjen fan hast alle komponinten. Mar spitigernôch hat stagnaasje yn 'e groei fan prosessor-kloksnelheden yn' e lêste jierren it net mear mooglik makke om prosessen head-on te skaaljen. Dêrom hawwe wy besletten om it Engine-proses te ferdielen yn trije nivo's, wêrfan de drokste fan har it risikokontrôlesysteem is, dat de beskikberens fan fûnsen yn akkounts evaluearret en de transaksjes sels makket. Mar jild kin wêze yn ferskate faluta, en it wie nedich om út te finen op hokker basis de ferwurking fan fersiken moatte wurde ferdield.

De logyske oplossing is om it te dielen troch muntienheid: ien tsjinner hannelet yn dollars, in oare yn pûn, en in tredde yn euro. Mar as, mei sa'n skema, twa transaksjes wurde stjoerd om ferskate faluta te keapjen, dan sil it probleem fan desyngronisaasje fan wallet ûntstean. Mar syngronisaasje is dreech en djoer. Dêrom soe it korrekt wêze om apart troch slúven en apart troch ynstruminten te knipjen. Trouwens, de measte westerske útwikselingen hawwe net de taak om risiko's sa akuut te kontrolearjen as wy dogge, dus meastentiids wurdt dit offline dien. Wy moasten online ferifikaasje ymplementearje.

Lit ús útlizze mei in foarbyld. In hanneler wol $ 30 keapje, en it fersyk giet nei transaksje-validaasje: wy kontrolearje oft dizze hanneler tastien is yn dizze hannelsmodus en oft hy de nedige rjochten hat. As alles yn oarder is, giet it fersyk nei it risikoferifikaasjesysteem, d.w.s. om de genôchheid fan fûnsen te kontrolearjen om in transaksje te sluten. D'r is in opmerking dat it fereaske bedrach op it stuit blokkearre is. It fersyk wurdt dan trochstjoerd nei it hannelssysteem, dat de transaksje goedkart of net goedkart. Litte wy sizze dat de transaksje is goedkard - dan markearret it risiko-ferifikaasjesysteem dat it jild blokkearre is, en de roebel wurde yn dollars feroare.

Yn 't algemien befettet it risikokontrôlesysteem komplekse algoritmen en fiert in grut oantal heul boarne-yntinsive berekkeningen, en kontrolearret net gewoan it "akkountsaldo", sa't it op it earste each liket.

Doe't wy it Engine-proses begûnen te ferdielen yn nivo's, tsjinkamen wy in probleem: de koade dy't op dat stuit beskikber wie brûkte aktyf deselde array fan gegevens yn 'e falidaasje- en ferifikaasjestadia, dy't nedich wie om de heule koadebasis opnij te skriuwen. As gefolch hawwe wy in technyk liend foar it ferwurkjen fan ynstruksjes fan moderne processors: elk fan har is ferdield yn lytse stadia en ferskate aksjes wurde parallel yn ien syklus útfierd.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Nei in lytse oanpassing fan 'e koade makken wy in pipeline foar parallelle transaksjeferwurking, wêryn de transaksje waard ferdield yn 4 stadia fan' e pipeline: netwurk ynteraksje, falidaasje, útfiering en publikaasje fan it resultaat

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Litte wy nei in foarbyld sjen. Wy hawwe twa ferwurkingssystemen, serial en parallel. De earste transaksje komt en wurdt stjoerd foar falidaasje yn beide systemen. De twadde transaksje komt daliks oan: yn in parallel systeem wurdt it fuortendaliks oan it wurk nommen, en yn in sekwinsjele systeem wurdt it yn in wachtrige set dy't wachtet op 'e earste transaksje om troch de hjoeddeistige ferwurkingsstadium te gean. Dat is, it wichtichste foardiel fan pipelineferwurking is dat wy de transaksjewachtrige rapper ferwurkje.

Dit is hoe't wy mei it ASTS + systeem kamen.

Wier is ek net alles sa glêd mei transportbanden. Litte wy sizze dat wy in transaksje hawwe dy't ynfloed hat op gegevensarrays yn in oanbuorjende transaksje; dit is in typyske situaasje foar in útwikseling. Sa'n transaksje kin net útfierd wurde yn in pipeline, om't it kin beynfloedzje oaren. Dizze situaasje wurdt gegevensgefaar neamd, en sokke transaksjes wurde gewoan apart ferwurke: as de "snelle" transaksjes yn 'e wachtrige rinne, stopet de pipeline, it systeem ferwurket de "stadige" transaksje, en dan begjint de pipeline wer. Gelokkich is it oanpart fan sokke transaksjes yn 'e totale stream tige lyts, sadat de pipeline sa komselden stopet dat it gjin ynfloed hat op' e totale prestaasjes.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Doe begûnen wy it probleem op te lossen fan syngronisaasje fan trije triedden fan útfiering. It resultaat wie in systeem basearre op in ring buffer mei fêste grutte sellen. Yn dit systeem is alles ûnderwurpen oan ferwurkingssnelheid; gegevens wurde net kopiearre.

  • Alle ynkommende netwurkpakketten geane yn it allocaasjestadium yn.
  • Wy pleatse se yn in array en markearje se as beskikber foar poadium #1.
  • De twadde transaksje is oankaam, it is wer beskikber foar poadium 1.
  • De earste ferwurkingstried sjocht de beskikbere transaksjes, ferwurket se en ferpleatst se nei de folgjende poadium fan 'e twadde ferwurkingsdraad.
  • It ferwurket dan de earste transaksje en markearret de oerienkommende sel deleted - it is no beskikber foar nij gebrûk.

De hiele wachtrige wurdt op dizze manier ferwurke.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Ferwurking fan elke poadium nimt ienheden as tsientallen mikrosekonden. En as wy standert OS-syngronisaasjeskema's brûke, dan sille wy mear tiid ferlieze op 'e syngronisaasje sels. Dat is wêrom wy begûn mei help fan spinlock. Dit is lykwols tige minne foarm yn in real-time systeem, en RedHat riedt strikt net oan om dit te dwaan, dus tapasse wy in spinlock foar 100 ms, en wikselje dan nei semafoarmodus om de mooglikheid fan in deadlock te eliminearjen.

As gefolch hawwe wy in prestaasje fan sawat 8 miljoen transaksjes per sekonde berikt. En letterlik twa moanne letter yn artikel oer LMAX Disruptor wy seagen in beskriuwing fan in circuit mei deselde funksjonaliteit.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

No kinne d'r ferskate triedden fan útfiering yn ien stadium wêze. Alle transaksjes waarden ien foar ien ferwurke, yn 'e folchoarder dy't se waarden ûntfongen. As gefolch, peak prestaasjes tanommen fan 18 tûzen nei 50 tûzen transaksjes per sekonde.

Exchange risiko behear systeem

D'r is gjin limyt foar perfeksje, en al gau binne wy ​​​​wer begûn mei modernisearring: yn it ramt fan ASTS + begonen wy systemen foar risikobehear en delsettingsoperaasjes yn autonome komponinten te ferpleatsen. Wy ûntwikkele in fleksibele moderne arsjitektuer en in nij hiërargysk risiko model, en besocht te brûken de klasse wêr mooglik fixed_point вместо double.

Mar der ûntstie fuortendaliks in probleem: hoe kinne jo alle saaklike logika dy't in protte jierren wurket, syngronisearje en it oerjaan nei it nije systeem? Dêrtroch moast de earste ferzje fan it prototype fan it nije systeem ferlitten wurde. De twadde ferzje, dy't op it stuit wurket yn produksje, is basearre op deselde koade, dy't wurket yn sawol de hannel en risiko dielen. Tidens ûntwikkeling wie it dreechste ding om te dwaan git gearfoegje tusken twa ferzjes. Us kollega Evgeniy Mazurenok hat dizze operaasje elke wike útfierd en elke kear flokte hy in heule tiid.

By it selektearjen fan in nij systeem moasten wy fuortendaliks it probleem fan ynteraksje oplosse. By it kiezen fan in gegevensbus wie it nedich om stabile jitter en minimale latency te garandearjen. It InfiniBand RDMA-netwurk wie hjir it bêste geskikt foar: de gemiddelde ferwurkingstiid is 4 kear minder as yn 10 G Ethernet-netwurken. Mar wat ús echt boeide wie it ferskil yn persintaazjes - 99 en 99,9.

Fansels hat InfiniBand syn útdagings. As earste, in oare API - ibverbs ynstee fan sockets. Twads binne d'r hast gjin breed beskikbere oplossingen foar iepen boarne messaging. Wy besochten ús eigen prototype te meitsjen, mar it die bliken heul lestich te wêzen, dus wy keas in kommersjele oplossing - Confinity Low Latency Messaging (earder IBM MQ LLM).

Doe ûntstie de taak om it risikosysteem goed te ferdielen. As jo ​​​​de Risk Engine gewoan fuortsmite en gjin tuskenknooppunt meitsje, dan kinne transaksjes fan twa boarnen wurde mingd.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

De saneamde Ultra Low Latency-oplossingen hawwe in weryndielingsmodus: transaksjes út twa boarnen kinne wurde regele yn 'e fereaske folchoarder by ûntfangst; dit wurdt útfierd mei in apart kanaal foar it útwikseljen fan ynformaasje oer de oarder. Mar wy brûke dizze modus noch net: it komplisearret it heule proses, en yn in oantal oplossingen wurdt it hielendal net stipe. Derneist soe elke transaksje oerienkommende tiidstempels moatte wurde tawiisd, en yn ús skema is dit meganisme heul lestich om korrekt út te fieren. Dêrom hawwe wy it klassike skema brûkt mei in berjochtmakelaar, dat is, mei in dispatcher dy't berjochten ferspriedt tusken de Risk Engine.

It twadde probleem wie relatearre oan kliïnt tagong: as d'r ferskate Risk Gateways binne, moat de kliïnt ferbine mei elk fan har, en dit sil feroaringen nedich hawwe oan 'e kliïntlaach. Wy woenen dit op dit poadium fuortkomme, sadat it hjoeddeistige Risk Gateway-ûntwerp de heule gegevensstream ferwurket. Dit beheint de maksimale trochfier sterk, mar makket systeemyntegraasje sterk simplifies.

Duplikaasje

Us systeem moat gjin inkeld punt fan mislearring hawwe, dat is, alle komponinten moatte duplikearre wurde, ynklusyf de berjochtmakelaar. Wy hawwe dit probleem oplost mei it CLLM-systeem: it befettet in RCMS-kluster wêryn twa dispatchers kinne wurkje yn master-slave-modus, en as ien mislearret, skeakelt it systeem automatysk oer nei de oare.

Wurkje mei in reservekopy data sintrum

InfiniBand is optimalisearre foar operaasje as in lokaal netwurk, dat is foar it ferbinen fan rack-mount-apparatuer, en in InfiniBand-netwurk kin net lein wurde tusken twa geografysk ferspraat datasintra. Dêrom, wy útfierd in brêge / dispatcher, dy't oanslút op it berjocht opslach fia reguliere Ethernet netwurken en relays alle transaksjes nei in twadde IB netwurk. As wy moatte migrearje fan in datasintrum, kinne wy ​​kieze hokker datasintrum wy no moatte wurkje.

Resultaten

Al it boppesteande waard net tagelyk dien; it duorre ferskate iteraasjes fan it ûntwikkeljen fan in nije arsjitektuer. Wy makken it prototype yn in moanne, mar it duorre mear as twa jier om it yn wurking te krijen. Wy besochten it bêste kompromis te berikken tusken tanimmende transaksjeferwurkingstiid en tanimmende systeembetrouberens.

Sûnt it systeem wie swier bywurke, wy ymplementearre gegevens herstel út twa ûnôfhinklike boarnen. As de berjochtwinkel om ien of oare reden net goed wurket, kinne jo it transaksjelogboek fan in twadde boarne nimme - fan 'e Risk Engine. Dit prinsipe wurdt waarnommen yn it hiele systeem.

Under oare dingen, wy wienen by steat om te behâlden de client API sadat noch makelders noch immen oars soe easkje wichtige rework foar de nije arsjitektuer. Wy moasten wat ynterfaces feroarje, mar d'r wie gjin need nedich om wichtige feroaringen te meitsjen oan it bestjoeringsmodel.

Wy neamden de hjoeddeistige ferzje fan ús platfoarm Rebus - as in ôfkoarting foar de twa meast opfallende ynnovaasjes yn 'e arsjitektuer, Risk Engine en BUS.

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Yn earste ynstânsje woenen wy allinich it clearingdiel tawize, mar it resultaat wie in enoarm ferspraat systeem. Klanten kinne no ynteraksje mei de Trade Gateway, de Clearing Gateway, of beide.

Wat wy úteinlik berikten:

De evolúsje fan 'e arsjitektuer fan it hannels- en ferwideringssysteem fan' e Moskouse Exchange. Diel 2

Fermindere de latency nivo. Mei in lyts folume fan transaksjes wurket it systeem itselde as de foarige ferzje, mar kin tagelyk in folle hegere lading ferneare.

Peak prestaasjes tanommen fan 50 tûzen nei 180 tûzen transaksjes per sekonde. In fierdere ferheging wurdt hindere troch de ienige stream fan oerienkommende bestelling.

D'r binne twa manieren foar fierdere ferbettering: parallelisearjen fan matching en feroarjen fan 'e manier wêrop it wurket mei Gateway. No wurkje alle Gateways neffens in replikaasjeskema, dy't ûnder sa'n lading ophâldt normaal te funksjonearjen.

Uteinlik kin ik wat advys jaan oan dyjingen dy't bedriuwssystemen finalisearje:

  • Wês altyd taret op it slimste. Problemen ûntsteane altyd ûnferwachts.
  • It is normaal ûnmooglik om arsjitektuer fluch opnij te meitsjen. Benammen as jo maksimale betrouberens moatte berikke oer meardere yndikatoaren. Hoe mear knopen, hoe mear boarnen nedich binne foar stipe.
  • Alle oanpaste en proprietêre oplossingen sille ekstra boarnen fereaskje foar ûndersyk, stipe en ûnderhâld.
  • Stel it oplossen fan problemen fan systeembetrouberens en herstel nei mislearrings net út; nim se yn 'e earste ûntwerpstadium yn rekken.

Boarne: www.habr.com

Add a comment