Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

Hej alla! Jag heter Sergey Kostanbaev, på börsen utvecklar jag kärnan i handelssystemet.

När Hollywood-filmer visar New York-börsen ser det alltid ut så här: folkmassor, alla skriker något, viftar med papper, totalt kaos uppstår. Detta har aldrig hänt här på Moskvabörsen, eftersom handeln har bedrivits elektroniskt från allra första början och är baserad på två huvudplattformar – Spectra (valutamarknaden) och ASTS (valuta-, aktie- och penningmarknaden). Och idag vill jag prata om utvecklingen av arkitekturen för ASTS-handels- och clearingsystemet, om olika lösningar och fynd. Historien kommer att bli lång, så jag var tvungen att dela upp den i två delar.

Vi är en av få börser i världen som handlar med tillgångar av alla klasser och tillhandahåller ett komplett utbud av börstjänster. Till exempel, förra året rankades vi tvåa i världen när det gäller volym för obligationshandel, 25:e plats bland alla börser, 13:e plats i kapitalisering bland offentliga börser.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

För professionella handelsdeltagare är sådana parametrar som svarstid, stabilitet i tidsfördelning (jitter) och tillförlitlighet för hela komplexet avgörande. Vi behandlar för närvarande tiotals miljoner transaktioner per dag. Bearbetningen av varje transaktion av systemkärnan tar tiotals mikrosekunder. Visst har mobiloperatörer på nyårsafton eller sökmotorer själva en högre arbetsbelastning än vår, men vad gäller arbetsbelastning, i kombination med ovan nämnda egenskaper, är det få som kan mäta sig med oss, tycks det mig. Samtidigt är det viktigt för oss att systemet inte saktar ner en sekund, fungerar absolut stabilt och att alla användare är jämställda.

Lite historia

1994 lanserades det australiensiska ASTS-systemet på Moscow Interbank Currency Exchange (MICEX), och från det ögonblicket kan den ryska historien om elektronisk handel räknas. 1998 moderniserades börsarkitekturen för att introducera internethandel. Sedan dess har implementeringshastigheten för nya lösningar och arkitektoniska förändringar i alla system och delsystem bara tagit fart.

Under dessa år fungerade utbytessystemet på avancerad hårdvara - ultratillförlitliga HP Superdome 9000-servrar (byggda på PA-RISC), där absolut allt duplicerades: in-/utgångsundersystem, nätverk, RAM (det fanns faktiskt en RAID-array av RAM), processorer (hot-swappable). Det var möjligt att ändra vilken serverkomponent som helst utan att stoppa maskinen. Vi litade på dessa enheter och ansåg att de var praktiskt taget felsäkra. Operativsystemet var ett Unix-liknande HP UX-system.

Men sedan omkring 2010 har det uppstått ett fenomen som kallas högfrekvenshandel (HFT), eller högfrekvenshandel – enkelt uttryckt, börsrobotar. På bara 2,5 år har belastningen på våra servrar ökat 140 gånger.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

Det var omöjligt att stå emot en sådan belastning med den gamla arkitekturen och utrustningen. Det var nödvändigt att på något sätt anpassa sig.

börjar

Förfrågningar till utbytessystemet kan delas in i två typer:

  • Transaktioner. Om du vill köpa dollar, aktier eller något annat skickar du en transaktion till handelssystemet och får svar om framgång.
  • Informationsförfrågningar. Om du vill ta reda på det aktuella priset, se orderboken eller indexen och skicka sedan informationsförfrågningar.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

Schematiskt kan kärnan i systemet delas in i tre nivåer:

  • Kundnivån, på vilken mäklare och kunder arbetar. De interagerar alla med åtkomstservrar.
  • Gatewayservrar är cachningsservrar som lokalt behandlar alla informationsförfrågningar. Vill du veta vilket pris Sberbanks aktier för närvarande handlas till? Begäran går till åtkomstservern.
  • Men om du vill köpa aktier går förfrågan till den centrala servern (Trade Engine). Det finns en sådan server för varje typ av marknad, de spelar en viktig roll, det är för dem som vi skapade det här systemet.

Kärnan i handelssystemet är en smart minnesdatabas där alla transaktioner är utbytestransaktioner. Basen skrevs i C, de enda externa beroenden var libc-biblioteket och det fanns ingen dynamisk minnesallokering alls. För att minska bearbetningstiden börjar systemet med en statisk uppsättning arrayer och med statisk dataflyttning: först laddas all data för den aktuella dagen in i minnet, och ingen ytterligare diskåtkomst utförs, allt arbete utförs endast i minnet. När systemet startar är all referensdata redan sorterad, så sökningen fungerar mycket effektivt och tar kort tid under körning. Alla tabeller är gjorda med påträngande listor och träd för dynamiska datastrukturer så att de inte kräver minnesallokering vid körning.

Låt oss kort gå igenom historien om utvecklingen av vårt handels- och clearingsystem.
Den första versionen av handels- och clearingsystemarkitekturen byggdes på den så kallade Unix-interaktionen: delat minne, semaforer och köer användes och varje process bestod av en enda tråd. Detta tillvägagångssätt var utbrett i början av 1990-talet.

Den första versionen av systemet innehöll två nivåer av Gateway och en central server för handelssystemet. Arbetsflödet var så här:

  • Klienten skickar en begäran som når Gatewayen. Den kontrollerar formatets giltighet (men inte själva data) och avvisar felaktiga transaktioner.
  • Om en informationsbegäran har skickats, utförs den lokalt; om vi pratar om en transaktion omdirigeras den till den centrala servern.
  • Handelsmotorn bearbetar sedan transaktionen, modifierar lokalt minne och skickar ett svar på transaktionen och själva transaktionen för replikering med hjälp av en separat replikeringsmotor.
  • Gatewayen tar emot svaret från den centrala noden och vidarebefordrar det till klienten.
  • Efter en tid tar Gatewayen emot transaktionen genom replikeringsmekanismen, och den här gången exekverar den lokalt och ändrar dess datastrukturer så att nästa informationsförfrågningar visar den senaste informationen.

Faktum är att den beskriver en replikeringsmodell där Gateway fullständigt replikerade de åtgärder som utfördes i handelssystemet. En separat replikeringskanal säkerställde att transaktioner utfördes i samma ordning över flera åtkomstnoder.

Eftersom koden var entrådig användes ett klassiskt schema med processgafflar för att betjäna många kunder. Det var dock väldigt dyrt att dela hela databasen, så lätta tjänsteprocesser användes som samlade in paket från TCP-sessioner och överförde dem till en kö (SystemV Message Queue). Gateway och Trade Engine fungerade bara med denna kö och tog transaktioner därifrån för exekvering. Det gick inte längre att skicka ett svar på det, eftersom det inte var klart vilken serviceprocess som skulle läsa den. Så vi tog till ett knep: varje splittrad process skapade en svarskö för sig själv, och när en förfrågan kom in i den inkommande kön lades en tagg för svarskön omedelbart till den.

Att ständigt kopiera stora mängder data från kö till kö skapade problem, särskilt typiska för informationsförfrågningar. Därför använde vi ett annat knep: förutom svarskön skapade varje process också delat minne (SystemV Shared Memory). Själva paketen placerades i den, och endast en tagg lagrades i kön, så att man kunde hitta originalpaketet. Detta hjälpte till att lagra data i processorns cache.

SystemV IPC innehåller verktyg för att visa tillståndet för kö-, minnes- och semaforobjekt. Vi använde detta aktivt för att förstå vad som hände i systemet vid ett visst tillfälle, var paket samlades, vad som blockerades etc.

Första uppgraderingarna

Först och främst blev vi av med enprocess Gateway. Dess betydande nackdel var att den kunde hantera antingen en replikeringstransaktion eller en informationsbegäran från en klient. Och när belastningen ökar kommer Gateway att ta längre tid att behandla förfrågningar och kommer inte att kunna bearbeta replikeringsflödet. Dessutom, om kunden skickade en transaktion, behöver du bara kontrollera dess giltighet och vidarebefordra den. Därför ersatte vi den enda Gateway-processen med flera komponenter som kan köras parallellt: flertrådad information och transaktionsprocesser som körs oberoende av varandra på ett delat minnesområde med hjälp av RW-låsning. Och samtidigt introducerade vi leverans- och replikeringsprocesser.

Effekten av högfrekvent handel

Ovanstående version av arkitekturen existerade fram till 2010. Samtidigt var vi inte längre nöjda med prestanda för HP Superdome-servrar. Dessutom var PA-RISC-arkitekturen praktiskt taget död; leverantören erbjöd inga betydande uppdateringar. Som ett resultat började vi gå från HP UX/PA RISC till Linux/x86. Övergången började med anpassningen av åtkomstservrar.

Varför var vi tvungna att ändra arkitekturen igen? Faktum är att högfrekvent handel har väsentligt förändrat belastningsprofilen på systemkärnan.

Låt oss säga att vi har en liten transaktion som orsakade en betydande prisförändring - någon köpte en halv miljard dollar. Efter ett par millisekunder märker alla marknadsaktörer detta och börjar göra en korrigering. Naturligtvis hamnar förfrågningar i en enorm kö, som systemet kommer att ta lång tid att rensa.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

Med detta 50 ms-intervall är medelhastigheten cirka 16 tusen transaktioner per sekund. Om vi ​​minskar fönstret till 20 ms får vi en genomsnittlig hastighet på 90 tusen transaktioner per sekund, med 200 tusen transaktioner på topp. Med andra ord är belastningen inte konstant, med plötsliga skurar. Och kön av förfrågningar ska alltid behandlas snabbt.

Men varför är det kö överhuvudtaget? Så i vårt exempel märkte många användare prisändringen och skickade transaktioner därefter. De kommer till Gateway, den serialiserar dem, sätter en viss ordning och skickar dem till nätverket. Routrar blandar paketen och vidarebefordrar dem. Vems paket kom först, den transaktionen "vann". Som ett resultat började utbytesklienter märka att om samma transaktion skickades från flera gateways, så ökade chanserna för snabb bearbetning. Snart började utbytesrobotar bombardera Gateway med förfrågningar, och en lavin av transaktioner uppstod.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

En ny omgång av evolution

Efter omfattande tester och efterforskningar bytte vi till realtidsoperativsystemkärnan. För detta valde vi RedHat Enterprise MRG Linux, där MRG står för messaging realtime grid. Fördelen med realtidspatchar är att de optimerar systemet för snabbast möjliga exekvering: alla processer är uppradade i en FIFO-kö, kärnor kan isoleras, inga utkast, alla transaktioner bearbetas i strikt sekvens.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1
Röd - arbetar med en kö i en vanlig kärna, grön - arbetar i en realtidskärna.

Men att uppnå låg latens på vanliga servrar är inte så lätt:

  • SMI-läget, som i x86-arkitekturen är grunden för att arbeta med viktig kringutrustning, stör kraftigt. Bearbetning av alla typer av hårdvaruhändelser och hantering av komponenter och enheter utförs av den fasta programvaran i det så kallade transparenta SMI-läget, där operativsystemet inte alls ser vad den fasta programvaran gör. Som regel erbjuder alla större leverantörer speciella tillägg för firmware-servrar som gör det möjligt att minska mängden SMI-bearbetning.
  • Det ska inte finnas någon dynamisk styrning av processorfrekvensen, detta leder till ytterligare stillestånd.
  • När filsystemloggen töms, inträffar vissa processer i kärnan som orsakar oförutsägbara förseningar.
  • Du måste vara uppmärksam på saker som CPU-affinitet, Interrupt-affinitet, NUMA.

Jag måste säga att ämnet att ställa in Linux-hårdvara och kärna för realtidsbearbetning förtjänar en separat artikel. Vi ägnade mycket tid åt att experimentera och forska innan vi nådde ett bra resultat.

När vi flyttade från PA-RISC-servrar till x86 behövde vi praktiskt taget inte ändra systemkoden mycket, vi bara anpassade och konfigurerade om den. Samtidigt fixade vi flera buggar. Till exempel kom konsekvenserna av det faktum att PA RISC var ett Big endian-system och x86 var ett Little endian-system snabbt upp: data lästes till exempel felaktigt. Det svårare felet var att PA RISC använder konsekvent konsekvent (Sekvensiellt konsekvent) minnesåtkomst, medan x86 kan ordna om läsoperationer, så kod som var absolut giltig på en plattform blev trasig på en annan.

Efter byte till x86 ökade prestandan nästan tre gånger, den genomsnittliga transaktionsbehandlingstiden minskade till 60 μs.

Låt oss nu titta närmare på vilka viktiga förändringar som har gjorts i systemarkitekturen.

Hett reservepos

När vi bytte till råvaruservrar var vi medvetna om att de var mindre tillförlitliga. Därför, när vi skapade en ny arkitektur, antog vi a priori möjligheten av fel på en eller flera noder. Därför behövdes ett hot standby-system som mycket snabbt kunde byta till reservmaskiner.

Dessutom fanns det andra krav:

  • Under inga omständigheter får du förlora bearbetade transaktioner.
  • Systemet måste vara helt transparent för vår infrastruktur.
  • Klienter ska inte se avbrutna anslutningar.
  • Reservationer bör inte medföra betydande förseningar eftersom detta är en kritisk faktor för utbytet.

När vi skapade ett hot standby-system övervägde vi inte sådana scenarier som dubbla fel (till exempel slutade nätverket på en server att fungera och huvudservern frös); övervägde inte möjligheten av fel i programvaran eftersom de identifieras under testning; och tog inte hänsyn till den felaktiga driften av hårdvaran.

Som ett resultat kom vi till följande schema:

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

  • Huvudservern interagerade direkt med Gateway-servrarna.
  • Alla transaktioner som togs emot på huvudservern replikerades omedelbart till backupservern via en separat kanal. Skiljemannen (guvernören) samordnade bytet om några problem uppstod.

    Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

  • Huvudservern behandlade varje transaktion och väntade på bekräftelse från backupservern. För att hålla latensen till ett minimum undvek vi att vänta på att transaktionen skulle slutföras på backupservern. Eftersom tiden det tog för en transaktion att färdas över nätverket var jämförbar med exekveringstiden, lades ingen ytterligare latens till.
  • Vi kunde bara kontrollera bearbetningsstatusen för huvud- och reservservrarna för den föregående transaktionen, och bearbetningsstatusen för den aktuella transaktionen var okänd. Eftersom vi fortfarande använde entrådade processer, skulle vänta på svar från Backup ha saktat ner hela bearbetningsflödet, så vi gjorde en rimlig kompromiss: vi kontrollerade resultatet av den föregående transaktionen.

Utveckling av arkitekturen för handels- och clearingsystemet för Moskvabörsen. Del 1

Schemat fungerade enligt följande.

Låt oss säga att huvudservern slutar svara, men Gateways fortsätter att kommunicera. En timeout inträffar på backupservern, den kontaktar guvernören, som tilldelar den rollen som huvudserver, och alla Gateways byter till den nya huvudservern.

Om huvudservern kommer tillbaka online utlöser den också en intern timeout, eftersom det inte har varit några anrop till servern från Gatewayen under en viss tid. Sedan vänder han sig också till guvernören, och han utesluter honom från schemat. Som ett resultat fungerar utbytet med en server till slutet av handelsperioden. Eftersom sannolikheten för ett serverfel är ganska låg ansågs detta schema vara ganska acceptabelt, det innehöll ingen komplex logik och var lätt att testa.

Att fortsätta

Källa: will.com

Lägg en kommentar