У 2017 годзе мы выйгралі конкурс на распрацоўку транзакцыйнага ядра інвестыцыйнага бізнесу Альфа-Банка і прыступілі да працы (на HighLoad++ 2018 з дакладам аб ядры інвестыцыйнага бізнесу
У працэсе распрацоўкі сістэма эвалюцыянавала і абрастала функцыяналам, і ў нейкі момант мы зразумелі, што ў нас крышталізуецца нешта нашмат большае, чым проста прыкладное ПЗ, створанае для рашэння строга вызначанага круга задач: у нас атрымалася сістэма для пабудовы размеркаваных прыкладанняў з персістэнтным сховішчам. Атрыманы намі вопыт лёг у аснову новага прадукта
Я хачу расказаць аб архітэктуры TDG і аб тых рашэннях, да якіх мы прыйшлі ў працэсе распрацоўкі, пазнаёміць вас з асноўным функцыяналам і паказаць, як наш прадукт можа стаць базай для пабудовы скончаных рашэнняў.
Архітэктурна мы падзялілі сістэму на асобныя ролі, кожная з якіх адказная за рашэнне вызначанага круга задач. Адзін запушчаны асобнік прыкладання рэалізуе адзін ці некалькі тыпаў роляў. У кластары можа быць некалькі роляў аднаго тыпу:
злучальнік
Connector адказвае за сувязь з навакольным светам; яго задача - прыняць запыт, распарсіць яго, і калі гэта атрымалася, то адправіць дадзеныя на апрацоўку ў input processor. Мы падтрымліваем фарматы HTTP, SOAP, Kafka, FIX. Архітэктура дазваляе проста дадаваць падтрымку новых фарматаў, хутка з'явіцца падтрымка IBM MQ. Калі разбор запыту завяршыўся памылкай, то connector верне памылку; у адваротным выпадку ён адкажа, што запыт быў апрацаваны паспяхова, нават калі і ўзнікла памылка пры яго далейшай апрацоўцы. Гэта зроблена спецыяльна, для таго каб працаваць з сістэмамі, якія не ўмеюць паўтараць запыты - ці наадварот, робяць гэта занадта настойліва. Для таго каб не губляць дадзеныя, выкарыстоўваецца рамонтная чарга: аб'ект спачатку пападае ў яе і толькі пасля паспяховай апрацоўкі выдаляецца з яе. Адміністратар можа атрымліваць абвесткі аб аб'ектах, якія засталіся ў рамонтнай чарзе, а пасля ўхілення праграмнай памылкі або апаратнага збою выканаць паўторную спробу.
Input processor
Input processor класіфікуе атрыманыя дадзеныя па характэрных прыкметах і выклікае прыдатныя апрацоўшчыкі. Апрацоўшчыкі - гэта код на мове Lua, які запускаецца ў пясочніцы, такім чынам паўплываць на функцыянаванне сістэмы яны не могуць. На гэтым этапе дадзеныя можна прывесці да патрабаванага ўвазе, а таксама пры неабходнасці запусціць адвольную колькасць задач, якія могуць рэалізоўваць неабходную логіку. Напрыклад, у прадукце MDM (Master Data Management), пабудаваным на Tarantool Data Grid, пры даданні новага карыстача мы, каб не запавольваць апрацоўку запыту, стварэнне залатога запісу запускаем асобнай задачай. Пясочніца падтрымлівае запыты на чытанне, змяненне і даданне даных, дазваляе выконваць некаторую функцыю на ўсіх ролях тыпу storage і агрэгацыю выніку (map/reduce).
Апрацоўшчыкі могуць быць апісаны ў файлах:
sum.lua
local x, y = unpack(...)
return x + y
І затым, абвешчаныя ў канфігурацыі:
functions:
sum: { __file: sum.lua }
Чаму Lua? Lua вельмі простая мова. Зыходзячы з нашага досведу, праз пару гадзін пасля знаёмства з ім, людзі пачынаюць пісаць код, які вырашае іх задачу. І гэта не толькі прафесійныя распрацоўшчыкі, а напрыклад, аналітыкі. Акрамя таго, дзякуючы jit-кампілятару, Lua працуе вельмі хутка.
захоўванне
Storage захоўвае персістэнтныя дадзеныя. Перад захаваннем дадзеныя праходзяць валідацыю на адпаведнасць схеме даных. Для апісання схемы мы выкарыстоўваем пашыраны фармат
{
"name": "User",
"type": "record",
"logicalType": "Aggregate",
"fields": [
{ "name": "id", "type": "string"},
{"name": "first_name", "type": "string"},
{"name": "last_name", "type": "string"}
],
"indexes": ["id"]
}
Па гэтым апісанні аўтаматычна генеруецца DDL (Data Definition Language) для СКБД Тарантул і
Падтрымліваецца асінхронная рэплікацыя дадзеных (у планах дадаць сінхронную).
Output processor
Часам аб паступленні новых дадзеных трэба апавясціць вонкавых спажыўцоў, для гэтага існуе роля Output processor. Пасля захавання дадзеных, яны могуць быць перададзены ў адпаведны ім апрацоўшчык (напрыклад, каб прывесці іх да выгляду, які патрабуе спажывец) - і пасля гэтага перададзены ў connector на адпраўку. Тут таксама выкарыстоўваецца рамонтная чарга: калі аб'ект ніхто не прыняў, адміністратар можа паўтарыць спробу пазней.
маштабаванне
Ролі connector, input processor і output processor не маюць станы, што дазваляе нам маштабаваць сістэму гарызантальна, проста дадаючы новыя асобнікі прыкладання з уключанай роляй патрэбнага тыпу. Для гарызантальнага маштабавання storage выкарыстоўваецца
Уласцівасці дадзеных
Аб'екты могуць быць вельмі вялікімі і змяшчаць іншыя аб'екты. Мы забяспечваем атамарнасць дадання і абнаўленні дадзеных, захоўваючы аб'ект са ўсімі залежнасцямі на адзін віртуальны бакет. Такім чынам выключаецца "размазванне" аб'екта па некалькіх фізічных серверах.
Падтрымліваецца версійнасць: кожнае абнаўленне аб'екта стварае новую версію, і мы заўсёды можам зрабіць часавы зрэз і паглядзець, як свет выглядаў тады. Для дадзеных, якім не патрэбна доўгая гісторыя, мы можам абмежаваць колькасць версій ці нават захоўваць толькі адну - апошнюю, - гэта значыць фактычна адключыць версіяванне для вызначанага тыпу. Таксама можна абмежаваць гісторыю па часе: напрыклад, выдаляць усе аб'екты некаторага тыпу старэйшыя за 1 гады. Падтрымліваецца і архівацыя: мы можам выгружаць аб'екты старэйшыя за азначаны час, вызваляючы месца ў кластары.
задачы
З цікавых функцый варта адзначыць магчымасць запуску задач па раскладзе, па запыце карыстальніка ці праграмна з пясочніцы:
Тут мы бачым яшчэ адну ролю - runner. Гэтая роля не мае стану, і пры неабходнасці ў кластар можна дадаць дадатковыя асобнікі дадатку з гэтай роляй. Адказнасць runner - выкананне задач. Як гаварылася, з пясочніцы магчыма спараджэнне новых задач; яны захоўваюцца ў чарзе на storage і потым выконваюцца на runner. Гэты тып задач называецца Job. Таксама ў нас ёсць тып задач, званы Task - гэта задачы, якія вызначаюцца карыстальнікам і запускаюцца па раскладзе (выкарыстоўваецца сінтаксіс cron) або па патрабаванні. Для запуску і адсочвання такіх задач у нас ёсць зручны дыспетчар задач. Для таго каб дадзены функцыянал быў даступны, неабходна ўлучыць ролю scheduler; гэтая роля мае стан, таму не маштабуецца, што зрэшты і не патрабуецца; пры гэтым яна, як і ўсе астатнія ролі, можа мець рэпліку, якая пачынае працаваць, калі майстар раптам адмовіў.
Лесаруб
Яшчэ адна роля называецца logger. Яна збірае логі з усіх членаў кластара і дае інтэрфейс для іх выгрузкі і прагляду праз вэб-інтэрфейс.
Сэрвісы
Варта згадаць, што сістэма дазваляе лёгка ствараць сервісы. У канфігурацыйным файле можна паказаць, якія запыты накіроўваць на напісаны карыстальнікам апрацоўшчык, які выконваецца ў пясочніцы. У гэтым апрацоўшчыку можна, напрыклад, выканаць нейкі аналітычны запыт і вярнуць вынік.
Сэрвіс апісваецца ў канфігурацыйным файле:
services:
sum:
doc: "adds two numbers"
function: sum
return_type: int
args:
x: int
y: int
GraphQL API генеруецца аўтаматычна і сэрвіс становіцца даступным для выкліку:
query {
sum(x: 1, y: 2)
}
Гэта прывядзе да выкліку апрацоўшчыка sum
, які верне вынік:
3
Прафіляванне запытаў і метрыкі
Для разумення працы сістэмы і прафіляванні запытаў мы рэалізавалі падтрымку пратаколу OpenTracing. Сістэма можа па патрабаванні адпраўляць інфармацыю інструментам, якія падтрымліваюць гэты пратакол, напрыклад, Zipkin, што дазволіць разабрацца з тым, як выконваўся запыт:
Натуральна, сістэма дае ўнутраныя метрыкі, якія можна збіраць з дапамогай Prometheus і візуалізаваць з дапамогай Grafana.
Дэплой
Tarantool Data Grid можа быць задэплоены з RPM-пакетаў або архіва, з дапамогай утыліты з пастаўкі або Ansible, таксама ёсць падтрымка Kubernetes (
Прыкладанне якое рэалізуе бізнэс логіку (канфігурацыя, апрацоўшчыкі) загружаюцца ў задэплоены кластар Tarantool Data Grid у выглядзе архіва праз UI або з дапамогай скрыпту, праз прадстаўлены намі API.
Буквары філасофіі
Якія прыкладанні можна стварыць з дапамогай Tarantool Data Grid? Насамрэч большасць бізнэс-задач так ці інакш злучаны з апрацоўкай струменя дадзеных, захоўваннем і доступам да іх. Таму, калі ў вас ёсць вялікія плыні дадзеных, якія неабходна надзейна захоўваць і мець да іх доступ, то наш прадукт можа зэканоміць вам шмат часу на распрацоўцы і засяродзіцца на сваёй бізнес-логіцы.
Напрыклад, мы хочам збіраць інфармацыю аб рынку нерухомасці, каб у наступным, напрыклад, мець інфармацыю аб самых выгадных прапановах. У гэтым выпадку мы вылучым наступныя задачы:
- Робаты, якія збіраюць інфармацыю з адкрытых крыніц - гэта будуць нашы крыніцы дадзеных. Гэтую задачу вы можаце вырашыць, выкарыстоўваючы гатовыя рашэнні ці напісаўшы код на любой мове.
- Далей Tarantool Data Grid прыме і захавае дадзеныя. Калі фармат дадзеных з розных крыніц адрозніваецца, тыя вы можаце напісаць код на мове Lua, які выканае прывядзенне да адзінага фармату. На этапе папярэдняй апрацоўкі вы таксама зможаце, напрыклад, фільтраваць паўтаральныя прапановы ці дадаткова абнаўляць у базе дадзеных інфармацыю аб агентах, якія працуюць на рынку.
- Цяпер у вас ужо ёсць якое маштабуецца рашэнне ў кластары, якое можна напаўняць дадзенымі і рабіць выбаркі дадзеных. Далей вы можаце рэалізоўваць новы функцыянал, напрыклад, напісаць сэрвіс, які зробіць запыт да дадзеных і выдасць найболей выгодную прапанову за суткі — гэта запатрабуе некалькіх радкоў у канфігурацыйным файле і трохі кода на Lua.
Што далей?
У нас у прыярытэце - павышэнне зручнасці распрацоўкі з дапамогай
Таксама мы вялікую ўвагу ўдзяляем пытанням бяспекі. Прама зараз мы праходзім сертыфікацыю ФСТЭК Расіі, каб пацвердзіць высокі ўзровень бяспекі і адпавядаць прад'яўляным патрабаванням па сертыфікацыі праграмных прадуктаў, якія выкарыстоўваюцца ў інфармацыйных сістэмах персанальных дадзеных і дзяржаўных інфармацыйных сістэмах.
Крыніца: habr.com