Tarantool Cartridge: поделба на Lua backend во три линии

Tarantool Cartridge: поделба на Lua backend во три линии

Во Mail.ru Group имаме Tarantool - ова е апликативен сервер во Луа, кој исто така работи како база на податоци (или обратно?). Брзо е и кул, но можностите на еден сервер сè уште не се неограничени. Вертикалното скалирање исто така не е лек, така што Tarantool има алатки за хоризонтално скалирање - модулот vshard [1]. Тоа ви овозможува да споделувате податоци преку неколку сервери, но мора да ги прескокнувате за да ги поставите и да ја прикачите деловната логика.

Добра вест: собравме некои големи снимки (на пр [2], [3]) и создаде друга рамка која значително ќе го поедностави решението на овој проблем.

Тарантул кертриџ е нова рамка за развој на сложени дистрибуирани системи. Ви овозможува да се фокусирате на пишување деловна логика наместо да решавате инфраструктурни проблеми. Подолу ќе ви кажам како функционира оваа рамка и како да пишувате дистрибуирани услуги користејќи ја.

Што точно е проблемот?

Имаме тарантула, имаме вшард - што повеќе да сакаш?

Прво, тоа е прашање на погодност. Конфигурацијата на vshard е конфигурирана преку табелите Lua. За дистрибуиран систем од повеќе процеси на Tarantool да работи правилно, конфигурацијата мора да биде иста насекаде. Никој не сака да го прави ова рачно. Затоа, се користат сите видови скрипти, Ansible и системи за распоредување.

Самиот кертриџ управува со конфигурацијата на vshard, тоа го прави врз основа на неговата сопствена дистрибуирана конфигурација. Во суштина, тоа е едноставна YAML-датотека, чија копија е зачувана во секој пример на Tarantool. Поедноставувањето е што самата рамка ја следи нејзината конфигурација и осигурува дека е иста насекаде.

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

Ги решававме овие проблеми одново и одново, и во одреден момент успеавме да развиеме пристап кој ја поедностави работата со апликацијата во текот на целиот нејзин животен циклус: создавање, развој, тестирање, CI/CD, одржување.

Картриџ го воведува концептот на улога за секој процес на Tarantool. Улогите се концепт што му овозможува на развивачот да се фокусира на пишување код. Сите улоги достапни во проектот може да се извршуваат на еден пример на Tarantool и тоа ќе биде доволно за тестови.

Главни карактеристики на кертриџот Tarantool:

  • автоматизирана кластерска оркестрација;
  • проширување на функционалноста на апликацијата користејќи нови улоги;
  • шаблон за апликација за развој и распоредување;
  • вградено автоматско сечење;
  • интеграција со рамката за тестирање Luatest;
  • управување со кластери користејќи WebUI и API;
  • алатки за пакување и распоредување.

Здраво свету!

Едвај чекам да ја прикажам самата рамка, па ќе ја оставиме приказната за архитектурата за подоцна и ќе започнеме со нешто едноставно. Ако претпоставиме дека самиот Tarantool е веќе инсталиран, тогаш останува само да се направи

$ tarantoolctl rocks install cartridge-cli
$ export PATH=$PWD/.rocks/bin/:$PATH

Овие две команди ќе ги инсталираат алатките за командна линија и ќе ви овозможат да ја креирате вашата прва апликација од шаблонот:

$ cartridge create --name myapp

И ова е она што го добиваме:

myapp/
├── .git/
├── .gitignore
├── app/roles/custom.lua
├── deps.sh
├── init.lua
├── myapp-scm-1.rockspec
├── test
│   ├── helper
│   │   ├── integration.lua
│   │   └── unit.lua
│   ├── helper.lua
│   ├── integration/api_test.lua
│   └── unit/sample_test.lua
└── tmp/

Ова е складиште за git со готово „Здраво, свето!“ апликација. Ајде да се обидеме да го извршиме веднаш, откако претходно ги инсталиравме зависностите (вклучувајќи ја и самата рамка):

$ tarantoolctl rocks make
$ ./init.lua --http-port 8080

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

Развој на апликации

Замислете, дизајнираме проект кој мора да прима податоци, да ги зачувува и да прави извештај еднаш дневно.

Tarantool Cartridge: поделба на Lua backend во три линии

Почнуваме да цртаме дијаграм и ставаме три компоненти на него: порта, складирање и распоредувач. Понатаму работиме на архитектурата. Бидејќи користиме vshard како складирање, додаваме vshard-рутер и vshard-storage во шемата. Ниту портата, ниту распоредувачот нема директно да пристапат до складирањето; за тоа служи рутерот, за тоа е создаден.

Tarantool Cartridge: поделба на Lua backend во три линии

Овој дијаграм сè уште не го претставува точно она што ќе го изградиме во проектот бидејќи компонентите изгледаат апстрактно. Сè уште треба да видиме како ова ќе се проектира на вистинскиот Tarantool - ајде да ги групираме нашите компоненти по процес.

Tarantool Cartridge: поделба на Lua backend во три линии

Нема смисла да се чуваат vshard-рутер и портата на посебни примероци. Зошто треба уште еднаш да сурфаме на мрежата ако ова е веќе одговорност на рутерот? Тие мора да се водат во рамките на истиот процес. Односно, и gateway и vshard.router.cfg се иницијализирани во еден процес и нека комуницираат локално.

Во фазата на дизајнирање, беше погодно да се работи со три компоненти, но јас, како развивач, додека го пишувам кодот, не сакам да размислувам за лансирање на три примери на Tarnatool. Треба да извршам тестови и да проверам дали правилно сум напишал gateway. Или можеби сакам да им покажам карактеристика на моите колеги. Зошто треба да поминам низ мака за распоредување на три копии? Така се роди концептот на улоги. Улога е редовен модул за луш, чиј животен циклус го управува Картриџ. Во овој пример има четири од нив - портал, рутер, складирање, распоредувач. Може да има повеќе во некој друг проект. Сите улоги можат да се извршат во еден процес, и тоа ќе биде доволно.

Tarantool Cartridge: поделба на Lua backend во три линии

И кога станува збор за распоредување на сцена или производство, тогаш на секој процес на Tarantool ќе му доделиме сопствен сет на улоги во зависност од хардверските можности:

Tarantool Cartridge: поделба на Lua backend во три линии

Управување со топологија

Информациите за тоа каде се извршуваат улогите мора да се складираат некаде. И ова „некаде“ е дистрибуираната конфигурација, која веќе ја споменав погоре. Најважно за него е топологијата на кластерот. Еве 3 групи за репликација од 5 процеси на Tarantool:

Tarantool Cartridge: поделба на Lua backend во три линии

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

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

Tarantool Cartridge: поделба на Lua backend во три линии

Животот на улогите

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

function init()
function validate_config()
function apply_config()
function stop()

Секоја улога има своја функција init. Се повикува еднаш или кога улогата е овозможена или кога Tarantool се рестартира. Таму е погодно, на пример, да се иницијализира box.space.create, или распоредувачот може да стартува некое заднинско влакно што ќе работи во одредени временски интервали.

Една функција init можеби не е доволно. Картриџот им овозможува на улогите да ги искористат предностите на дистрибуираната конфигурација што ја користи за складирање на топологијата. Можеме да декларираме нов дел во истата конфигурација и да складираме фрагмент од деловната конфигурација во неа. Во мојот пример, ова може да биде шема на податоци или поставки за распоред за улогата на распоредувачот.

Кластерски повици validate_config и apply_config секој пат кога се менува дистрибуираната конфигурација. Кога конфигурацијата се применува со обврзување во две фази, кластерот проверува дали секоја улога е подготвена да ја прифати оваа нова конфигурација и, доколку е потребно, известува за грешка на корисникот. Кога сите ќе се согласат дека конфигурацијата е нормална, тогаш apply_config.

Исто така, улогите имаат метод stop, што е потребно за да се исчисти излезот на улогата. Ако кажеме дека распоредувачот повеќе не е потребен на овој сервер, тој може да ги запре оние влакна со кои започна init.

Улогите можат да комуницираат едни со други. Навикнати сме да пишуваме повици за функции во Lua, но може да се случи даден процес да ја нема улогата што ни треба. За да ги олесниме повиците преку мрежата, го користиме помошниот модул rpc (повик за далечинска процедура), кој е изграден врз основа на стандардното netbox вградено во Tarantool. Ова може да биде корисно ако, на пример, вашиот портал сака директно да побара од распоредувачот да ја заврши работата токму сега, наместо да чека еден ден.

Друга важна точка е обезбедувањето толеранција на грешки. Картриџот го користи протоколот SWIM за да го следи здравјето [4]. Накратко, процесите разменуваат „гласини“ едни со други преку UDP - секој процес им ги кажува на своите соседи најновите вести, а тие одговараат. Ако одеднаш одговорот не дојде, Тарантул почнува да се сомнева дека нешто не е во ред, а по некое време ја рецитира смртта и почнува да им кажува на сите околу оваа вест.

Tarantool Cartridge: поделба на Lua backend во три линии

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

Tarantool Cartridge: поделба на Lua backend во три линии

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

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

За разлика од Docker, не можеме само да земеме „слика“ на улогата, да ја однесеме на друга машина и да ја извршиме таму. Нашите улоги не се толку изолирани како контејнерите на Докер. Исто така, не можеме да извршиме две идентични улоги на еден пример. Улогата или постои или не; во извесна смисла, тоа е сингл. И трето, улогите мора да бидат исти во целата репликациска група, бидејќи во спротивно би било апсурдно - податоците се исти, но конфигурацијата е различна.

Алатки за распоредување

Ветив дека ќе покажам како Cartridge помага да се распоредат апликациите. За да им го олесни животот на другите, рамката ги пакетите RPM пакети:

$ cartridge pack rpm myapp -- упакует для нас ./myapp-0.1.0-1.rpm
$ sudo yum install ./myapp-0.1.0-1.rpm

Инсталираниот пакет содржи речиси сè што ви треба: и апликацијата и инсталираните зависности. Tarantool, исто така, ќе пристигне на серверот како зависност од пакетот RPM, а нашата услуга е подготвена за стартување. Ова се прави преку systemd, но прво треба да напишете мала конфигурација. Најмалку, наведете го URI на секој процес. На пример, три се доволни.

$ sudo tee /etc/tarantool/conf.d/demo.yml <<CONFIG
myapp.router: {"advertise_uri": "localhost:3301", "http_port": 8080}
myapp.storage_A: {"advertise_uri": "localhost:3302", "http_enabled": False}
myapp.storage_B: {"advertise_uri": "localhost:3303", "http_enabled": False}
CONFIG

Тука има една интересна нијанса. Наместо да ја специфицираме само портата за бинарниот протокол, ја одредуваме целата јавна адреса на процесот вклучувајќи го и името на домаќинот. Ова е неопходно за јазлите на кластерот да знаат како да се поврзат едни со други. Лоша идеја е да се користи 0.0.0.0 како advertise_uri адреса; тоа треба да биде надворешна IP адреса, а не штекер. Без него, ништо нема да работи, па Cartridge едноставно нема да ви дозволи да стартувате јазол со погрешен advertise_uri.

Сега кога конфигурацијата е подготвена, можете да ги започнете процесите. Бидејќи обичната системска единица не дозволува да започне повеќе од еден процес, апликациите на Картриџот се инсталираат со т.н. инстанцирани единици кои работат вака:

$ sudo systemctl start myapp@router
$ sudo systemctl start myapp@storage_A
$ sudo systemctl start myapp@storage_B

Во конфигурацијата, ја одредивме HTTP-портата на која Картриџот го опслужува веб-интерфејсот - 8080. Ајде да одиме до него и да погледнеме:

Tarantool Cartridge: поделба на Lua backend во три линии

Гледаме дека иако процесите работат, тие сè уште не се конфигурирани. Картриџот сè уште не знае кој со кого треба да реплицира и не може сам да донесе одлука, па ги чека нашите постапки. Но, немаме многу избор: животот на новиот кластер започнува со конфигурацијата на првиот јазол. Потоа ќе ги додадеме другите во кластерот, ќе им доделиме улоги и во овој момент распоредувањето може да се смета за успешно завршено.

Ајде да истуриме чаша од вашиот омилен пијалок и да се опуштиме по долгата работна недела. Апликацијата може да се користи.

Tarantool Cartridge: поделба на Lua backend во три линии

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

Кои се резултатите? Пробајте го, искористете го, оставете повратни информации, креирајте билети на Github.

референци

[1] Tarantool » 2.2 » Референца » Референца за карпи » Модул vshard

[2] Како го имплементиравме јадрото на инвестицискиот бизнис на Alfa-Bank базиран на Tarantool

[3] Архитектура за наплата на новата генерација: трансформација со преминот кон Tarantool

[4] SWIM - протокол за изградба на кластер

[5] GitHub - tarantool/cartridge-cli

[6] GitHub - тарантол/кертриџ

Извор: www.habr.com

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