Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

U Mail.ru Grupi imamo Tarantool — to je poslužitelj aplikacija na Lua, koji također služi kao baza podataka (ili obrnuto?). Brz je i izvrstan, ali mogućnosti jednog poslužitelja nisu beskrajne. Vertikalno skaliranje također nije panaceja, zbog čega Tarantool ima alate za horizontalno skaliranje — modul vshard. [1]. Omogućuje shardiranje podataka na više poslužitelja, ali potrebno je malo truda da ga pravilno postavite i integrirate poslovnu logiku.

Dobre vijesti: prikupili smo iskustva (na primjer [2], [3]) i stvorili novi okvir koji će značajno olakšati rješavanje ovog problema.

Tarantool Cartridge — novi je okvir za razvoj složenih distribuiranih sustava. Omogućuje vam da se fokusirate na pisanje poslovne logike umjesto rješavanja infrastrukturnih problema. U nastavku ću objasniti kako je ovaj okvir strukturiran i kako s njim razvijati distribuirane usluge.

A koja je zapravo problematika?

Imamo Tarantool, imamo vshard — što još poželjeti?

Prvo, radi se o praktičnosti. Konfiguracija vsharda postavlja se putem Lua tablica. Da bi distribuirani sustav s više Tarantool procesa ispravno radio, konfiguracija mora biti posvuda identična. Nitko ne želi raditi to ručno. Stoga se koriste razni skripti, Ansible, sustavi za implementaciju.

Cartridge upravlja konfiguracijom vsharda, to čini na temelju svoje vlastite distribuirane konfiguracije. U suštini, to je jednostavna YAML datoteka, čija kopija se čuva u svakoj instanci Tarantool-a. Olakšanje se sastoji u tome da okvir sam prati svoju konfiguraciju i osigurava da ona bude posvuda identična.

Drugo, ponovo se radi o praktičnosti. Konfiguracija vsharda nema veze s razvojem poslovne logike i samo odvlači pažnju programerima od posla. Kada raspravljamo o arhitekturi nekog projekta, najčešće govorimo o pojedinačnim komponentama i njihovoj interakciji. O implementaciji klastera na 3 data centra je preuranjeno razmišljati.

Bavili smo se ovim problemima iznova i iznova, i u nekom trenutku smo uspjeli razviti pristup koji pojednostavljuje rad s aplikacijom tijekom cijelog njezina životnog ciklusa: kreiranje, razvoj, testiranje, CI/CD, održavanje.

Cartridge uvodi pojam uloge za svaki proces Tarantool. Uloge su koncept koji omogućava programerima da se fokusiraju na pisanje koda. Sve dostupne uloge u projektu mogu se pokrenuti na jednom instanci Tarantool-a, a za testiranje će to biti dovoljno.

Glavne mogućnosti Tarantool Cartridge:

  • automatsko orkestriranje klastera;
  • proširenje funkcionalnosti aplikacije putem novih uloga;
  • šablon aplikacije za razvoj i implementaciju;
  • ugrađeno automatsko shardiranje;
  • integracija s testnim okvirom Luatest;
  • upravljanje klasterom putem WebUI i API;
  • alatke za pakiranje i implementaciju.

Hello, World!

Jedva čekam da pokažem sam okvir, pa ćemo razgovor o arhitekturi ostaviti za kasnije i započeti s jednostavnim. Ako pretpostavimo da je Tarantool već instaliran, ostaje samo:

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

Ove dvije naredbe će instalirati alate komandne linije i omogućiti kreiranje vaše prve aplikacije iz šablona:

$ cartridge create --name myapp

I evo što ćemo dobiti:

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/

To je git-repozitorij s gotovom "Hello, World!" aplikacijom. Odmah ćemo pokušati pokrenuti aplikaciju, nakon što instaliramo zavisnosti (uključujući sam okvir):

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

Dakle, imamo pokrenutu jednu nodu buduće shardirane aplikacije. Radoznao posmatrač može odmah otvoriti web sučelje, konfigurirati klaster s jednim čvorom i uživati u rezultatu, ali još je rano za radovanje. Trenutno aplikacija ne može raditi ništa korisno, pa ću o implementaciji govoriti kasnije, a sada dolazi vrijeme za pisanje koda.

Razvoj aplikacija

Zamislite da dizajniramo projekat koji treba primati podatke, čuvati ih i jednom dnevno generirati izvještaj.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Počinjemo s crtanjem sheme i stavljamo na nju tri komponente: gateway, storage i scheduler. Nastavljamo s razradom arhitekture. Pošto koristimo vshard kao skladište, dodajemo vshard-router i vshard-storage u shemu. Ni gateway ni scheduler neće izravno pristupati skladištu, za to postoji router, koji je prvenstveno za to stvoren.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Ova shema još uvijek ne odražava sasvim točno ono što ćemo stvoriti u projektu, jer komponenti izgleda apstraktno. Trebamo još vidjeti kako će se to projicirati na stvarni Tarantool — grupirat ćemo naše komponente prema procesima.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Nema smisla zadržati vshard-router i gateway na odvojenim instancama. Zašto bismo se dodatno kretali mrežom kada to već pripada dužnosti routera? Oni bi trebali biti pokrenuti unutar jednog procesa. To znači da se u jednom procesu inicijaliziraju i gateway i vshard.router.cfg, i neka interagiraju lokalno.

U fazi dizajniranja bilo je praktično raditi s tri komponente, ali, kao developer, dok pišem kod, ne želim razmišljati o pokretanju tri instance Tarnatool-a. Trebam pokrenuti testove i provjeriti jesam li ispravno napisao gateway. Ili, možda, želim demonstrirati značajku kolegama. Zašto bih se mučio s postavljanjem tri instance? Tako je nastala koncept uloga. Uloga je obični lua modul čijim životnim ciklusom upravlja Cartridge. U ovom primjeru ima ih četiri — gateway, router, storage, scheduler. U drugom projektu može ih biti više. Sve uloge mogu se pokrenuti u jednom procesu, i to će biti dovoljno.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

A kada dođe vrijeme za implementaciju u staging ili proizvodnju, tada ćemo svakom procesu Tarantool dodijeliti svoj set uloga ovisno o hardverskim mogućnostima:

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Upravljenje topologijom

Informacije o tome gdje su koje uloge pokrenute moraju se negdje pohraniti. A to “negdje” je distribuirana konfiguracija, o kojoj sam već spomenuo. Najvažnije u tome je topologija klastera. Ovdje je prikazano 3 replikacijske grupe od 5 procesa Tarantool:

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Ne želimo izgubiti podatke, stoga pažljivo tretiramo informacije o pokrenutim procesima. Cartridge prati konfiguraciju putem dvostruke faze commit-a. Kada želimo ažurirati konfiguraciju, prvo provjerava dostupnost svih instanci i njihovu spremnost da prime novu konfiguraciju. Nakon toga se u drugoj fazi primjenjuje konfiguracija. Tako, čak i ako jedna instanca postane privremeno nedostupna, ništa strašno se neće dogoditi. Konfiguracija se jednostavno neće primijeniti i unaprijed ćete vidjeti grešku.

U sekciji topologije naveden je važan parametar, kao što je vođa svake replikacijske grupe. Obično je to onaj primjerak na koji se zapisuje. Ostali su najčešće samo za čitanje, iako može biti iznimaka. Ponekad se hrabri programeri ne boje sukoba i mogu paralelno pisati podatke na nekoliko replika, ali postoje određene operacije koje se bez obzira na sve ne smiju izvoditi dvaput. Za to postoji oznaka vođe.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Život uloga

Da apstraktna uloga može postojati u takvoj arhitekturi, okvir mora nekako njima upravljati. Naravno, upravljanje se odvija bez ponovnog pokretanja procesa Tarantool. Za upravljanje ulogama postoje 4 povratne informacije. Cartridge će ih automatski pozvati ovisno o tome što je napisano u distribuiranoj konfiguraciji, čime primjenjuje konfiguraciju na određene uloge.

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

Svaka uloga ima funkciju init. Ona se poziva jednom prilikom uključivanja uloge ili prilikom ponovnog pokretanja Tarantoola. Tu se lako može inicijalizirati box.space.create, ili scheduler može pokrenuti neki pozadinski fiber koji će obavljati posao u određenim intervalima.

Jedna funkcija init možda nije dovoljna. Cartridge omogućuje ulogama da koriste onu distribuiranu konfiguraciju koju koristi za pohranu topologije. U ovoj istoj konfiguraciji možemo deklarirati novu sekciju i pohraniti u njoj fragment poslovne konfiguracije. U mom primjeru to može biti shema podataka ili postavke rasporeda za ulogu scheduler.

Klaster poziva validate_config i apply_config prilikom svake promjene distribuirane konfiguracije. Kada se konfiguracija primjenjuje dvostupanjskim komitom, klaster provjerava da li je svaka uloga spremna primiti ovu novu konfiguraciju i, ako je potrebno, obavještava korisnika o grešci. Kada se svi slože da je konfiguracija u redu, izvršava se apply_config.

Također, uloge imaju metodu stop, koja je potrebna za čišćenje rezultata rada uloge. Ako kažemo da scheduler na ovom serveru više nije potreban, on može zaustaviti one fibere koje je pokrenuo putem init.

Uloge se mogu međusobno povezivati. Navikli smo pisati pozive funkcija na Lua, ali može se dogoditi da u tom procesu nemamo potrebnu ulogu. Kako bismo olakšali pozive preko mreže, koristimo pomoćni modul rpc (remote procedure call) koji je izgrađen na osnovu standardnog netbox-a uključenog u Tarantool. To može biti korisno, ako, na primjer, vaš gateway želi izravno zatražiti od scheduler-a da obavi posao odmah, umjesto da čeka 24 sata.

Još jedna važna stavka je osiguranje otpornosti na greške. Za nadgledanje stanja, Cartridge koristi SWIM protokol. [4]. Ukratko, procesi međusobno razmjenjuju "glasine" putem UDP-a — svaki proces govori svojim susjedima najnovije vijesti, a oni odgovaraju. Ako odgovor iznenada ne stigne, Tarantool počinje sumnjati da nešto nije u redu, a nakon nekog vremena objavljuje smrt i počinje javno priopćavati tu vijest svima u okolini.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Na temelju ovog protokola, Cartridge organizira automatsku obradu grešaka. Svaki proces prati svoje okruženje, i ako lider iznenada prestane odgovarati, replikat može preuzeti njegovu ulogu, a Cartridge odgovarajuće konfigurira pokrenute uloge.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Ovdje treba biti oprezan, jer česte promjene naprijed-natrag mogu dovesti do sukoba podataka tijekom replikacije. Uključivati automatski failover bez razmišljanja, naravno, nije pametno. Treba jasno razumjeti što se događa i biti sigurni da replikacija neće propasti nakon što se lider oporavi i ponovno preuzme svoju ulogu.

Od svega rečenog može se steći dojam da uloge nalikuju mikroservisima. U nekom smislu one to i jesu, samo kao moduli unutar Tarantool procesa. No, postoje i brojna načelna razlikovanja. Prvo, sve uloge projekta trebaju živjeti u istoj bazi koda. I svi Tarantool procesi trebaju se pokretati iz iste baze koda kako ne bi bilo iznenađenja poput onih kada pokušavamo inicijalizirati scheduler, a njega jednostavno nema. Također, ne bi trebalo dopuštati razlike u verzijama koda, jer je ponašanje sustava u takvoj situaciji vrlo teško predvidjeti i otkloniti greške.

Za razliku od Dockera, ne možemo jednostavno uzeti "sliku" uloge, prenijeti je na drugo računalo i tamo je pokrenuti. Naše uloge nisu toliko izolirane poput Docker kontejnera. Također, ne možemo pokrenuti dvije iste uloge na jednoj instanci. Uloga ili postoji ili je nema, na neki način je to singleton. I treće, unutar cijele replikacijske grupe uloge moraju biti jednake, jer bi inače bilo besmisleno — podaci su isti, a konfiguracija različita.

Alati za implementaciju

Obećao sam pokazati kako Cartridge pomaže u implementaciji aplikacija. Kako bih olakšao život svima, okvir pakira RPM pakete:

$ cartridge pack rpm myapp -- pakira za nas .\/myapp-0.1.0-1.rpm
$ sudo yum install .\/myapp-0.1.0-1.rpm

Instalirani paket nosi gotovo sve što je potrebno: i aplikaciju i instalirane Lua ovisnosti. Tarantool će na server također doći kao ovisnost RPM paketa, a naš servis je spreman za pokretanje. To se radi kroz systemd, ali prvo je potrebno napisati malo konfiguracije. Bar, potrebno je navesti URI svakog procesa. Tri za primjer će biti dovoljna.

$ 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

Ovdje postoji zanimljiva nijansa. Umjesto da navedemo samo port binarnog protokola, navodimo javnu adresu procesa u cijelosti uključujući hostname. To je potrebno kako bi čvorovi klastera znali kako se povezati jedni s drugima. Loša ideja je koristiti adresu 0.0.0.0 kao advertise_uri, trebao bi to biti vanjski IP adresa, a ne bind socket. Bez njega ništa neće raditi, tako da Cartridge jednostavno neće dopustiti pokretanje čvora s pogrešnim advertise_uri.

Sada kada je konfiguracija spremna, možemo pokrenuti procese. Kako obična systemd jedinica ne dopušta pokretanje više od jednog procesa, aplikacije na Cartridge instaliraju takozvane instantiated jedinice, koje rade ovako:

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

U konfiguraciji smo naveli HTTP port na kojem Cartridge poslužuje web sučelje — 8080. Posjetimo ga i pogledajmo:

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Vidimo da su procesi pokrenuti, ali još nisu konfigurirani. Kteridž još uvijek ne zna tko se s kim treba replicirati i ne može donijeti odluku samostalno, stoga čeka naše akcije. Naš izbor nije velik: život novog klastera počinje konfiguracijom prvog čvora. Kasnije ćemo dodati ostatak klastera, dodijeliti im uloge, i tada možemo smatrati da je implementacija uspješno završena.

Ulijmo čašu omiljenog napitka i opustimo se nakon dugog radnog tjedna. Aplikaciju možemo koristiti.

Tarantool Cartridge: shardiranje Lua-bekenda u tri linije

Zaključci

Što su zaključci? Isprobajte, koristite, ostavite povratne informacije, otvarajte tikete na GitHubu.

Linkovi

[1] Tarantool » 2.2 » Reference » Rocks reference » Modul vshard

[2] Kako smo implementirali jezgru investicijskog biznisa Alfa-Banke na temelju Tarantoola

[3] Arhitektura novog generacijskog billing sistema: transformacija prelaskom na Tarantool

[4] SWIM — protokol za izgradnju klastera

[5] GitHub — tarantool/carpod-cli

[6] GitHub — tarantool/carpod

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster