Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Ова е продолжение на долгата приказна за нашиот трнлив пат кон создавање моќен систем со големо оптоварување кој обезбедува работа на Берзата. Првиот дел е тука: habr.com/ru/post/444300

Мистериозна грешка

По многубројните тестови, ажурираниот систем за тргување и расчистување беше пуштен во употреба, при што наидовме на бубачка за која можевме да напишеме детективско-мистична приказна.

Набргу по стартувањето на главниот сервер, една од трансакциите беше обработена со грешка. Сепак, сè беше во ред на резервниот сервер. Се покажа дека едноставна математичка операција на пресметување на експонентот на главниот сервер даде негативен резултат од вистинскиот аргумент! Го продолживме нашето истражување и во регистарот SSE2 најдовме разлика во еден бит, кој е одговорен за заокружување при работа со броеви со подвижна запирка.

Напишавме едноставна алатка за тестирање за да го пресметаме експонентот со множеството на битови за заокружување. Се испостави дека во верзијата на RedHat Linux што ја користевме, имаше грешка во работата со математичката функција кога беше вметнат несреќниот бит. Го пријавивме ова на RedHat, по некое време добивме лепенка од нив и го испуштивме. Грешката повеќе не се појави, но не беше јасно од каде воопшто дојде овој бит? Функцијата беше одговорна за тоа fesetround од јазикот C. Внимателно го анализиравме нашиот код во потрага по наводната грешка: ги проверивме сите можни ситуации; ги разгледа сите функции кои користеа заокружување; се обиде да репродуцира неуспешна сесија; користеле различни компајлери со различни опции; Користена е статичка и динамичка анализа.

Причината за грешката не може да се најде.

Потоа почнаа да го проверуваат хардверот: извршија тестирање на оптоварувањето на процесорите; ја проверив RAM меморијата; Спроведовме дури и тестови за многу неверојатно сценарио за грешка со повеќе битови во една ќелија. Залудно.

На крајот, се решивме на една теорија од светот на високо-енергетската физика: некоја високо-енергетска честичка полета во нашиот центар за податоци, го прободе ѕидот на куќиштето, удри во процесорот и предизвика бравата на чкрапалото да се залепи во тој дел. Оваа апсурдна теорија беше наречена „неутрино“. Ако сте далеку од физика на честички: неутрината речиси и не комуницираат со надворешниот свет и секако не се во можност да влијаат на работата на процесорот.

Бидејќи не беше можно да се најде причината за неуспехот, серверот „навредлив“ беше отстранет од работа за секој случај.

По некое време, почнавме да го подобруваме системот за топла резервна копија: воведовме таканаречени „топли резерви“ (топло) - асинхрони реплики. Тие добија проток на трансакции кои можеа да се лоцираат во различни центри за податоци, но топлите не беа активно во интеракција со други сервери.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Зошто е направено ова? Ако резервниот сервер не успее, тогаш топлото врзано за главниот сервер станува нова резервна копија. Односно, по дефект, системот не останува со еден главен сервер до крајот на трговската сесија.

И кога новата верзија на системот беше тестирана и ставена во функција, повторно се појави грешка со битот за заокружување. Згора на тоа, со зголемувањето на бројот на топли сервери, грешката почна да се појавува почесто. Во исто време, продавачот немал што да покаже, бидејќи немало конкретни докази.

При следната анализа на ситуацијата, се појави теорија дека проблемот може да биде поврзан со ОС. Напишавме едноставна програма која повикува функција во бескрајна јамка fesetround, се сеќава на моменталната состојба и ја проверува преку спиење, а тоа се прави во многу конкурентни нишки. Откако ги избравме параметрите за спиење и бројот на нишки, почнавме постојано да го репродуцираме дефектот на битот по околу 5 минути од извршувањето на алатката. Сепак, поддршката на Red Hat не можеше да ја репродуцира. Тестирањето на нашите други сервери покажа дека само оние со одредени процесори се подложни на грешка. Во исто време, префрлањето на ново јадро го реши проблемот. На крајот, едноставно го заменивме оперативниот систем, а вистинската причина за грешката остана нејасна.

И одеднаш минатата година беше објавена статија на Хабре “Како најдов грешка во процесорите Intel Skylake" Ситуацијата опишана во него беше многу слична на нашата, но авторот ја одведе истрагата понатаму и изнесе теорија дека грешката била во микрокодот. И кога кернелите на Линукс се ажурираат, производителите го ажурираат и микрокодот.

Понатамошен развој на системот

Иако се ослободивме од грешката, оваа приказна не принуди да ја преиспитаме архитектурата на системот. На крајот на краиштата, не бевме заштитени од повторување на такви грешки.

Следниве принципи ја формираа основата за следните подобрувања на системот за резервации:

  • Не можете да верувате никому. Серверите може да не функционираат правилно.
  • Мнозинска резервација.
  • Обезбедување консензус. Како логичен додаток на мнозинската резервација.
  • Можни се двојни неуспеси.
  • Виталност. Новата жешка шема на подготвеност не треба да биде полоша од претходната. Тргувањето треба да продолжи непречено до последниот сервер.
  • Мало зголемување на латентноста. Секое време на застој повлекува огромни финансиски загуби.
  • Минимална мрежна интеракција за да се задржи латентноста што е можно пониска.
  • Избор на нов главен сервер за неколку секунди.

Ниту едно од решенијата достапни на пазарот не ни одговараше, а протоколот Raft сè уште беше во почетна фаза, па создадовме сопствено решение.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Вмрежување

Покрај системот за резервации, почнавме да ја модернизираме мрежната интеракција. Подсистемот В/И се состоеше од многу процеси, кои имаа најлошо влијание врз нервозата и латентноста. Со стотици процеси кои се справуваат со TCP конекции, бевме принудени постојано да се префрламе помеѓу нив, а на скала од микросекунда ова е прилично време одземена операција. Но, најлошиот дел е што кога еден процес доби пакет за обработка, го испраќаше до една редица SystemV и потоа чекаше настан од друга редица SystemV. Меѓутоа, кога има голем број на јазли, пристигнувањето на нов TCP пакет во еден процес и приемот на податоци во редот во друг претставуваат два натпреварувачки настани за оперативниот систем. Во овој случај, ако нема достапни физички процесори за двете задачи, едната ќе биде обработена, а втората ќе биде ставена во редот на чекање. Невозможно е да се предвидат последиците.

Во такви ситуации, може да се користи динамична контрола на приоритетите на процесот, но за тоа ќе биде потребна употреба на системски повици со интензивни ресурси. Како резултат на тоа, се префрливме на една нишка користејќи класичен епол, што значително ја зголеми брзината и го намали времето за обработка на трансакциите. Се ослободивме и од засебните мрежни комуникациски процеси и комуникација преку SystemV, значително го намаливме бројот на системски повици и почнавме да ги контролираме приоритетите на операциите. Само на потсистемот В/И, беше можно да се заштедат околу 8-17 микросекунди, во зависност од сценариото. Оваа шема со една нишка се користи непроменета оттогаш; една епол нишка со маргина е доволна за сервисирање на сите врски.

Обработка на трансакции

Растечкото оптоварување на нашиот систем бараше надградба на речиси сите негови компоненти. Но, за жал, стагнацијата во растот на брзините на часовникот на процесорот во последниве години веќе не овозможи директно да се зголемуваат процесите. Затоа, решивме да го поделиме процесот на Engine на три нивоа, а најзафатен од нив е системот за проверка на ризик, кој ја проценува достапноста на средствата на сметките и ги креира самите трансакции. Но, парите можат да бидат во различни валути, и беше неопходно да се открие врз основа на која треба да се подели обработката на барањата.

Логичното решение е да се подели по валута: еден сервер тргува во долари, друг во фунти, а трет во евра. Но, ако, со таква шема, две трансакции се испратат за купување различни валути, тогаш ќе се појави проблемот со десинхронизација на паричникот. Но, синхронизацијата е тешка и скапа. Затоа, би било точно да се дели одделно по паричници и одделно по инструменти. Патем, повеќето западни берзи немаат задача да ги проверуваат ризиците толку акутно како ние, па најчесто тоа се прави офлајн. Требаше да спроведеме онлајн верификација.

Да објасниме со пример. Трговецот сака да купи 30 долари, а барањето оди на валидација на трансакцијата: проверуваме дали на овој трговец му е дозволено да го користи овој режим на тргување и дали ги има потребните права. Ако се е во ред, барањето оди во системот за верификација на ризик, т.е. да се провери доволноста на средства за склучување трансакција. Има забелешка дека потребната сума е моментално блокирана. Барањето потоа се проследува до системот за тргување, кој ја одобрува или не ја одобрува трансакцијата. Да речеме дека трансакцијата е одобрена - тогаш системот за проверка на ризикот означува дека парите се деблокирани, а рубљите се претвораат во долари.

Општо земено, системот за проверка на ризикот содржи сложени алгоритми и врши голем број пресметки кои бараат многу ресурси и не го проверува едноставно „билансот на сметката“, како што може да изгледа на прв поглед.

Кога почнавме да го делиме процесот на Engine на нивоа, наидовме на проблем: кодот што беше достапен во тоа време активно ја користеше истата низа на податоци во фазите на валидација и верификација, што бараше препишување на целата база на кодови. Како резултат на тоа, позајмивме техника за обработка на инструкции од современите процесори: секој од нив е поделен на мали фази и неколку дејства се изведуваат паралелно во еден циклус.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

По мала адаптација на кодот, создадовме цевковод за паралелна обработка на трансакции, во кој трансакцијата беше поделена во 4 фази на гасоводот: мрежна интеракција, валидација, извршување и објавување на резултатот

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Ајде да погледнеме на пример. Имаме два системи за обработка, сериски и паралелни. Првата трансакција пристигнува и се испраќа на валидација во двата системи. Втората трансакција веднаш пристигнува: во паралелен систем таа веднаш се носи на работа, а во секвенцијален систем се става во редица чекајќи првата трансакција да помине низ тековната фаза на обработка. Односно, главната предност на обработката на гасоводот е што побрзо ја обработуваме редицата за трансакции.

Вака дојдовме до системот ASTS+.

Точно, не е сè така мазно ниту со транспортерите. Да речеме дека имаме трансакција што влијае на низите на податоци во соседна трансакција; ова е типична ситуација за размена. Таква трансакција не може да се изврши во нафтоводот бидејќи може да влијае на другите. Оваа ситуација се нарекува опасност од податоци, а таквите трансакции едноставно се обработуваат одделно: кога ќе истечат „брзите“ трансакции во редот, гасоводот запира, системот ја обработува „бавната“ трансакција и потоа повторно го стартува гасоводот. За среќа, процентот на такви трансакции во целокупниот проток е многу мал, така што гасоводот запира толку ретко што не влијае на севкупните перформанси.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Потоа почнавме да го решаваме проблемот со синхронизирање на три нишки на извршување. Резултатот беше систем заснован на прстенест тампон со ќелии со фиксна големина. Во овој систем, сè е предмет на брзина на обработка; податоците не се копираат.

  • Сите дојдовни мрежни пакети влегуваат во фазата на распределба.
  • Ги ставаме во низа и ги означуваме како достапни за фазата #1.
  • Пристигна втората трансакција, повторно е достапна за етапа бр.1.
  • Првата нишка за обработка ги гледа достапните трансакции, ги обработува и ги преместува во следната фаза од втората нишка за обработка.
  • Потоа ја обработува првата трансакција и ја означува соодветната ќелија deleted — сега е достапен за нова употреба.

Целата редица се обработува на овој начин.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Обработката на секоја фаза трае единици или десетици микросекунди. И ако користиме стандардни шеми за синхронизација на ОС, тогаш ќе изгубиме повеќе време на самата синхронизација. Затоа почнавме да користиме spinlock. Сепак, ова е многу лоша форма во систем во реално време, и RedHat строго не препорачува да го правите тоа, затоа применуваме заклучување за 100 ms, а потоа се префрламе на режим на семафор за да ја елиминираме можноста за ќор-сокак.

Како резултат на тоа, постигнавме перформанси од околу 8 милиони трансакции во секунда. И буквално два месеци подоцна во Член за LMAX Disruptor видовме опис на коло со истата функционалност.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Сега може да има неколку нишки на извршување во една фаза. Сите трансакции беа обработени една по една, по редоследот по кој беа примени. Како резултат на тоа, врвните перформанси се зголемија од 18 илјади на 50 илјади трансакции во секунда.

Систем за управување со девизниот ризик

Нема ограничување до совршенството, а наскоро повторно започнавме со модернизирање: во рамките на ASTS+, почнавме да ги преместуваме системите за управување со ризик и операции за порамнување во автономни компоненти. Развивме флексибилна модерна архитектура и нов модел на хиерархиски ризик и се обидовме да ја користиме класата секогаш кога е можно fixed_point наместо double.

Но, веднаш се појави проблем: како да се синхронизира целата деловна логика што функционира долги години и да се пренесе во новиот систем? Како резултат на тоа, првата верзија на прототипот на новиот систем мораше да биде напуштена. Втората верзија, која моментално работи во производство, се заснова на истиот код, кој работи и во трговскиот и во ризичниот дел. За време на развојот, најтешкото нешто што требаше да се направи беше git merge помеѓу две верзии. Нашиот колега Евгениј Мазуренок ја правеше оваа операција секоја недела и секој пат пцуеше многу долго.

При изборот на нов систем, веднаш моравме да го решиме проблемот со интеракцијата. При изборот на магистрала за податоци, неопходно беше да се обезбеди стабилен треперење и минимална латентност. Мрежата InfiniBand RDMA беше најдобро прилагодена за ова: просечното време на обработка е 4 пати помало отколку во 10 G Ethernet мрежите. Но, она што навистина не плени беше разликата во проценти - 99 и 99,9.

Се разбира, InfiniBand има свои предизвици. Прво, различен API - ибглаголи наместо сокети. Второ, речиси и да нема широко достапни решенија за пораки со отворен код. Се обидовме да направиме сопствен прототип, но се покажа дека е многу тешко, па избравме комерцијално решение - Confinity Low Latency Messaging (поранешен IBM MQ LLM).

Тогаш се појави задачата за правилна поделба на системот на ризик. Ако едноставно го отстраните Risk Engine и не создадете среден јазол, тогаш трансакциите од два извори може да се мешаат.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Таканаречените решенија за ултра ниска латентност имаат режим на пренаредување: трансакциите од два извора може да се организираат по бараниот редослед по приемот; тоа се спроведува со помош на посебен канал за размена на информации за нарачката. Но, ние сè уште не го користиме овој режим: тој го комплицира целиот процес, а во голем број решенија воопшто не е поддржан. Дополнително, на секоја трансакција би требало да и се доделат соодветни временски печати, а во нашата шема овој механизам е многу тешко да се спроведе правилно. Затоа, ја користевме класичната шема со брокер за пораки, односно со диспечер кој дистрибуира пораки помеѓу Risk Engine.

Вториот проблем беше поврзан со пристапот до клиентот: ако има неколку Risk Gateway, клиентот треба да се поврзе со секој од нив, а тоа ќе бара промени во слојот на клиентот. Сакавме да се извлечеме од ова во оваа фаза, така што сегашниот дизајн на Risk Gateway го обработува целиот поток на податоци. Ова во голема мера ја ограничува максималната пропусност, но во голема мера ја поедноставува системската интеграција.

Дуплирање

Нашиот систем не треба да има ниту една точка на неуспех, односно сите компоненти мора да се дуплираат, вклучувајќи го и брокерот за пораки. Овој проблем го решивме со помош на системот CLLM: содржи RCMS кластер во кој два диспечери можат да работат во режим на главен роб, а кога едниот не успее, системот автоматски се префрла на другиот.

Работа со резервен центар за податоци

InfiniBand е оптимизиран за работа како локална мрежа, односно за поврзување на опрема за монтирање на решетката, а мрежата InfiniBand не може да се постави помеѓу два географски распределени центри за податоци. Затоа, имплементиравме мост/диспечер, кој се поврзува со складиштето на пораки преку редовни етернет мрежи и ги пренесува сите трансакции на втора IB мрежа. Кога треба да мигрираме од центар за податоци, можеме да избереме со кој центар за податоци да работиме сега.

Резултатите од

Сето горенаведено не беше направено одеднаш; беа потребни неколку повторувања за развој на нова архитектура. Прототипот го создадовме за еден месец, но беа потребни повеќе од две години за да се доведе во работна состојба. Се обидовме да го постигнеме најдобриот компромис помеѓу зголемувањето на времето за обработка на трансакциите и зголемувањето на доверливоста на системот.

Бидејќи системот беше силно ажуриран, имплементиравме враќање на податоците од два независни извори. Ако продавницата за пораки не функционира правилно поради некоја причина, можете да го земете дневникот за трансакции од втор извор - од Risk Engine. Овој принцип се почитува низ целиот систем.

Меѓу другото, можевме да го зачуваме API-то на клиентот, така што ниту брокерите ниту некој друг нема да бара значителна преработка за новата архитектура. Моравме да промениме некои интерфејси, но немаше потреба да правиме значителни промени во оперативниот модел.

Тековната верзија на нашата платформа ја нарековме Rebus - како кратенка за двете најзабележливи иновации во архитектурата, Risk Engine и BUS.

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Првично сакавме да го доделиме само клириншкиот дел, но резултатот беше огромен дистрибуиран систем. Клиентите сега можат да комуницираат или со Trade Gateway, Clearing Gateway или со двете.

Што на крајот постигнавме:

Еволуција на архитектурата на системот за тргување и клириншка на Московската берза. Дел 2

Го намали нивото на латентност. Со мал обем на трансакции, системот работи исто како и претходната верзија, но во исто време може да издржи многу поголем товар.

Врвните перформанси се зголемија од 50 илјади на 180 илјади трансакции во секунда. Понатамошното зголемување е попречено од единствениот тек на усогласување на нарачките.

Постојат два начини за понатамошно подобрување: паралелизирање на совпаѓањето и менување на начинот на кој работи со Gateway. Сега сите Gateways работат според шема за репликација, која, под такво оптоварување, престанува да функционира нормално.

Конечно, можам да дадам неколку совети за оние кои ги финализираат претпријатијата системи:

  • Бидете подготвени за најлошото во секое време. Проблемите секогаш се појавуваат неочекувано.
  • Обично е невозможно брзо да се преправи архитектурата. Особено ако треба да постигнете максимална сигурност кај повеќе индикатори. Колку повеќе јазли, толку повеќе ресурси се потребни за поддршка.
  • Сите сопствени и сопственички решенија ќе бараат дополнителни ресурси за истражување, поддршка и одржување.
  • Не го одложувајте решавањето на проблемите со доверливоста на системот и обновувањето по неуспесите; земете ги предвид во почетната фаза на дизајнирање.

Извор: www.habr.com

Додадете коментар