Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Në Mail.ru Group ne kemi Tarantool - ky është një server aplikacioni në Lua, i cili gjithashtu funksionon si bazë të dhënash (ose anasjelltas?). Është i shpejtë dhe i lezetshëm, por aftësitë e një serveri nuk janë ende të pakufizuara. Shkallëzimi vertikal nuk është gjithashtu një ilaç, kështu që Tarantool ka mjete për shkallëzim horizontal - moduli vshard [1]. Kjo ju lejon të ndani të dhënat nëpër disa serverë, por ju duhet të ndërhyni me to për t'i konfiguruar dhe bashkangjitur logjikën e biznesit.

Lajm i mirë: ne kemi mbledhur disa foto të mëdha (p.sh [2], [3]) dhe krijoi një kornizë tjetër që do të thjeshtojë ndjeshëm zgjidhjen e këtij problemi.

Fisheku Tarantool është një kornizë e re për zhvillimin e sistemeve komplekse të shpërndara. Kjo ju lejon të përqendroheni në shkrimin e logjikës së biznesit në vend që të zgjidhni problemet e infrastrukturës. Më poshtë prerjes do t'ju tregoj se si funksionon kjo kornizë dhe si të shkruani shërbime të shpërndara duke përdorur atë.

Cili është saktësisht problemi?

Ne kemi një tarantula, kemi vshard - çfarë mund të dëshironi më shumë?

Së pari, është një çështje komoditeti. Konfigurimi i vshard është konfiguruar përmes tabelave Lua. Që një sistem i shpërndarë me procese të shumta Tarantool të funksionojë siç duhet, konfigurimi duhet të jetë i njëjtë kudo. Askush nuk dëshiron ta bëjë këtë me dorë. Prandaj, përdoren të gjitha llojet e skripteve, Ansible dhe sistemet e vendosjes.

Fisheku vetë menaxhon konfigurimin vshard, ai e bën këtë bazuar në të konfigurimin e vet të shpërndarë. Në thelb është një skedar i thjeshtë YAML, një kopje e të cilit ruhet në çdo shembull të Tarantool. Thjeshtimi është se vetë kuadri monitoron konfigurimin e tij dhe siguron që ai të jetë i njëjtë kudo.

Së dyti, është përsëri një çështje komoditeti. Konfigurimi i vshard nuk ka asnjë lidhje me zhvillimin e logjikës së biznesit dhe vetëm e largon programuesin nga puna e tij. Kur diskutojmë arkitekturën e një projekti, më shpesh flasim për komponentë individualë dhe ndërveprimin e tyre. Është shumë herët për të menduar për hapjen e një grupi në 3 qendra të të dhënave.

Ne i zgjidhëm këto probleme vazhdimisht dhe në një moment arritëm të zhvillonim një qasje që thjeshtoi punën me aplikacionin gjatë gjithë ciklit të tij jetësor: krijimi, zhvillimi, testimi, CI/CD, mirëmbajtja.

Cartridge prezanton konceptin e një roli për çdo proces Tarantool. Rolet janë një koncept që lejon një zhvillues të fokusohet në shkrimin e kodit. Të gjitha rolet e disponueshme në projekt mund të ekzekutohen në një shembull të Tarantool, dhe kjo do të jetë e mjaftueshme për teste.

Karakteristikat kryesore të fishekut Tarantool:

  • orkestrimi i automatizuar i grupimeve;
  • zgjerimi i funksionalitetit të aplikacionit duke përdorur role të reja;
  • shabllonin e aplikacionit për zhvillim dhe vendosje;
  • ndarje automatike e integruar;
  • integrimi me kornizën e testimit Luatest;
  • menaxhimi i grupimeve duke përdorur WebUI dhe API;
  • mjetet e paketimit dhe vendosjes.

Përshendetje Botë!

Mezi pres të tregoj vetë kornizën, kështu që ne do ta lëmë historinë për arkitekturën për më vonë dhe do të fillojmë me diçka të thjeshtë. Nëse supozojmë se vetë Tarantool është instaluar tashmë, atëherë gjithçka që mbetet është të bëjmë

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

Këto dy komanda do të instalojnë shërbimet e linjës së komandës dhe do t'ju lejojnë të krijoni aplikacionin tuaj të parë nga shablloni:

$ cartridge create --name myapp

Dhe kjo është ajo që marrim:

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/

Ky është një depo git me një "Hello, World!" aplikacion. Le të përpiqemi ta ekzekutojmë menjëherë, pasi të kemi instaluar më parë varësitë (përfshirë vetë kornizën):

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

Pra, ne kemi një nyje që funksionon për aplikacionin e ardhshëm të copëtuar. Një laik kureshtar mund të hapë menjëherë ndërfaqen në internet, të konfigurojë një grup të një nyje me miun dhe të shijojë rezultatin, por është shumë herët për t'u gëzuar. Deri më tani, aplikacioni nuk mund të bëjë asgjë të dobishme, kështu që unë do t'ju tregoj për vendosjen më vonë, por tani është koha për të shkruar kodin.

Zhvillimi i Aplikacionit

Vetëm imagjinoni, ne po hartojmë një projekt që duhet të marrë të dhëna, t'i ruajë dhe të ndërtojë një raport një herë në ditë.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Ne fillojmë të vizatojmë një diagram dhe vendosim tre komponentë në të: portë, ruajtje dhe planifikues. Ne po punojmë më tej për arkitekturën. Meqenëse ne përdorim vshard si ruajtje, ne shtojmë vshard-ruter dhe vshard-storage në skemë. As porta dhe as planifikuesi nuk do të hyjnë drejtpërdrejt në hapësirën ruajtëse; për këtë shërben ruteri, për këtë është krijuar.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Ky diagram ende nuk përfaqëson saktësisht atë që do të ndërtojmë në projekt sepse komponentët duken abstraktë. Ne ende duhet të shohim se si do të projektohet kjo në Tarantool-in e vërtetë - le t'i grupojmë komponentët tanë sipas procesit.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Nuk ka kuptim të mbash vshard-router dhe gateway në raste të veçanta. Pse duhet të shfletojmë rrjetin edhe një herë nëse kjo tashmë është përgjegjësi e ruterit? Ato duhet të drejtohen brenda të njëjtit proces. Kjo do të thotë, si gateway ashtu edhe vshard.router.cfg janë inicializuar në një proces dhe le të ndërveprojnë në nivel lokal.

Në fazën e projektimit, ishte e përshtatshme të punoja me tre komponentë, por unë, si zhvillues, ndërsa shkruaj kodin, nuk dua të mendoj për lëshimin e tre shembujve të Tarnatool. Më duhet të bëj teste dhe të kontrolloj nëse e kam shkruar saktë portën. Ose ndoshta dua t'u tregoj një veçori kolegëve të mi. Pse duhet të kaloj nëpër telashet e vendosjes së tre kopjeve? Kështu lindi koncepti i roleve. Një rol është një modul i rregullt luash, cikli i jetës së të cilit menaxhohet nga Cartridge. Në këtë shembull ka katër prej tyre - gateway, router, storage, planer. Mund të ketë më shumë në një projekt tjetër. Të gjitha rolet mund të ekzekutohen në një proces, dhe kjo do të jetë e mjaftueshme.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Dhe kur bëhet fjalë për vendosjen në skenë ose prodhim, atëherë ne do t'i caktojmë secilit proces Tarantool grupin e vet të roleve në varësi të aftësive të harduerit:

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Menaxhimi i topologjisë

Informacioni se ku po ekzekutohen rolet duhet të ruhen diku. Dhe kjo "diku" është konfigurimi i shpërndarë, të cilin e përmenda tashmë më lart. Gjëja më e rëndësishme për të është topologjia e grupimeve. Këtu janë 3 grupe të përsëritjes me 5 procese Tarantool:

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Ne nuk duam të humbasim të dhëna, kështu që ne i trajtojmë me kujdes informacionin rreth proceseve të ekzekutimit. Fisheku mban gjurmët e konfigurimit duke përdorur një angazhim dyfazor. Sapo duam të përditësojmë konfigurimin, ai fillimisht kontrollon që të gjitha instancat janë të disponueshme dhe gati për të pranuar konfigurimin e ri. Pas kësaj, faza e dytë aplikon konfigurimin. Kështu, edhe nëse një kopje rezulton të jetë përkohësisht e padisponueshme, asgjë e keqe nuk do të ndodhë. Konfigurimi thjesht nuk do të zbatohet dhe do të shihni një gabim paraprakisht.

Gjithashtu në seksionin e topologjisë, tregohet një parametër kaq i rëndësishëm si drejtuesi i secilit grup replikues. Zakonisht kjo është kopja që po regjistrohet. Pjesa tjetër janë më shpesh vetëm për lexim, megjithëse mund të ketë përjashtime. Ndonjëherë zhvilluesit e guximshëm nuk kanë frikë nga konfliktet dhe mund të shkruajnë të dhëna në disa kopje paralelisht, por ka disa operacione që, pavarësisht se çfarë, nuk duhet të kryhen dy herë. Për këtë ekziston një shenjë e një udhëheqësi.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Jeta e roleve

Që një rol abstrakt të ekzistojë në një arkitekturë të tillë, korniza duhet t'i menaxhojë ato disi. Natyrisht, kontrolli ndodh pa rifilluar procesin Tarantool. Ka 4 telefonata për të menaxhuar rolet. Vetë fisheku do t'i thërrasë ato në varësi të asaj që shkruhet në konfigurimin e tij të shpërndarë, duke aplikuar kështu konfigurimin në role specifike.

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

Çdo rol ka një funksion init. Ai thirret një herë ose kur roli është i aktivizuar ose kur Tarantool riniset. Është e përshtatshme atje, për shembull, të inicializosh box.space.create, ose planifikuesi mund të nisë disa fibra sfondi që do të kryejnë punë në intervale të caktuara kohore.

Një funksion init mund të mos mjaftojë. Cartridge lejon rolet të përfitojnë nga konfigurimi i shpërndarë që ai përdor për të ruajtur topologjinë. Ne mund të deklarojmë një seksion të ri në të njëjtin konfigurim dhe të ruajmë një fragment të konfigurimit të biznesit në të. Në shembullin tim, kjo mund të jetë një skemë e të dhënave ose cilësimet e planit për rolin e planifikuesit.

Thirrjet e grupit validate_config и apply_config sa herë që ndryshon konfigurimi i shpërndarë. Kur një konfigurim zbatohet nga një kryerje dyfazore, grupi kontrollon që secili rol të jetë gati për të pranuar këtë konfigurim të ri dhe, nëse është e nevojshme, raporton një gabim tek përdoruesi. Kur të gjithë bien dakord që konfigurimi është normal, atëherë apply_config.

Gjithashtu rolet kanë një metodë stop, e cila nevojitet për të pastruar rezultatin e rolit. Nëse themi se programuesi nuk është më i nevojshëm në këtë server, ai mund të ndalojë ato fibra me të cilat filloi init.

Rolet mund të ndërveprojnë me njëri-tjetrin. Jemi mësuar të shkruajmë thirrje funksioni në Lua, por mund të ndodhë që një proces i caktuar të mos ketë rolin që na nevojitet. Për të lehtësuar thirrjet përmes rrjetit, ne përdorim modulin ndihmës rpc (thirrja e procedurës në distancë), i cili është ndërtuar mbi bazën e netbox standard të integruar në Tarantool. Kjo mund të jetë e dobishme nëse, për shembull, gateway juaj dëshiron t'i kërkojë drejtpërdrejt planifikuesit të bëjë punën tani, në vend që të presë një ditë.

Një pikë tjetër e rëndësishme është sigurimi i tolerancës së gabimeve. Fisheku përdor protokollin SWIM për të monitoruar shëndetin [4]. Shkurtimisht, proceset shkëmbejnë "thashetheme" me njëri-tjetrin mbi PZHU - secili proces u tregon fqinjëve të tij lajmet më të fundit dhe ata përgjigjen. Nëse papritmas përgjigja nuk vjen, Tarantool fillon të dyshojë se diçka nuk është në rregull, dhe pas një kohe ai reciton vdekjen dhe fillon t'u tregojë të gjithëve rreth këtij lajmi.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Bazuar në këtë protokoll, Cartridge organizon përpunimin automatik të dështimit. Çdo proces monitoron mjedisin e tij dhe nëse lideri papritmas ndalon së përgjigjuri, kopja mund të marrë përsipër rolin e tij dhe Cartridge konfiguron rolet e ekzekutimit në përputhje me rrethanat.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Këtu duhet të jeni të kujdesshëm, sepse ndërrimi i shpeshtë përpara dhe mbrapa mund të çojë në konflikte të të dhënave gjatë replikimit. Sigurisht, nuk duhet të aktivizoni dështimin automatik në mënyrë të rastësishme. Ne duhet të kuptojmë qartë se çfarë po ndodh dhe të jemi të sigurt që përsëritja nuk do të prishet pasi udhëheqësi të rivendoset dhe kurora t'i kthehet atij.

Nga e gjithë kjo, ju mund të merrni ndjenjën se rolet janë të ngjashme me mikroshërbimet. Në një farë kuptimi, ato janë vetëm kaq, vetëm si module brenda proceseve të Tarantool. Por ka edhe një sërë dallimesh thelbësore. Së pari, të gjitha rolet e projektit duhet të jetojnë në të njëjtën bazë kodi. Dhe të gjitha proceset e Tarantool duhet të nisen nga e njëjta bazë kodi, në mënyrë që të mos ketë surpriza si ato kur përpiqemi të inicializojmë planifikuesin, por ai thjesht nuk ekziston. Gjithashtu, nuk duhet të lejoni dallime në versionet e kodit, sepse sjellja e sistemit në një situatë të tillë është shumë e vështirë për t'u parashikuar dhe korrigjuar.

Ndryshe nga Docker, ne nuk mund të marrim thjesht një "imazh" roli, ta çojmë atë në një makinë tjetër dhe ta ekzekutojmë atje. Rolet tona nuk janë aq të izoluara sa kontejnerët Docker. Gjithashtu, ne nuk mund të ekzekutojmë dy role identike në një shembull. Një rol ose ekziston ose nuk ekziston; në një farë kuptimi, ai është një i vetëm. Dhe së treti, rolet duhet të jenë të njëjta brenda të gjithë grupit të replikimit, sepse përndryshe do të ishte absurde - të dhënat janë të njëjta, por konfigurimi është i ndryshëm.

Mjetet e vendosjes

Unë premtova të tregoj se si Cartridge ndihmon vendosjen e aplikacioneve. Për ta bërë jetën më të lehtë për të tjerët, kornizë paketon paketa RPM:

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

Paketa e instaluar përmban pothuajse gjithçka që ju nevojitet: si aplikacionin ashtu edhe varësitë e instaluara. Tarantool gjithashtu do të mbërrijë në server si një varësi e paketës RPM dhe shërbimi ynë është gati për t'u nisur. Kjo bëhet përmes systemd, por së pari duhet të shkruani një konfigurim të vogël. Së paku, specifikoni URI-në e secilit proces. Tre janë të mjaftueshme për shembull.

$ 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

Këtu ka një nuancë interesante. Në vend që të specifikojmë vetëm portën e protokollit binar, ne specifikojmë të gjithë adresën publike të procesit duke përfshirë emrin e hostit. Kjo është e nevojshme në mënyrë që nyjet e grupimit të dinë se si të lidhen me njëra-tjetrën. Është një ide e keqe të përdoret 0.0.0.0 si adresa advertise_uri; ajo duhet të jetë një adresë IP e jashtme, jo një lidhje prizë. Pa të, asgjë nuk do të funksionojë, kështu që Cartridge thjesht nuk do t'ju lejojë të hapni një nyje me reklamën e gabuar.

Tani që konfigurimi është gati, mund të filloni proceset. Meqenëse një njësi sistematike e rregullt nuk lejon më shumë se një proces të fillojë, aplikacionet në Cartridge instalohen nga të ashtuquajturat. njësitë e instancuara që funksionojnë si kjo:

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

Në konfigurim, ne specifikuam portën HTTP në të cilën Cartridge shërben ndërfaqen në internet - 8080. Le të shkojmë tek ajo dhe të hedhim një vështrim:

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Ne shohim që edhe pse proceset po funksionojnë, ato nuk janë konfiguruar ende. Fisheku nuk e di ende se kush duhet të replikojë me kë dhe nuk mund të marrë një vendim vetë, kështu që pret veprimet tona. Por ne nuk kemi shumë zgjedhje: jeta e një grupi të ri fillon me konfigurimin e nyjës së parë. Më pas do t'i shtojmë të tjerët në grup, do t'u caktojmë role dhe në këtë pikë vendosja mund të konsiderohet e përfunduar me sukses.

Le të derdhim një gotë pijen tuaj të preferuar dhe të pushojmë pas një jave të gjatë pune. Aplikacioni mund të përdoret.

Fisheku Tarantool: copëtimi i një fundi Lua në tre rreshta

Rezultatet e

Cilat janë rezultatet? Provojeni, përdorni, lini komente, krijoni bileta në Github.

Referencat

[1] Tarantool » 2.2 » Referenca » Referenca e shkëmbinjve » Moduli vshard

[2] Si e zbatuam thelbin e biznesit të investimeve të Alfa-Bank bazuar në Tarantool

[3] Arkitektura e faturimit të gjeneratës së re: transformimi me kalimin në Tarantool

[4] SWIM - protokolli i ndërtimit të grupimeve

[5] GitHub - tarantool/fishek-cli

[6] GitHub - tarantool/fishek

Burimi: www.habr.com

Shto një koment