In u Gruppu Mail.ru avemu Tarantool - questu hè un servitore d'applicazioni in Lua, chì hè ancu doppia cum'è una basa di dati (o vice versa?). Hè veloce è cool, ma e capacità di un servitore ùn sò micca sempre illimitate. A scala verticale ùn hè ancu una panacea, cusì Tarantool hà arnesi per a scala horizontale - u modulu vshard
Una bona nutizia: avemu cullatu alcuni grandi colpi (per esempiu
Chì ghjè esattamente u prublema?
Avemu una tarantula, avemu vshard - chì vulete più?
Prima, hè una questione di comodità. A cunfigurazione vshard hè cunfigurata attraversu e tavule Lua. Per un sistema distribuitu di parechji prucessi Tarantool per travaglià currettamente, a cunfigurazione deve esse a stessa in ogni locu. Nimu vole fà questu manualmente. Dunque, ogni tipu di script, Ansible è sistemi di implementazione sò usati.
Cartridge stessu gestisce a cunfigurazione vshard, face questu basatu nantu à a so propria cunfigurazione distribuita. Hè essenzialmente un schedariu YAML simplice, una copia di quale hè almacenata in ogni istanza di Tarantool. A simplificazione hè chì u quadru stessu monitoreghja a so cunfigurazione è assicura chì hè u listessu in ogni locu.
Siconda, hè dinò una questione di comodità. A cunfigurazione vshard ùn hà nunda di fà cù u sviluppu di a logica cummerciale è solu distracte u programatore da u so travagliu. Quandu avemu discututu l'architettura di un prughjettu, u più spessu parlemu di cumpunenti individuali è a so interazzione. Hè troppu prestu per pensà à sparghje un cluster à 3 centri di dati.
Avemu risoltu sti prublemi una volta è più, è à un certu puntu avemu riesciutu à sviluppà un approcciu chì simplificà u travagliu cù l'applicazione in tuttu u so ciclu di vita: creazione, sviluppu, teste, CI / CD, mantenimentu.
Cartuccia introduce u cuncettu di un rolu per ogni prucessu Tarantool. I roli sò un cuncettu chì permette à un sviluppatore di fucalizza nantu à scrive codice. Tutti i roli dispunibuli in u prugettu ponu esse eseguiti nantu à una istanza di Tarantool, è questu serà abbastanza per e teste.
Caratteristiche principali di Tarantool Cartridge:
- orchestrazione di cluster automatizata;
- espansione a funziunalità di l'applicazione utilizendu novi roles;
- mudellu di applicazione per u sviluppu è a implementazione;
- sharding automaticu integratu;
- integrazione cù u framework di teste Luatest;
- gestione di cluster cù WebUI è API;
- Strumenti di imballaggio è implementazione.
Hola, Monde!
Ùn possu aspittà per vede u quadru stessu, cusì lasceremu a storia di l'architettura per più tardi è principià cù qualcosa simplice. Se assumemu chì Tarantool stessu hè digià stallatu, allora tuttu ciò chì resta hè di fà
$ tarantoolctl rocks install cartridge-cli
$ export PATH=$PWD/.rocks/bin/:$PATH
Questi dui cumandamenti installanu l'utilità di linea di cumanda è permettenu di creà a vostra prima applicazione da u mudellu:
$ cartridge create --name myapp
È questu hè ciò chì avemu:
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/
Questu hè un repository git cun un prontu "Hello, World!" applicazione. Pruvemu di eseguisce subitu, dopu avè installatu prima e dipendenze (cumpresu u quadru stessu):
$ tarantoolctl rocks make
$ ./init.lua --http-port 8080
Dunque, avemu un nodu in esecuzione per a futura applicazione sharded. Un laico inquisitore pò apre immediatamente l'interfaccia web, cunfigurà un cluster di un node cù u mouse è gode di u risultatu, ma hè troppu prestu per rallegra. Finu a ora, l'appiecazione ùn pò micca fà nunda d'utile, cusì vi dicu nantu à a implementazione dopu, ma avà hè u tempu di scrive codice.
Sviluppu di l'applicazioni
Immaginate, simu cuncependu un prughjettu chì deve riceve dati, salvà è custruisce un rapportu una volta à ghjornu.
Cuminciamu à disegnà un diagramma è mette trè cumpunenti nantu à ellu: gateway, storage and scheduler. Travagliemu in più nantu à l'architettura. Siccomu usemu vshard cum'è almacenamiento, aghjunghjemu vshard-router è vshard-storage à u schema. Nè u gateway nè u pianificatore accede direttamente à l'almacenamiento hè per quessa chì u router hè per quessa hè statu creatu.
Stu diagramma ùn rapprisenta micca esattamente ciò chì avemu da custruisce in u prugettu perchè i cumpunenti parenu astratti. Avemu sempre bisognu di vede cumu questu serà prughjettatu nantu à u veru Tarantool - raggruppemu i nostri cumpunenti per prucessu.
Ci hè pocu puntu di mantene vshard-router è gateway in casi separati. Perchè avemu bisognu di navigà in a reta una volta, se questu hè digià a rispunsabilità di u router? Deve esse eseguite in u stessu prucessu. Questu hè, tramindui gateway è vshard.router.cfg sò inizializzati in un prucessu, è permettenu interagisce in u locu.
À u stadiu di cuncepimentu, era còmuda di travaglià cù trè cumpunenti, ma eiu, cum'è sviluppatore, mentre scrive u codice, ùn vogliu micca pensà à lancià trè casi di Tarnatool. Aghju bisognu di eseguisce e teste è verificate chì aghju scrittu correttu a porta. O forse vogliu dimustrà una funzione à i mo culleghi. Perchè duverebbe passà per u fastidiu di implementà trè copie? Hè cusì chì u cuncettu di roli hè natu. Un rolu hè un modulu luash regulare chì u ciclu di vita hè gestitu da Cartuccia. In questu esempiu, ci sò quattru - gateway, router, storage, scheduler. Ci pò esse più in un altru prughjettu. Tutti i roli ponu esse eseguiti in un prucessu, è questu serà abbastanza.
È quandu si tratta di implementazione à staging o produzzione, allora assignemu à ogni prucessu Tarantool u so propiu set di roli secondu e capacità di hardware:
Gestione di topulugia
L'infurmazione nantu à induve i roli sò in esecuzione deve esse guardatu in qualchì locu. E questu "in un locu" hè a cunfigurazione distribuita, chì aghju digià citatu sopra. A cosa più impurtante hè a topologia di cluster. Eccu 3 gruppi di replicazione di 5 prucessi Tarantool:
Ùn vulemu micca perdiri dati, cusì trattemu l'infurmazioni nantu à i prucessi in esecuzione cun cura. Cartuccia mantene a traccia di a cunfigurazione utilizendu un impegnu in duie fasi. Una volta vulemu aghjurnà a cunfigurazione, prima verifica chì tutti i casi sò dispunibuli è pronti per accettà a nova cunfigurazione. Dopu questu, a seconda fasa applica a cunfigurazione. Cusì, ancu s'è una copia hè temporaneamente indisponibile, ùn succede nunda di male. A cunfigurazione ùn serà micca solu appiicata è vi vede un errore in anticipu.
Ancu in a seccione di topologia, hè indicatu un parametru cusì impurtante cum'è u capu di ogni gruppu di replicazione. Di solitu questu hè a copia chì hè stata arregistrata. U restu sò più spessu in lettura, ancu s'ellu ci ponu esse eccezzioni. Calchì volta i sviluppatori bravi ùn anu micca paura di cunflitti è ponu scrive dati à parechje rèpliche in parallelu, ma ci sò parechje operazioni chì, ùn importa ciò chì, ùn deve esse realizatu duie volte. Per questu ci hè un signu di un capu.
A vita di roli
Per esse un rolu astrattu in una tale architettura, u quadru deve in qualchì manera gestisce. Naturalmente, u cuntrollu si faci senza riavvia u prucessu Tarantool. Ci sò 4 callbacks per gestisce i roli. Cartuccia stessu li chjamarà secondu ciò chì hè scrittu in a so cunfigurazione distribuita, applicà cusì a cunfigurazione à roli specifichi.
function init()
function validate_config()
function apply_config()
function stop()
Ogni rolu hà una funzione init
. Hè chjamatu una volta o quandu u rolu hè attivatu o quandu Tarantool hè riavviatu. Hè cunvenutu quì, per esempiu, per inizializà box.space.create, o u scheduler pò lancià una fibra di fondu chì hà da fà u travagliu in certi intervalli di tempu.
Una funzione init
pò esse micca abbastanza. Cartuccia permette à i roli di prufittà di a cunfigurazione distribuita chì usa per almacenà a topologia. Pudemu dichjarà una nova sezione in a listessa cunfigurazione è almacenà un fragmentu di a cunfigurazione cummerciale in questu. In u mo esempiu, questu puderia esse un schema di dati o paràmetri di pianificazione per u rolu di pianificatore.
Chjama di cluster validate_config
и apply_config
ogni volta chì a cunfigurazione distribuita cambia. Quandu una cunfigurazione hè appiicata da un impegnu in dui fasi, u cluster verifica chì ogni rolu hè prontu à accettà sta nova cunfigurazione è, se ne necessariu, informa un errore à l'utilizatore. Quandu tutti accunsenu chì a cunfigurazione hè normale, allora u apply_config
.
I roli anu ancu un metudu stop
, chì hè necessariu per pulizziari l'output di u rolu. Se dicemu chì u pianificatore ùn hè più necessariu in questu servitore, pò piantà quelli fibre chì hà cuminciatu init
.
I roli ponu interagisce cù l'altri. Semu abituati à scrive e chjama di funzione in Lua, ma pò accade chì un prucessu datu ùn hà micca u rolu chì avemu bisognu. Per facilità e chjama nantu à a reta, usemu u modulu ausiliariu rpc (call procedure remote), chì hè custruitu nantu à a basa di a netbox standard integrata in Tarantool. Questu pò esse utile se, per esempiu, u vostru gateway vole dumandà direttamente à u pianificatore per fà u travagliu avà, invece di aspittà un ghjornu.
Un altru puntu impurtante hè di assicurà a tolleranza di difetti. Cartuccia usa u protocolu SWIM per monitorizà a salute
Basatu annantu à stu protokollu, Cartuccia urganizeghja u prucessu di fallimentu automaticu. Ogni prucessu monitoreghja u so ambiente, è se u capu di colpu smette di risponde, a replica pò piglià u so rolu, è Cartridge cunfigura i roli in esecuzione in cunseguenza.
Avete bisognu à esse attentu quì, perchè u cambiamentu frequente avanti è avanti pò purtà à cunflitti di dati durante a replicazione. Di sicuru, ùn deve micca attivà u failover automaticu à l'aleatoriu. Avemu da capisce chjaramente ciò chì succede è esse sicuru chì a replicazione ùn si romperà dopu chì u capu hè restauratu è a corona hè tornata à ellu.
Da tuttu questu, pudete avè a sensazione chì i roli sò simili à i microservizi. In un sensu, sò solu questu, solu cum'è moduli in i prucessi Tarantool. Ma ci sò ancu una quantità di differenzi fundamentali. Prima, tutti i roli di u prughjettu devenu campà in a stessa basa di codice. E tutti i prucessi di Tarantool deve esse lanciatu da a listessa basa di codice, perchè ùn ci sò micca sorprese cum'è quelli chì avemu da pruvà à inizializà u scheduler, ma simpricimenti ùn esiste micca. Inoltre, ùn deve micca permette di differenzi in versioni di codice, perchè u cumpurtamentu di u sistema in una tale situazione hè assai difficiuli di predichendu è debug.
A cuntrariu di Docker, ùn pudemu micca solu piglià un rolu "imaghjini", piglià à un'altra macchina è eseguisce quì. I nostri roli ùn sò micca cusì isolati cum'è i cuntenituri Docker. Inoltre, ùn pudemu micca eseguisce dui roli identichi nantu à una istanza. Un rolu o esiste o ùn hè micca in un sensu, hè un singleton. E terzu, i roli devenu esse listessi in tuttu u gruppu di replicazione, perchè altrimenti seria assurdu - i dati sò listessi, ma a cunfigurazione hè diversa.
Strumenti di implementazione
Aghju prumessu di mostrà cumu Cartridge aiuta à implementà l'applicazioni. Per fà a vita più faciule per l'altri, i pacchetti di framework RPM:
$ cartridge pack rpm myapp -- упакует для нас ./myapp-0.1.0-1.rpm
$ sudo yum install ./myapp-0.1.0-1.rpm
U pacchettu installatu cuntene guasi tuttu ciò chì avete bisognu: sia l'applicazione sia e dipendenze installate. Tarantool ghjunghjerà ancu in u servitore cum'è una dependenza di u pacchettu RPM, è u nostru serviziu hè prontu à lancià. Questu hè fattu attraversu systemd, ma prima avete bisognu di scrive un pocu cunfigurazione. À u minimu, specificate l'URI di ogni prucessu. Trè hè abbastanza per esempiu.
$ 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
Ci hè una sfumatura interessante quì. Invece di specificà solu u portu di protokollu binariu, specifiemu l'indirizzu publicu tutale di u prucessu cumpresu u nome d'ospite. Questu hè necessariu per chì i nodi di cluster sappianu cumu cunnette cù l'altri. Hè una mala idea di utilizà 0.0.0.0 cum'è l'indirizzu advertise_uri deve esse un indirizzu IP esternu, micca un socket bind. Senza ellu, nunda ùn hà da travaglià, cusì Cartridge simpricimenti ùn vi permetterà di lancià un node cù u advertise_uri sbagliatu.
Avà chì a cunfigurazione hè pronta, pudete inizià i prucessi. Siccomu una unità systemd regulare ùn permettenu micca più di un prucessu per inizià, l'applicazioni nantu à a Cartuccia sò stallate da u cusì chjamatu. unità instantiate chì funzionanu cusì:
$ sudo systemctl start myapp@router
$ sudo systemctl start myapp@storage_A
$ sudo systemctl start myapp@storage_B
In a cunfigurazione, avemu specificatu u portu HTTP nantu à quale Cartridge serve l'interfaccia web - 8080. Andemu à ellu è fate un ochju:
Avemu vistu chì ancu se i prucessi sò in esecuzione, ùn sò micca cunfigurati. U cartucciu ùn sapi ancu quale deve riplicà cù quale è ùn pò micca fà una decisione per sè stessu, cusì aspetta per e nostre azzioni. Ma ùn avemu micca assai scelta: a vita di un novu cluster principia cù a cunfigurazione di u primu node. Allora aghjunghjemu l'altri à u cluster, l'assignemu roli, è à questu puntu a implementazione pò esse cunsiderata cum'è successu.
Versemu un vetru di a vostra bevanda preferita è rilassate dopu una longa settimana di travagliu. L'applicazione pò esse usata.
Risultati
Chì sò i risultati ? Pruvate, aduprate, lasciate feedback, create biglietti nantu à Github.
referenze
[1]
Source: www.habr.com