Cartutx Tarantool: fragmentació de backend Lua en tres línies

Cartutx Tarantool: fragmentació de backend Lua en tres línies

A Mail.ru Group tenim Tarantool: aquest és un servidor d'aplicacions a Lua, que també és una base de dades combinada (o viceversa?). És ràpid i genial, però les possibilitats d'un sol servidor encara no són il·limitades. L'escala vertical tampoc és una panacea, de manera que Tarantool té eines per a l'escala horitzontal: el mòdul vshard [1]. Us permet dividir les dades entre diversos servidors, però heu de fer-hi un cop de mà per configurar-les i enganxar la lògica empresarial.

Bones notícies: hem recollit cons (per exemple [2], [3]) i va presentar un altre marc que simplificarà significativament la solució d'aquest problema.

Cartutx Tarantool és un nou marc per desenvolupar sistemes distribuïts complexos. Us permet centrar-vos a escriure lògica empresarial en lloc de resoldre problemes d'infraestructura. Sota el tall, us explicaré com funciona aquest marc i com escriure serveis distribuïts amb ell.

I quin és, exactament, el problema?

Tenim una taràntula, tenim un vshard, què més pots desitjar?

En primer lloc, és una qüestió de comoditat. La configuració de vshard es configura mitjançant taules Lua. Perquè un sistema distribuït de múltiples processos Tarantool funcioni correctament, la configuració ha de ser la mateixa a tot arreu. Ningú vol fer-ho manualment. Per tant, s'utilitzen tot tipus de scripts, Ansible, sistemes de desplegament.

El cartutx gestiona la pròpia configuració de vshard, ho fa pel seu compte configuració distribuïda pròpia. Bàsicament, és un fitxer YAML senzill, una còpia del qual s'emmagatzema a cada instància de Tarantool. La simplificació rau en el fet que el propi marc supervisa la seva configuració i assegura que sigui igual a tot arreu.

En segon lloc, torna a ser una qüestió de comoditat. La configuració de vshard no té res a veure amb el desenvolupament de la lògica empresarial i només distreu el programador de la feina. Quan parlem de l'arquitectura d'un projecte, sovint estem parlant de components individuals i la seva interacció. És massa aviat per pensar en desplegar un clúster per a 3 centres de dades.

Aquests problemes els vam resoldre una rere l'altra, i en algun moment vam aconseguir desenvolupar un enfocament que ens permeti simplificar el treball amb l'aplicació al llarg de tot el seu cicle de vida: creació, desenvolupament, proves, CI/CD, manteniment.

Cartridge introdueix el concepte d'un paper per a cada procés de Tarantool. Els rols són el concepte que permet al desenvolupador centrar-se a escriure codi. Tots els rols disponibles al projecte es poden executar en una sola instància de Tarantool, i això serà suficient per a les proves.

Característiques principals del cartutx Tarantool:

  • orquestració de clúster automatitzada;
  • ampliar la funcionalitat de l'aplicació amb nous rols;
  • plantilla d'aplicació per al desenvolupament i desplegament;
  • fragmentació automàtica integrada;
  • integració amb el marc de proves Luatest;
  • gestió de clúster mitjançant WebUI i API;
  • eines d'embalatge i desplegament.

Hola món!

No puc esperar per mostrar el marc en si, així que deixarem la història sobre l'arquitectura per a més endavant i començarem senzill. Suposant que Tarantool ja està instal·lat, l'únic que queda per fer és

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

Aquestes dues ordres instal·laran les utilitats de la línia d'ordres i us permetran crear la vostra primera aplicació a partir de la plantilla:

$ cartridge create --name myapp

I això és el que obtenim:

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/

Aquest és un repositori git amb "Hello, World!" aplicació. Intentem executar-lo immediatament, després d'instal·lar les dependències (inclòs el marc en si mateix):

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

Per tant, tenim un node de la futura aplicació fragmentada en execució. Un profe curiós pot obrir immediatament la interfície web, configurar un clúster des d'un node amb el ratolí i gaudir del resultat, però és massa aviat per alegrar-se. Fins ara, l'aplicació no sap com fer res útil, així que parlaré del desplegament més endavant, i ara és el moment d'escriure codi.

Desenvolupament d'aplicacions

Imagineu-vos que estem dissenyant un projecte que hauria de rebre dades, guardar-les i crear un informe un cop al dia.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Comencem a dibuixar el diagrama i hi col·loquem tres components: passarel·la, emmagatzematge i planificador. Estem treballant l'arquitectura. Com que fem servir vshard com a emmagatzematge, afegim vshard-router i vshard-storage a l'esquema. Ni la passarel·la ni el planificador accediran directament a l'emmagatzematge, hi ha un encaminador per a això, s'ha creat per a això.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Aquest diagrama encara no reflecteix amb exactitud el que crearem al projecte, perquè els components semblen abstractes. Encara hem de veure com es projecta això al Tarantool real: agrupem els nostres components per processos.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

No té gaire sentit mantenir l'encaminador vshard i la passarel·la en instàncies separades. Per què hem de tornar a passar per la xarxa, si això ja és responsabilitat de l'encaminador? S'han d'executar dins del mateix procés. És a dir, tant la passarel·la com vshard.router.cfg s'inicialitzen en un sol procés i els permeten interactuar localment.

En l'etapa de disseny, era convenient treballar amb tres components, però com a desenvolupador, mentre escrivia codi, no vull pensar en executar tres instàncies de Tarnatool. He de fer proves i comprovar que he escrit correctament la passarel·la. O potser vull demostrar una característica als meus companys. Per què m'he de preocupar de desplegar tres instàncies? Així va néixer el concepte de rols. Un rol és un mòdul de luash normal, el cicle de vida del qual està gestionat per Cartridge. En aquest exemple, n'hi ha quatre: passarel·la, encaminador, emmagatzematge i planificador. Potser n'hi ha més en un altre projecte. Tots els rols es poden executar en un sol procés, i això serà suficient.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

I quan es tracta de desplegament a la posada en escena o a la producció, assignarem a cada procés de Tarantool el seu propi conjunt de rols en funció de les capacitats del maquinari:

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Gestió de topologia

La informació sobre on s'executen quins rols s'ha d'emmagatzemar en algun lloc. I aquest "en algun lloc" és una configuració distribuïda, que ja he esmentat més amunt. El més important és la topologia del clúster. Aquí hi ha 3 grups de replicació de 5 processos de Tarantool:

Cartutx Tarantool: fragmentació de backend Lua en tres línies

No volem perdre dades, per això ens ocupem de la informació sobre els processos en execució. El cartutx fa un seguiment de la configuració amb una confirmació de dues fases. Tan bon punt volem actualitzar la configuració, primer comprova que totes les instàncies estiguin disponibles i llestes per acceptar la nova configuració. Després d'això, la segona fase aplica la configuració. Així, fins i tot si una còpia no està disponible temporalment, no passarà res dolent. La configuració simplement no s'aplicarà i veureu un error per endavant.

La secció de topologia també conté un paràmetre tan important com el líder de cada grup de replicació. Aquesta és normalment la instància a la qual s'escriu. La resta solen ser només de lectura, tot i que hi pot haver excepcions. De vegades, els desenvolupadors valents no tenen por dels conflictes i poden escriure dades a diverses rèpliques en paral·lel, però hi ha algunes operacions que, malgrat tot, no s'han de fer dues vegades. Per a això hi ha un signe de líder.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Vida de rols

Perquè existeixi un paper abstracte en aquesta arquitectura, el marc ha de gestionar-los d'alguna manera. Naturalment, la gestió es produeix sense reiniciar el procés de Tarantool. Hi ha 4 trucades per gestionar els rols. El propi cartutx els cridarà en funció del que hagi escrit a la configuració distribuïda, aplicant així la configuració a rols específics.

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

Cada rol té una funció init. Es crida una vegada quan s'habilita un rol o quan es reinicia Tarantool. Allà és convenient, per exemple, inicialitzar box.space.create, o el planificador pot iniciar alguna fibra de fons que realitzarà el treball a determinats intervals.

funció única init potser no n'hi ha prou. El cartutx permet que els rols aprofitin la configuració distribuïda que fa servir per emmagatzemar la topologia. Podem declarar una nova secció en la mateixa configuració i emmagatzemar-hi un fragment de configuració empresarial. En el meu exemple, pot ser un esquema de dades o una configuració de programació per al rol de planificador.

Trucades en clúster validate_config и apply_config cada vegada que canvia la configuració distribuïda. Quan s'aplica una configuració mitjançant una confirmació en dues fases, el clúster comprova que cada rol estigui preparat per acceptar aquesta nova configuració i informa d'un error a l'usuari si és necessari. Quan tothom estava d'acord que la configuració és normal, aleshores apply_config.

Els rols també tenen un mètode stopEl que és necessari per netejar els aspectes vitals del paper. Si diem que el planificador ja no és necessari en aquest servidor, pot aturar les fibres amb les quals va començar init.

Els rols poden interactuar entre ells. Estem acostumats a escriure trucades de funció en Lua, però pot passar que en aquest procés no hi hagi cap rol que necessitem. Per facilitar les trucades a la xarxa, utilitzem el mòdul auxiliar rpc (trucada de procediment remot), que es construeix sobre la base de la xarxa estàndard integrada a Tarantool. Això pot ser útil si, per exemple, la vostra passarel·la vol demanar directament al planificador que faci la feina ara mateix, en lloc d'esperar un dia.

Un altre punt important és garantir la tolerància a errors. El cartutx utilitza el protocol SWIM per controlar la salut [4]. En resum, els processos intercanvien "rumors" entre ells per UDP: cada procés informa als seus veïns les últimes notícies i aquests responen. Si de sobte la resposta no arriba, Tarantool comença a sospitar que alguna cosa no va bé, i al cap d'un temps recita la mort i comença a dir-li aquesta notícia a tothom.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Basant-se en aquest protocol, Cartridge organitza la gestió automàtica de fallades. Cada procés supervisa el seu entorn i, si el líder deixa de respondre de sobte, la rèplica pot assumir el seu paper i Cartridge configura els rols en execució en conseqüència.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Heu de tenir cura aquí, perquè els canvis freqüents d'anada i tornada poden provocar conflictes de dades durant la rèplica. Activar la failover automàtica a l'atzar, per descomptat, no val la pena. Heu d'entendre clarament què està passant i assegurar-vos que la replicació no es trencarà després que el líder hagi estat restaurat i se li torni la corona.

A partir de tot l'anterior, és possible que tingueu la sensació que els rols són com els microserveis. En cert sentit, són, només com a mòduls dins dels processos de Tarantool. Però també hi ha una sèrie de diferències fonamentals. En primer lloc, tots els rols del projecte han de conviure en la mateixa base de codi. I tots els processos de Tarantool s'han d'executar des de la mateixa base de codi perquè no hi hagi sorpreses com quan intentem inicialitzar el planificador, però simplement no existeix. A més, no hauríeu de permetre diferències en les versions del codi, perquè el comportament del sistema en aquesta situació és molt difícil de predir i depurar.

A diferència de Docker, no podem simplement prendre una "imatge" d'un paper, portar-lo a una altra màquina i executar-lo allà. Els nostres rols no estan tan aïllats com els contenidors Docker. A més, no podem executar dos rols idèntics a la mateixa instància. Un paper hi és o no hi és, en cert sentit és un singleton. I en tercer lloc, dins de tot el grup de rèplica, els rols han de ser els mateixos, perquè en cas contrari seria ridícul: les dades són les mateixes, però la configuració és diferent.

Eines de desplegament

Em vaig comprometre a mostrar com Cartridge ajuda a desplegar aplicacions. Per facilitar la vida als altres, el marc inclou paquets RPM:

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

El paquet instal·lat conté gairebé tot el que necessiteu: tant l'aplicació com les dependències de luash instal·lades. Tarantool també arribarà al servidor com a dependència del paquet RPM, i el nostre servei està a punt per ser llançat. Això es fa mitjançant systemd, però primer cal escriure una petita configuració. Com a mínim, especifiqueu l'URI de cada procés. N'hi ha prou amb tres com a exemple.

$ 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

Aquí hi ha un matís interessant. En lloc d'especificar només el port del protocol binari, especifiquem tota l'adreça pública del procés, inclòs el nom d'amfitrió. Això és necessari perquè els nodes del clúster sàpiguen connectar-se entre ells. És una mala idea utilitzar 0.0.0.0 com a advertise_uri, hauria de ser la IP pública, no el socket d'enllaç. Sense ell, res funcionarà, de manera que Cartridge simplement no us permetrà llançar un node amb un advertise_uri incorrecte.

Ara que la configuració està preparada, podeu iniciar els processos. Com que la unitat systemd habitual no permet que s'iniciï més d'un procés, les aplicacions del cartutx les instal·len l'anomenat. unitats instanciades que funcionen així:

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

A la configuració, hem especificat el port HTTP en què Cartridge serveix la interfície web: 8080. Anem-hi i veiem:

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Veiem que els processos, tot i que estan en execució, encara no estan configurats. El cartutx encara no sap qui ha de replicar amb qui i no pot prendre una decisió per si mateix, per la qual cosa està esperant les nostres accions. I no tenim gaire opció: la vida d'un nou clúster comença amb la configuració del primer node. A continuació, afegim la resta al clúster, els assignem rols i en aquest moment es pot considerar que el desplegament ha finalitzat amb èxit.

Aboca un got de la teva beguda preferida i relaxa't després d'una llarga setmana de treball. L'aplicació es pot operar.

Cartutx Tarantool: fragmentació de backend Lua en tres línies

Resultats de

I què passa amb els resultats? Prova, fes servir, deixa comentaris, inicia entrades a github.

Referències

[1] Tarantool » 2.2 » Referència » Referència de roques » Mòdul vshard

[2] Com hem implementat el nucli del negoci d'inversió d'Alfa-Bank basat en Tarantool

[3] Arquitectura de facturació de nova generació: transformació amb la transició a Tarantool

[4] SWIM - protocol de creació de clústers

[5] GitHub - tarantool/cartridge-cli

[6] GitHub - tarantool/cartutx

Font: www.habr.com

Afegeix comentari