Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Ons by Mail.ru Group het Tarantool - dit is 'n toepassingsbediener in Lua, wat ook 'n databasis in kombinasie is (of andersom?). Dit is vinnig en gaaf, maar die moontlikhede van 'n enkele bediener is steeds nie onbeperk nie. Vertikale skaal is ook nie 'n wondermiddel nie, so Tarantool het gereedskap vir horisontale skaal - die vshard-module [1]. Dit laat jou toe om data oor verskeie bedieners te verdeel, maar jy moet daarmee peuter om dit op te stel en besigheidslogika in te skroef.

Goeie nuus: ons het keëls versamel (byvoorbeeld [2], [3]) en 'n ander raamwerk ingedien wat die oplossing van hierdie probleem aansienlik sal vereenvoudig.

Tarantool patroon is 'n nuwe raamwerk vir die ontwikkeling van komplekse verspreide stelsels. Dit laat jou toe om te fokus op die skryf van besigheidslogika in plaas daarvan om infrastruktuurprobleme op te los. Onder die snit sal ek jou vertel hoe hierdie raamwerk werk en hoe om verspreide dienste daarmee te skryf.

En wat presies is die probleem?

Ons het 'n tarantula, ons het 'n vshard - wat meer wil jy hê?

Eerstens is dit 'n kwessie van gerief. Die vshard-konfigurasie word gekonfigureer via Lua-tabelle. Vir 'n verspreide stelsel van veelvuldige Tarantool-prosesse om korrek te werk, moet die konfigurasie oral dieselfde wees. Niemand wil dit met die hand doen nie. Daarom word allerhande skrifte, Ansible, ontplooiingstelsels gebruik.

Cartridge bestuur die vshard-konfigurasie self, dit doen dit op sy eie eie verspreide konfigurasie. Basies is dit 'n eenvoudige YAML-lêer, waarvan 'n kopie in elke geval van Tarantool gestoor word. Die vereenvoudiging lê daarin dat die raamwerk self sy konfigurasie monitor en verseker dat dit oral dieselfde is.

Tweedens is dit weer 'n kwessie van gerief. Die vshard-konfigurasie het niks te doen met die ontwikkeling van besigheidslogika nie en lei net die programmeerder se aandag van die werk af. Wanneer ons die argitektuur van 'n projek bespreek, praat ons meestal van individuele komponente en hul interaksie. Dit is te vroeg om te dink oor die uitrol van 'n groepering vir 3 datasentrums.

Ons het hierdie probleme keer op keer opgelos, en op 'n stadium het ons daarin geslaag om 'n benadering te ontwikkel wat ons in staat stel om die werk met die toepassing deur sy hele lewensiklus te vereenvoudig: skepping, ontwikkeling, toetsing, CI / CD, instandhouding.

Cartridge stel die konsep van 'n rol vir elke Tarantool-proses bekend. Rolle is die konsep wat die ontwikkelaar toelaat om te fokus op die skryf van kode. Alle rolle wat in die projek beskikbaar is, kan op 'n enkele instansie van Tarantool uitgevoer word, en dit sal genoeg wees vir toetse.

Belangrikste kenmerke van Tarantool Cartridge:

  • outomatiese trosorkestrasie;
  • uitbreiding van toepassingsfunksionaliteit met nuwe rolle;
  • toepassingsjabloon vir ontwikkeling en ontplooiing;
  • ingeboude outomatiese versnippering;
  • integrasie met die Luatest toetsraamwerk;
  • groepbestuur met behulp van WebUI en API;
  • verpakking en ontplooiing gereedskap.

Hello Wêreld!

Ek kan nie wag om die raamwerk self te wys nie, so ons laat die storie oor die argitektuur vir later, en begin eenvoudig. As ons aanvaar dat Tarantool self reeds geïnstalleer is, is die enigste ding om te doen

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

Hierdie twee opdragte sal die opdragreëlhulpmiddels installeer en jou toelaat om jou eerste toepassing vanaf die sjabloon te skep:

$ cartridge create --name myapp

En dit is wat ons kry:

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/

Dit is 'n git-bewaarplek met "Hallo, Wêreld!" aansoek. Kom ons probeer dadelik om dit uit te voer, nadat ons die afhanklikhede geïnstalleer het (insluitend die raamwerk self):

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

Dus, ons het een knooppunt van die toekomstige versnipperde toepassing wat loop. 'n Nuuskierige leek kan dadelik die webkoppelvlak oopmaak, 'n groepering vanaf een nodus met die muis konfigureer en die resultaat geniet, maar dit is te vroeg om bly te wees. Tot dusver weet die toepassing nie hoe om iets nuttigs te doen nie, so ek sal later oor ontplooiing praat, en nou is dit tyd om kode te skryf.

Toepassingsontwikkeling

Stel jou net voor, ons ontwerp 'n projek wat data moet ontvang, stoor en een keer per dag 'n verslag moet bou.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Ons begin die diagram teken en plaas drie komponente daarop: poort, berging en skeduleerder. Ons werk aan die argitektuur. Aangesien ons vshard as berging gebruik, voeg ons vshard-router en vshard-berging by die skema. Nie die poort of die skeduleerder sal direk toegang tot die berging kry nie, daar is 'n router hiervoor, dit is hiervoor geskep.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Hierdie diagram weerspieël steeds nie heeltemal akkuraat wat ons in die projek gaan skep nie, want die komponente lyk abstrak. Ons moet nog sien hoe dit op die regte Tarantool geprojekteer word - kom ons groepeer ons komponente volgens prosesse.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Dit maak min sin om vshard-router en gateway op aparte gevalle te hou. Hoekom moet ons weer oor die netwerk gaan, as dit reeds die verantwoordelikheid van die router is? Hulle moet binne dieselfde proses uitgevoer word. Dit wil sê, beide gateway en vshard.router.cfg word in een proses geïnisialiseer, en laat hulle plaaslik interaksie hê.

Op die ontwerpstadium was dit gerieflik om met drie komponente te werk, maar as 'n ontwikkelaar, terwyl ek kode skryf, wil ek nie daaraan dink om drie instansies van Tarnatool te laat loop nie. Ek moet toetse uitvoer en seker maak dat ek gateway korrek gespel het. Of miskien wil ek 'n kenmerk aan my kollegas demonstreer. Hoekom moet ek die moeite doen om drie gevalle te ontplooi? Dit is hoe die konsep van rolle gebore is. 'n Rol is 'n gereelde luash-module, waarvan die lewensiklus deur Cartridge bestuur word. In hierdie voorbeeld is daar vier van hulle - poort, router, berging, skeduleerder. Daar is dalk meer in 'n ander projek. Alle rolle kan in een proses uitgevoer word, en dit sal genoeg wees.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

En wanneer dit kom by die ontplooiing na opvoering of produksie, sal ons elke Tarantool-proses sy eie stel rolle toewys, afhangende van die hardeware-vermoëns:

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Topologiebestuur

Inligting oor waar watter rolle loop, moet iewers gestoor word. En hierdie "iewers" is 'n verspreide konfigurasie, wat ek reeds hierbo genoem het. Die belangrikste ding daarin is die topologie van die cluster. Hier is 3 replikasiegroepe van 5 Tarantool-prosesse:

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Ons wil nie data verloor nie, so ons sorg vir inligting oor lopende prosesse. Cartridge hou tred met die konfigurasie met 'n twee-fase commit. Sodra ons die konfigurasie wil opdateer, kyk dit eers of alle gevalle beskikbaar is en gereed is om die nuwe konfigurasie te aanvaar. Daarna pas die tweede fase die config toe. Dus, selfs al is een kopie tydelik onbeskikbaar, sal niks sleg gebeur nie. Die konfigurasie sal eenvoudig nie van toepassing wees nie en u sal vooraf 'n fout sien.

Die topologie-afdeling bevat ook so 'n belangrike parameter as die leier van elke replikasiegroep. Dit is gewoonlik die instansie waarna geskryf word. Die res is meestal leesalleen, hoewel daar uitsonderings kan wees. Soms is dapper ontwikkelaars nie bang vir konflikte nie en kan data parallel na verskeie replikas skryf, maar daar is 'n paar bewerkings wat, ten spyte van alles, nie twee keer uitgevoer moet word nie. Hiervoor is daar 'n teken van 'n leier.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Lewe van rolle

Om 'n abstrakte rol in so 'n argitektuur te laat bestaan, moet die raamwerk dit op een of ander manier bestuur. Natuurlik vind bestuur plaas sonder om die Tarantool-proses te herbegin. Daar is 4 terugbelopings vir die bestuur van rolle. Cartridge self sal hulle noem, afhangende van wat dit in die verspreide konfigurasie geskryf het, en sodoende die konfigurasie op spesifieke rolle toepas.

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

Elke rol het 'n funksie init. Dit word een keer genoem óf wanneer 'n rol geaktiveer is óf wanneer Tarantool herbegin word. Daar is dit gerieflik om byvoorbeeld box.space.create te inisialiseer, of die skeduleerder kan 'n bietjie agtergrondvesel begin wat werk met sekere intervalle sal verrig.

enkele funksie init dalk nie genoeg nie. Cartridge laat rolle toe om voordeel te trek uit die verspreide konfigurasie wat dit gebruik om die topologie te stoor. Ons kan 'n nuwe afdeling in dieselfde konfigurasie verklaar en 'n besigheidsopsetfragment daarin stoor. In my voorbeeld kan dit 'n dataskema wees, of skeduleinstellings vir die skeduleerderrol.

Groepoproepe validate_config и apply_config elke keer as die verspreide konfigurasie verander. Wanneer 'n konfigurasie toegepas word deur 'n twee-fase commit, kontroleer die groepering dat elke rol gereed is om hierdie nuwe konfigurasie te aanvaar en rapporteer 'n fout aan die gebruiker indien nodig. Toe almal saamgestem het dat die konfigurasie normaal is, dan is die apply_config.

Rolle het ook 'n metode stopDie wat nodig is om die noodsaaklikhede van die rol skoon te maak. As ons sê dat die skeduleerder nie meer op hierdie bediener nodig is nie, kan dit daardie vesels stop waarmee dit begin het init.

Rolle kan interaksie met mekaar hê. Ons is gewoond daaraan om funksie-oproepe in Lua te skryf, maar dit kan gebeur dat daar in hierdie proses geen rol is wat ons nodig het nie. Om oproepe oor die netwerk te fasiliteer, gebruik ons ​​die rpc (remote procedure call) hulpmodule, wat gebou is op die basis van die standaard netboks wat in Tarantool ingebou is. Dit kan nuttig wees as byvoorbeeld jou gateway die skeduleerder direk wil vra om die werk dadelik te doen, eerder as om vir 'n dag te wag.

Nog 'n belangrike punt is om foutverdraagsaamheid te verseker. Cartridge gebruik die SWIM-protokol om gesondheid te monitor [4]. Kortom, prosesse ruil "gerugte" met mekaar oor UDP - elke proses vertel sy bure die jongste nuus, en hulle reageer. As die antwoord skielik nie gekom het nie, begin Tarantool vermoed dat iets verkeerd is, en na 'n rukkie sê hy die dood op en begin almal rondom hierdie nuus vertel.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Gebaseer op hierdie protokol, organiseer Cartridge outomatiese fouthantering. Elke proses monitor sy omgewing, en as die leier skielik ophou reageer, dan kan die replika sy rol oorneem, en Cartridge konfigureer die lopende rolle dienooreenkomstig.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Jy moet hier versigtig wees, want gereelde heen-en-weer skakeling kan tot datakonflik tydens replikasie lei. Om outomatiese failover lukraak aan te skakel, is natuurlik nie die moeite werd nie. Jy moet duidelik verstaan ​​wat gebeur, en seker wees dat replikasie nie sal breek nadat die leier herstel is en die kroon aan hom terugbesorg is nie.

Uit al die bogenoemde kan jy die gevoel kry dat rolle soos mikrodienste is. In 'n sekere sin is hulle slegs as modules binne Tarantool-prosesse. Maar daar is ook 'n aantal fundamentele verskille. Eerstens moet alle projekrolle in dieselfde kodebasis woon. En alle Tarantool-prosesse moet vanaf dieselfde kodebasis loop sodat daar geen verrassings is soos wanneer ons probeer om die skeduleerder te inisialiseer nie, maar dit bestaan ​​eenvoudig nie. U moet ook nie verskille in kodeweergawes toelaat nie, want die gedrag van die stelsel in so 'n situasie is baie moeilik om te voorspel en te ontfout.

Anders as Docker, kan ons nie net 'n "beeld" van 'n rol neem, dit na 'n ander masjien neem en dit daar laat loop nie. Ons rolle is nie so geïsoleer soos Docker-houers nie. Ons kan ook nie twee identiese rolle op dieselfde instansie speel nie. 'n Rol is óf daar óf dit is nie, in 'n sekere sin is dit 'n enkeling. En derdens, binne die hele replikasiegroep moet die rolle dieselfde wees, want anders sou dit belaglik wees – die data is dieselfde, maar die konfigurasie is anders.

Ontplooiingsnutsgoed

Ek het belowe om te wys hoe Cartridge help om toepassings te ontplooi. Om die lewe vir ander makliker te maak, pak die raamwerk RPM-pakkette:

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

Die geïnstalleerde pakket bevat byna alles wat jy nodig het: beide die toepassing en die geïnstalleerde luash-afhanklikhede. Tarantool sal ook op die bediener aankom as 'n afhanklikheid van die RPM-pakket, en ons diens is gereed om bekendgestel te word. Dit word gedoen deur systemd, maar eers moet jy 'n bietjie konfigurasie skryf. Spesifiseer ten minste die URI van elke proses. Drie is genoeg vir 'n voorbeeld.

$ 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

Hier is 'n interessante nuanse. In plaas daarvan om net die binêre protokolpoort te spesifiseer, spesifiseer ons die hele publieke adres van die proses, insluitend die gasheernaam. Dit is nodig sodat die cluster nodusse weet hoe om aan mekaar te koppel. Dit is 'n slegte idee om 0.0.0.0 as die advertise_uri te gebruik, dit moet die openbare IP wees, nie die bindsok nie. Daarsonder sal niks werk nie, so Cartridge sal jou eenvoudig nie toelaat om 'n nodus met 'n verkeerde advertise_uri te begin nie.

Noudat die konfigurasie gereed is, kan u die prosesse begin. Aangesien die gewone systemd-eenheid nie meer as een proses toelaat om te begin nie, word toepassings op die Cartridge geïnstalleer deur die sg. geïnstantieerde eenhede wat soos volg werk:

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

In die konfigurasie het ons die HTTP-poort gespesifiseer waarop Cartridge die webkoppelvlak bedien - 8080. Kom ons gaan daarna en kyk:

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Ons sien dat die prosesse, alhoewel hulle loop, nog nie gekonfigureer is nie. Die patroon weet nog nie wie met wie moet repliseer nie en kan nie op sy eie 'n besluit neem nie, so dit wag vir ons optrede. En ons het nie veel keuse nie: die lewe van 'n nuwe groep begin met die konfigurasie van die eerste nodus. Dan voeg ons die res by die groepering, ken rolle aan hulle toe, en op hierdie stadium kan die ontplooiing as suksesvol afgehandel beskou word.

Skink 'n glasie van jou gunstelingdrankie en ontspan na 'n lang werksweek. Die toepassing kan bedryf word.

Tarantool-patroon: Lua-agterkant wat in drie reëls geskeur word

Resultate van

En wat van die resultate? Probeer, gebruik, laat terugvoer, begin kaartjies op github.

verwysings

[1] Tarantool » 2.2 » Verwysing » Rocks verwysing » Module vshard

[2] Hoe ons die kern van Alfa-Bank se beleggingsbesigheid, gebaseer op Tarantool, geïmplementeer het

[3] Nuwe generasie faktuurargitektuur: transformasie met die oorgang na Tarantool

[4] SWIM - cluster bou protokol

[5] GitHub - tarantool/cartridge-cli

[6] GitHub - tarantool/patroon

Bron: will.com

Voeg 'n opmerking