Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Sa Mail.ru Group mayroon kaming Tarantool - ito ay isang server ng application sa Lua, na nagdodoble din bilang isang database (o kabaligtaran?). Ito ay mabilis at cool, ngunit ang mga kakayahan ng isang server ay hindi pa rin walang limitasyon. Ang vertical scaling ay hindi rin isang panlunas sa lahat, kaya ang Tarantool ay may mga tool para sa horizontal scaling - ang vshard module [1]. Binibigyang-daan ka nitong mag-shard ng data sa ilang mga server, ngunit kailangan mong pag-usapan ito upang i-set up ito at ilakip ang lohika ng negosyo.

Magandang balita: nakakolekta kami ng ilang malalaking kuha (hal [2], [3]) at lumikha ng isa pang balangkas na makabuluhang magpapasimple sa solusyon sa problemang ito.

Tarantool Cartridge ay isang bagong balangkas para sa pagbuo ng mga kumplikadong distributed system. Pinapayagan ka nitong tumuon sa pagsulat ng lohika ng negosyo sa halip na lutasin ang mga problema sa imprastraktura. Sa ibaba ng hiwa sasabihin ko sa iyo kung paano gumagana ang balangkas na ito at kung paano magsulat ng mga ipinamamahaging serbisyo gamit ito.

Ano nga ba ang problema?

Mayroon kaming tarantula, mayroon kaming vshard - ano pa ang gusto mo?

Una, ito ay isang bagay ng kaginhawaan. Ang configuration ng vshard ay na-configure sa pamamagitan ng mga talahanayan ng Lua. Para gumana nang tama ang isang distributed system ng maraming proseso ng Tarantool, dapat pareho ang configuration sa lahat ng dako. Walang gustong gawin ito nang manu-mano. Samakatuwid, lahat ng uri ng mga script, Ansible, at mga deployment system ay ginagamit.

Ang Cartridge mismo ang namamahala sa configuration ng vshard, ginagawa nito ito batay sa nito sariling distributed configuration. Ito ay mahalagang isang simpleng YAML file, isang kopya nito ay naka-imbak sa bawat halimbawa ng Tarantool. Ang pagpapasimple ay ang mismong balangkas na sinusubaybayan ang pagsasaayos nito at tinitiyak na pareho ito sa lahat ng dako.

Pangalawa, ito ay muli ng kaginhawaan. Ang pagsasaayos ng vshard ay walang kinalaman sa pagbuo ng lohika ng negosyo at nakakagambala lamang sa programmer mula sa kanyang trabaho. Kapag tinatalakay natin ang arkitektura ng isang proyekto, madalas nating pinag-uusapan ang mga indibidwal na bahagi at ang kanilang pakikipag-ugnayan. Masyado pang maaga para isipin ang tungkol sa paglulunsad ng isang cluster sa 3 data center.

Nalutas namin ang mga problemang ito nang paulit-ulit, at sa ilang sandali ay nagawa naming bumuo ng isang diskarte na pinasimple ang pagtatrabaho sa application sa buong ikot ng buhay nito: paglikha, pag-develop, pagsubok, CI/CD, pagpapanatili.

Ipinakilala ng Cartridge ang konsepto ng isang tungkulin para sa bawat proseso ng Tarantool. Ang mga tungkulin ay isang konsepto na nagbibigay-daan sa isang developer na tumuon sa pagsusulat ng code. Ang lahat ng mga tungkulin na magagamit sa proyekto ay maaaring patakbuhin sa isang halimbawa ng Tarantool, at ito ay magiging sapat para sa mga pagsubok.

Mga pangunahing tampok ng Tarantool Cartridge:

  • awtomatikong cluster orkestra;
  • pagpapalawak ng pag-andar ng application gamit ang mga bagong tungkulin;
  • template ng application para sa pagbuo at pag-deploy;
  • built-in na awtomatikong sharding;
  • pagsasama sa balangkas ng pagsusuri ng Luatest;
  • pamamahala ng kumpol gamit ang WebUI at API;
  • packaging at deployment tool.

Kumusta, Mundo!

Hindi ako makapaghintay na ipakita ang mismong framework, kaya iiwan natin ang kuwento tungkol sa arkitektura para sa ibang pagkakataon at magsimula sa isang bagay na simple. Kung ipagpalagay natin na ang Tarantool mismo ay naka-install na, ang natitira ay gawin

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

Ang dalawang command na ito ay mag-i-install ng command line utilities at magbibigay-daan sa iyong lumikha ng iyong unang application mula sa template:

$ cartridge create --name myapp

At ito ang makukuha natin:

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/

Ito ay isang git repository na may handa na "Hello, World!" aplikasyon. Subukan nating patakbuhin ito kaagad, na dati nang na-install ang mga dependencies (kabilang ang mismong balangkas):

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

Kaya, mayroon kaming isang node na tumatakbo para sa hinaharap na sharded na application. Ang isang matanong na karaniwang tao ay maaaring agad na magbukas ng web interface, mag-configure ng isang kumpol ng isang node gamit ang mouse at tamasahin ang resulta, ngunit ito ay masyadong maaga upang magalak. Sa ngayon, ang application ay hindi maaaring gumawa ng anumang bagay na kapaki-pakinabang, kaya sasabihin ko sa iyo ang tungkol sa pag-deploy sa ibang pagkakataon, ngunit ngayon ay oras na upang magsulat ng code.

Pagbuo ng Application

Isipin mo lang, nagdidisenyo kami ng isang proyekto na dapat makatanggap ng data, i-save ito at bumuo ng isang ulat isang beses sa isang araw.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Nagsisimula kaming gumuhit ng isang diagram at naglalagay ng tatlong bahagi dito: gateway, storage at scheduler. Patuloy kaming nagtatrabaho sa arkitektura. Dahil ginagamit namin ang vshard bilang storage, nagdaragdag kami ng vshard-router at vshard-storage sa scheme. Hindi direktang maa-access ng gateway o ng scheduler ang storage; para iyon sa router, para sa kung ano ito nilikha.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Ang diagram na ito ay hindi pa rin eksaktong kumakatawan sa kung ano ang gagawin namin sa proyekto dahil ang mga bahagi ay mukhang abstract. Kailangan pa rin nating makita kung paano ito ipapakita sa totoong Tarantool - pagpangkatin natin ang ating mga bahagi ayon sa proseso.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

May maliit na punto sa pagpapanatili ng vshard-router at gateway sa magkahiwalay na pagkakataon. Bakit kailangan nating mag-surf muli sa network kung ito ay responsibilidad na ng router? Dapat silang patakbuhin sa loob ng parehong proseso. Ibig sabihin, parehong gateway at vshard.router.cfg ay sinisimulan sa isang proseso, at hayaan silang makipag-ugnayan nang lokal.

Sa yugto ng disenyo, ito ay maginhawa upang gumana sa tatlong mga bahagi, ngunit ako, bilang isang developer, habang isinusulat ang code, ay hindi nais na isipin ang tungkol sa paglulunsad ng tatlong mga pagkakataon ng Tarnatool. Kailangan kong magpatakbo ng mga pagsubok at suriin kung isinulat ko nang tama ang gateway. O baka gusto kong magpakita ng feature sa aking mga kasamahan. Bakit ako dapat dumaan sa abala sa pag-deploy ng tatlong kopya? Ito ay kung paano ipinanganak ang konsepto ng mga tungkulin. Ang tungkulin ay isang regular na modulong luash na ang siklo ng buhay ay pinamamahalaan ng Cartridge. Sa halimbawang ito mayroong apat sa kanila - gateway, router, storage, scheduler. Maaaring marami pa sa ibang proyekto. Ang lahat ng mga tungkulin ay maaaring patakbuhin sa isang proseso, at ito ay magiging sapat na.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

At pagdating sa deployment sa staging o production, itatalaga namin ang bawat proseso ng Tarantool ng sarili nitong hanay ng mga tungkulin depende sa mga kakayahan ng hardware:

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Pamamahala ng topology

Ang impormasyon tungkol sa kung aling mga tungkulin ang tumatakbo ay dapat na nakaimbak sa isang lugar. At ang "sa isang lugar" na ito ay ang ipinamahagi na pagsasaayos, na nabanggit ko na sa itaas. Ang pinakamahalagang bagay tungkol dito ay ang cluster topology. Narito ang 3 pangkat ng pagtitiklop ng 5 proseso ng Tarantool:

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Hindi namin gustong mawalan ng data, kaya tinatrato namin nang may pag-iingat ang impormasyon tungkol sa pagpapatakbo ng mga proseso. Sinusubaybayan ng Cartridge ang configuration gamit ang two-phase commit. Kapag gusto naming i-update ang configuration, susuriin muna nito kung available ang lahat ng instance at handa nang tanggapin ang bagong configuration. Pagkatapos nito, ang pangalawang yugto ay inilalapat ang config. Kaya, kahit na ang isang kopya ay lumabas na pansamantalang hindi magagamit, walang masamang mangyayari. Ang pagsasaayos ay hindi lamang ilalapat at makakakita ka ng isang error nang maaga.

Gayundin sa seksyon ng topology, ang isang mahalagang parameter bilang pinuno ng bawat pangkat ng pagtitiklop ay ipinahiwatig. Kadalasan ito ang kopya na nire-record. Ang iba ay kadalasang read-only, bagama't maaaring may mga exception. Minsan ang mga matapang na developer ay hindi natatakot sa mga salungatan at maaaring magsulat ng data sa ilang mga replika nang magkatulad, ngunit may ilang mga operasyon na, kahit na ano, ay hindi dapat gawin nang dalawang beses. Para dito mayroong isang tanda ng isang pinuno.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Buhay ng mga tungkulin

Para umiral ang isang abstract na papel sa naturang arkitektura, dapat na pamahalaan ang mga ito sa anumang paraan. Natural, ang kontrol ay nangyayari nang hindi na-restart ang proseso ng Tarantool. Mayroong 4 na callback para pamahalaan ang mga tungkulin. Ang Cartridge mismo ay tatawag sa kanila depende sa kung ano ang nakasulat sa ibinahagi na pagsasaayos nito, sa gayon ay inilalapat ang pagsasaayos sa mga partikular na tungkulin.

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

Ang bawat tungkulin ay may tungkulin init. Tinatawag ito nang isang beses kapag pinagana ang tungkulin o kapag na-restart ang Tarantool. Maginhawa doon, halimbawa, upang simulan ang box.space.create, o ang scheduler ay maaaring maglunsad ng ilang background fiber na magsasagawa ng trabaho sa ilang partikular na agwat ng oras.

Isang function init maaaring hindi sapat. Ang Cartridge ay nagbibigay-daan sa mga tungkulin na samantalahin ang ipinamahagi na pagsasaayos na ginagamit nito upang iimbak ang topology. Maaari kaming magdeklara ng bagong seksyon sa parehong configuration at mag-imbak ng fragment ng configuration ng negosyo dito. Sa aking halimbawa, maaaring ito ay isang schema ng data o mga setting ng iskedyul para sa tungkulin ng scheduler.

Cluster na tawag validate_config и apply_config sa tuwing nagbabago ang ipinamamahaging configuration. Kapag ang isang configuration ay inilapat sa pamamagitan ng isang two-phase commit, ang cluster ay tumitingin na ang bawat tungkulin ay handa nang tanggapin ang bagong configuration na ito at, kung kinakailangan, mag-uulat ng isang error sa user. Kapag ang lahat ay sumang-ayon na ang pagsasaayos ay normal, pagkatapos ay ang apply_config.

Gayundin ang mga tungkulin ay may pamamaraan stop, na kinakailangan upang linisin ang output ng tungkulin. Kung sasabihin nating hindi na kailangan ang scheduler sa server na ito, maaari nitong ihinto ang mga fibers na sinimulan nitong gamitin init.

Ang mga tungkulin ay maaaring makipag-ugnayan sa isa't isa. Nakasanayan na naming magsulat ng mga function call sa Lua, ngunit maaaring mangyari na ang isang partikular na proseso ay walang papel na kailangan namin. Upang mapadali ang mga tawag sa network, ginagamit namin ang rpc (remote procedure call) na auxiliary module, na binuo batay sa karaniwang netbox na binuo sa Tarantool. Maaari itong maging kapaki-pakinabang kung, halimbawa, gusto ng iyong gateway na direktang hilingin sa scheduler na gawin ang trabaho ngayon, sa halip na maghintay ng isang araw.

Ang isa pang mahalagang punto ay ang pagtiyak ng fault tolerance. Ginagamit ng Cartridge ang SWIM protocol upang subaybayan ang kalusugan [4]. Sa madaling sabi, ang mga proseso ay nagpapalitan ng "mga alingawngaw" sa isa't isa tungkol sa UDP-bawat proseso ay nagsasabi sa mga kapitbahay nito ng pinakabagong balita, at sila ay tumutugon. Kung biglang ang sagot ay hindi dumating, ang Tarantool ay nagsisimulang maghinala na may mali, at pagkaraan ng ilang sandali ay binibigkas nito ang kamatayan at nagsimulang sabihin sa lahat sa paligid ng balitang ito.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Batay sa protocol na ito, inaayos ng Cartridge ang awtomatikong pagpoproseso ng pagkabigo. Ang bawat proseso ay sinusubaybayan ang kapaligiran nito, at kung ang pinuno ay biglang huminto sa pagtugon, ang replica ay maaaring pumalit sa tungkulin nito, at ang Cartridge ay nagko-configure ng mga gumaganang tungkulin nang naaayon.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Kailangan mong mag-ingat dito, dahil ang madalas na paglipat-lipat ay maaaring humantong sa mga salungatan ng data sa panahon ng pagtitiklop. Siyempre, hindi mo dapat paganahin ang awtomatikong failover nang random. Dapat nating malinaw na maunawaan kung ano ang nangyayari at siguraduhing hindi masisira ang pagtitiklop pagkatapos maibalik ang pinuno at maibalik sa kanya ang korona.

Mula sa lahat ng ito, maaari mong maramdaman na ang mga tungkulin ay katulad ng mga microservice. Sa isang kahulugan, ganoon lang sila, bilang mga module sa loob ng mga proseso ng Tarantool. Ngunit mayroon ding isang bilang ng mga pangunahing pagkakaiba. Una, ang lahat ng mga tungkulin ng proyekto ay dapat na nakatira sa parehong base ng code. At ang lahat ng proseso ng Tarantool ay dapat na ilunsad mula sa parehong base ng code, upang walang mga sorpresa tulad ng kapag sinubukan nating simulan ang scheduler, ngunit hindi ito umiiral. Gayundin, hindi mo dapat payagan ang mga pagkakaiba sa mga bersyon ng code, dahil ang pag-uugali ng system sa ganoong sitwasyon ay napakahirap hulaan at i-debug.

Hindi tulad ng Docker, hindi lang tayo maaaring kumuha ng isang papel na "imahe", dalhin ito sa isa pang makina at patakbuhin ito doon. Ang aming mga tungkulin ay hindi kasing hiwalay ng mga container ng Docker. Gayundin, hindi tayo maaaring magpatakbo ng dalawang magkatulad na tungkulin sa isang pagkakataon. Ang isang tungkulin ay umiiral o wala; sa isang kahulugan, ito ay isang singleton. At pangatlo, ang mga tungkulin ay dapat na pareho sa loob ng buong pangkat ng pagtitiklop, dahil kung hindi, ito ay magiging walang katotohanan - ang data ay pareho, ngunit ang pagsasaayos ay naiiba.

Mga tool sa pag-deploy

Nangako akong ipakita kung paano nakakatulong ang Cartridge sa pag-deploy ng mga application. Upang gawing mas madali ang buhay para sa iba, ang framework packages ay RPM packages:

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

Ang naka-install na package ay naglalaman ng halos lahat ng kailangan mo: ang application at ang mga naka-install na dependencies. Darating din ang Tarantool sa server bilang dependency ng RPM package, at handa nang ilunsad ang aming serbisyo. Ginagawa ito sa pamamagitan ng systemd, ngunit kailangan mo munang magsulat ng kaunting pagsasaayos. Sa pinakamababa, tukuyin ang URI ng bawat proseso. Halimbawa, sapat na ang tatlo.

$ 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

Mayroong isang kawili-wiling nuance dito. Sa halip na tukuyin lamang ang binary protocol port, tinutukoy namin ang buong pampublikong address ng proseso kasama ang hostname. Ito ay kinakailangan upang malaman ng mga cluster node kung paano kumonekta sa isa't isa. Isang masamang ideya na gamitin ang 0.0.0.0 bilang advertise_uri address; ito ay dapat na isang panlabas na IP address, hindi isang socket bind. Kung wala ito, walang gagana, kaya hindi ka hahayaan ng Cartridge na maglunsad ng node na may maling advertise_uri.

Ngayon na ang pagsasaayos ay handa na, maaari mong simulan ang mga proseso. Dahil ang isang regular na systemd unit ay hindi nagpapahintulot ng higit sa isang proseso na magsimula, ang mga application sa Cartridge ay ini-install ng tinatawag na. instantiated unit na gumagana tulad nito:

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

Sa pagsasaayos, tinukoy namin ang HTTP port kung saan nagsisilbi ang Cartridge sa web interface - 8080. Pumunta tayo dito at tingnan:

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Nakikita namin na bagama't tumatakbo ang mga proseso, hindi pa sila na-configure. Ang kartutso ay hindi pa alam kung sino ang dapat magtiklop kung kanino at hindi maaaring gumawa ng desisyon sa sarili nitong, kaya ito ay naghihintay para sa aming mga aksyon. Ngunit wala kaming maraming pagpipilian: ang buhay ng isang bagong kumpol ay nagsisimula sa pagsasaayos ng unang node. Pagkatapos ay idaragdag namin ang iba sa cluster, magtatalaga sa kanila ng mga tungkulin, at sa puntong ito ay maituturing na matagumpay na nakumpleto ang deployment.

Ibuhos natin ang isang baso ng paborito mong inumin at magpahinga pagkatapos ng mahabang linggo ng trabaho. Maaaring gamitin ang application.

Tarantool Cartridge: sharding ng Lua backend sa tatlong linya

Mga resulta ng

Ano ang mga resulta? Subukan ito, gamitin ito, mag-iwan ng feedback, gumawa ng mga tiket sa Github.

sanggunian

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

[2] Paano namin ipinatupad ang core ng negosyo ng pamumuhunan ng Alfa-Bank batay sa Tarantool

[3] Bagong henerasyong arkitektura ng pagsingil: pagbabago sa paglipat sa Tarantool

[4] SWIM - protocol ng pagtatayo ng cluster

[5] GitHub - tarantool/cartridge-cli

[6] GitHub - tarantool/cartridge

Pinagmulan: www.habr.com

Magdagdag ng komento