A Mail.ru Groupnál van Tarantool - ez egy Lua alkalmazásszerver, amely adatbázisként is működik (vagy fordítva?). Gyors és menő, de egy szerver képességei még mindig nem korlátlanok. A függőleges skálázás szintén nem csodaszer, így a Tarantool rendelkezik a vízszintes méretezéshez szükséges eszközökkel – a vshard modullal
Jó hír: összegyűjtöttünk néhány nagy felvételt (pl
És pontosan mi a probléma?
Van egy tarantulánk, van vshardunk – mit kívánhat még?
Először is, ez kényelmi kérdés. A vshard konfiguráció Lua táblákon keresztül konfigurálható. A több Tarantool folyamatból álló elosztott rendszer megfelelő működéséhez a konfigurációnak mindenhol azonosnak kell lennie. Senki sem akarja ezt manuálisan megtenni. Ezért mindenféle szkriptet, Ansible-t és telepítési rendszert használnak.
A kazetta maga kezeli a vshard konfigurációt, ennek alapján teszi ezt saját elosztott konfiguráció. Lényegében egy egyszerű YAML-fájl, amelynek egy példányát minden Tarantool-példány tárolja. Az egyszerűsítés az, hogy maga a keretrendszer figyeli a konfigurációját, és biztosítja, hogy mindenhol ugyanaz legyen.
Másodszor, ez ismét a kényelem kérdése. A vshard konfigurációnak semmi köze az üzleti logika fejlesztéséhez, és csak elvonja a programozó figyelmét a munkájáról. Amikor egy projekt felépítéséről beszélünk, leggyakrabban az egyes összetevőkről és azok kölcsönhatásáról beszélünk. Túl korai még gondolkodni egy fürt 3 adatközpontból történő kiépítésén.
Újra és újra megoldottuk ezeket a problémákat, és valamikor sikerült egy olyan megközelítést kidolgoznunk, amely leegyszerűsítette az alkalmazással való munkát annak teljes életciklusa során: létrehozás, fejlesztés, tesztelés, CI/CD, karbantartás.
A Cartridge bemutatja a szerep fogalmát minden Tarantool folyamathoz. A szerepek olyan koncepció, amely lehetővé teszi a fejlesztő számára, hogy a kódírásra összpontosítson. A projektben elérhető összes szerepkör futtatható egy Tarantool-példányon, és ez elegendő lesz a tesztekhez.
A Tarantool kazetta főbb jellemzői:
- automatizált klaszter hangszerelés;
- az alkalmazás funkcionalitásának bővítése új szerepkörök segítségével;
- alkalmazássablon fejlesztéshez és telepítéshez;
- beépített automatikus szilánkolás;
- integráció a Luatest tesztelési keretrendszerrel;
- fürtkezelés WebUI és API használatával;
- csomagolási és telepítési eszközök.
Helló Világ!
Alig várom, hogy megmutassam magát a keretrendszert, így az építészetről szóló történetet későbbre hagyjuk, és valami egyszerűvel kezdjük. Ha feltételezzük, hogy maga a Tarantool már telepítve van, akkor nincs más hátra, mint a teendő
$ tarantoolctl rocks install cartridge-cli
$ export PATH=$PWD/.rocks/bin/:$PATH
Ez a két parancs telepíti a parancssori segédprogramokat, és lehetővé teszi az első alkalmazás létrehozását a sablonból:
$ cartridge create --name myapp
És ezt kapjuk:
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/
Ez egy git adattár, amely készen áll a „Hello, World!” felirattal. Alkalmazás. Próbáljuk meg azonnal futtatni, miután korábban telepítettük a függőségeket (beleértve magát a keretrendszert is):
$ tarantoolctl rocks make
$ ./init.lua --http-port 8080
Tehát van egy csomópontunk a jövőbeli megosztott alkalmazás számára. Egy érdeklődő laikus azonnal megnyithatja a webes felületet, konfigurálhat egy csomópontból álló klasztert az egérrel, és élvezheti az eredményt, de még korai örülni. Egyelőre az alkalmazás nem tud semmi hasznosat csinálni, ezért később mesélek a telepítésről, de most itt az ideje a kód írásának.
Alkalmazásfejlesztés
Képzelje el, egy olyan projektet tervezünk, amelynek naponta egyszer adatokat kell fogadnia, el kell mentenie és jelentést kell készítenie.
Elkezdünk rajzolni egy diagramot, és három komponenst helyezünk el rajta: átjárót, tárolót és ütemezőt. Dolgozunk tovább az építészeten. Mivel a vshard-ot tárolóként használjuk, a vshard-routert és a vshard-storage-t hozzáadjuk a sémához. Sem az átjáró, sem az ütemező nem fér hozzá közvetlenül a tárolóhoz; erre való az útválasztó, erre készült.
Ez a diagram még mindig nem mutatja pontosan, hogy mit fogunk építeni a projektben, mert az összetevők absztraktnak tűnnek. Még látnunk kell, hogyan vetül ez ki a valódi Tarantoolra – csoportosítsuk az összetevőinket folyamatok szerint.
Nincs értelme a vshard-routert és az átjárót külön példányokon tartani. Miért kell még egyszer szörfölni a hálózaton, ha ez már a router felelőssége? Ugyanabban a folyamatban kell futtatni őket. Ez azt jelenti, hogy az átjáró és a vshard.router.cfg egy folyamatban inicializálódik, és lehetővé teszi számukra, hogy helyileg kommunikáljanak egymással.
A tervezési szakaszban kényelmes volt három komponenssel dolgozni, de én, mint fejlesztő, a kód írása közben nem akarok a Tarnatool három példányának elindítására gondolni. Futtatnom kell teszteket, és ellenőriznem kell, hogy helyesen írtam-e be az átjárót. Vagy talán egy tulajdonságot szeretnék bemutatni a kollégáimnak. Miért kell végigcsinálnom a három példány telepítésével járó fáradságot? Így született meg a szerepek fogalma. A szerepkör egy normál luash modul, amelynek életciklusát a Cartridge kezeli. Ebben a példában négy közülük van - átjáró, útválasztó, tároló, ütemező. Egy másik projektben több is lehet. Minden szerep egy folyamatban futtatható, és ez elég lesz.
Ha pedig a gyártási vagy gyártási folyamatba való bevezetésről van szó, akkor minden Tarantool-folyamathoz hozzárendeljük a saját szerepköreit a hardver képességeitől függően:
Topológia kezelés
Valahol tárolni kell az arra vonatkozó információkat, hogy mely szerepkörök hol futnak. És ez a „valahol” az elosztott konfiguráció, amit fentebb már említettem. A legfontosabb dolog a fürt topológia. Íme 3 Tarantool-folyamat 5 replikációs csoportja:
Nem szeretnénk adatokat elveszíteni, ezért óvatosan kezeljük a futó folyamatokkal kapcsolatos információkat. A kazetta kétfázisú véglegesítéssel követi nyomon a konfigurációt. Miután frissíteni akarjuk a konfigurációt, először ellenőrzi, hogy minden példány elérhető-e, és készen áll-e az új konfiguráció elfogadására. Ezt követően a második fázis alkalmazza a konfigurációt. Így még ha egy példány átmenetileg elérhetetlennek bizonyul is, semmi rossz nem történik. A konfiguráció egyszerűen nem kerül alkalmazásra, és előre hibaüzenetet fog látni.
Szintén a topológia részben szerepel egy olyan fontos paraméter, mint az egyes replikációs csoportok vezetője. Általában ez a rögzítés alatt álló másolat. A többi legtöbbször csak olvasható, bár lehetnek kivételek. Néha a bátor fejlesztők nem félnek a konfliktusoktól, és párhuzamosan több replikába is írhatnak adatokat, de vannak olyan műveletek, amelyeket bármitől függetlenül nem szabad kétszer végrehajtani. Erre van egy vezető jele.
Szerepek élete
Ahhoz, hogy egy absztrakt szerep létezhessen egy ilyen architektúrában, a keretrendszernek kezelnie kell őket valahogy. A vezérlés természetesen a Tarantool folyamat újraindítása nélkül történik. A szerepek kezeléséhez 4 visszahívás áll rendelkezésre. Maga a kazetta hívja meg őket attól függően, hogy mi van írva az elosztott konfigurációjában, ezáltal alkalmazza a konfigurációt bizonyos szerepkörökre.
function init()
function validate_config()
function apply_config()
function stop()
Minden szerepnek megvan a maga funkciója init
. Egyszer hívják meg a szerepkör engedélyezésekor vagy a Tarantool újraindításakor. Ott kényelmes például a box.space.create inicializálása, vagy az ütemező elindíthat valamilyen háttérszálat, amely bizonyos időközönként munkát végez.
Egy funkció init
lehet, hogy nem elég. A kazetta lehetővé teszi a szerepkörök számára, hogy kihasználják a topológia tárolására használt elosztott konfiguráció előnyeit. Ugyanabban a konfigurációban deklarálhatunk egy új szakaszt, és tárolhatunk benne az üzleti konfiguráció egy töredékét. Példámban ez lehet egy adatséma vagy az ütemező szerep ütemezési beállításai.
Klaszterhívások validate_config
и apply_config
minden alkalommal, amikor az elosztott konfiguráció megváltozik. Amikor egy konfigurációt kétfázisú véglegesítéssel alkalmaznak, a fürt ellenőrzi, hogy minden szerep készen áll-e az új konfiguráció elfogadására, és ha szükséges, hibát jelent a felhasználónak. Ha mindenki egyetért abban, hogy a konfiguráció normális, akkor a apply_config
.
A szerepeknek is van módszerük stop
, amely a szerepkör kimenetének megtisztításához szükséges. Ha azt mondjuk, hogy ezen a szerveren már nincs szükség ütemezőre, akkor leállíthatja azokat a szálakat, amelyekkel elindult init
.
A szerepek kölcsönhatásba léphetnek egymással. Megszoktuk, hogy Lua-ban függvényhívásokat írunk, de előfordulhat, hogy egy adott folyamat nem rendelkezik a szükséges szereppel. A hálózaton keresztüli hívások megkönnyítésére az rpc (távoli eljáráshívás) segédmodult használjuk, amely a Tarantoolba épített szabványos netboxra épül. Ez akkor lehet hasznos, ha például az átjáró közvetlenül meg akarja kérni az ütemezőt a feladat azonnali elvégzésére, ahelyett, hogy várna egy napot.
Egy másik fontos szempont a hibatűrés biztosítása. A Cartridge a SWIM protokollt használja az állapot figyelésére
E protokoll alapján a Cartridge automatikus hibafeldolgozást szervez. Minden folyamat figyeli a környezetét, és ha a vezető hirtelen leállítja a válaszadást, a replika átveheti a szerepét, és a Cartridge ennek megfelelően konfigurálja a futó szerepeket.
Itt óvatosnak kell lenni, mert a gyakori oda-vissza váltás adatütközésekhez vezethet a replikáció során. Természetesen nem szabad véletlenszerűen engedélyezni az automatikus feladatátvételt. Világosan meg kell értenünk, mi történik, és biztosnak kell lennünk abban, hogy a replikáció nem fog megszakadni, miután a vezért helyreállítják és a koronát visszaadják neki.
Mindebből az az érzése támadhat, hogy a szerepek hasonlóak a mikroszolgáltatásokhoz. Bizonyos értelemben ezek csak a Tarantool folyamatokon belüli modulok. De van néhány alapvető különbség is. Először is, minden projektszerepkörnek ugyanabban a kódbázisban kell élnie. És az összes Tarantool folyamatot ugyanarról a kódbázisról kell elindítani, hogy ne érjenek olyan meglepetések, mint amikor megpróbáljuk inicializálni az ütemezőt, de az egyszerűen nem létezik. Ezenkívül nem szabad megengedni a kódverziók közötti különbségeket, mert a rendszer viselkedését ilyen helyzetben nagyon nehéz megjósolni és hibakeresni.
A Dockerrel ellentétben nem tudunk csak úgy felvenni egy szerep "képet", átvinni egy másik gépre és ott futtatni. A mi szerepeink nem olyan elszigeteltek, mint a Docker konténerek. Ezenkívül nem futtathatunk két azonos szerepet egy példányon. Egy szerep vagy létezik, vagy nem; bizonyos értelemben egy egyéniség. Harmadszor pedig, a szerepeknek azonosaknak kell lenniük a teljes replikációs csoporton belül, mert különben abszurd lenne – az adatok ugyanazok, de a konfiguráció más.
Telepítési eszközök
Megígértem, hogy megmutatom, hogyan segít a Cartridge alkalmazások telepítésében. Mások életének megkönnyítése érdekében a keretrendszer RPM-csomagokat csomagol:
$ cartridge pack rpm myapp -- упакует для нас ./myapp-0.1.0-1.rpm
$ sudo yum install ./myapp-0.1.0-1.rpm
A telepített csomag szinte mindent tartalmaz, amire szüksége van: az alkalmazást és a telepített függőségeket egyaránt. Az RPM-csomag függőségeként a Tarantool is megérkezik a szerverre, szolgáltatásunk pedig készen áll az indulásra. Ez a systemd-n keresztül történik, de először meg kell írni egy kis konfigurációt. Legalább minden folyamat URI-jét adja meg. Három elég például.
$ 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
Van itt egy érdekes árnyalat. Ahelyett, hogy csak a bináris protokollportot adnánk meg, a folyamat teljes nyilvános címét adjuk meg, beleértve a gazdagép nevét is. Erre azért van szükség, hogy a fürt csomópontjai tudják, hogyan kapcsolódjanak egymáshoz. Rossz ötlet a 0.0.0.0-t használni reklám_uri címként; ennek külső IP-címnek kell lennie, nem pedig socket bind-nek. Enélkül semmi sem fog működni, így a Cartridge egyszerűen nem engedi, hogy elindítson egy csomópontot rossz hirdetési_uri-val.
Most, hogy a konfiguráció készen áll, elindíthatja a folyamatokat. Mivel egy normál rendszeregység nem enged több folyamat elindítását, ezért a kazettán lévő alkalmazások telepítése az ún. példányosított egységek, amelyek így működnek:
$ sudo systemctl start myapp@router
$ sudo systemctl start myapp@storage_A
$ sudo systemctl start myapp@storage_B
A konfigurációban megadtuk azt a HTTP portot, amelyen a Cartridge a webes felületet szolgálja - 8080. Menjünk rá, és nézzük meg:
Látjuk, hogy bár a folyamatok futnak, még nincsenek konfigurálva. A patron még nem tudja, ki kivel replikáljon, és nem tud önállóan dönteni, ezért a mi cselekedeteinkre vár. De nincs sok választásunk: egy új klaszter élete az első csomópont konfigurációjával kezdődik. Ezután hozzáadjuk a többit a fürthöz, szerepeket rendelünk hozzájuk, és ezen a ponton a telepítés sikeresnek tekinthető.
Öntsünk egy pohár kedvenc italunkból, és lazítsunk egy hosszú munkahét után. Az alkalmazás használható.
Eredményei
Mik az eredmények? Próbálja ki, használja, hagyjon visszajelzést, hozzon létre jegyeket a Githubon.
referenciák
[1]
Forrás: will.com