Tere, ma teen rakendusi andmebaasihaldussĂŒsteemide jaoks â see on Mail.ru Group'i vĂ€lja töötatud platvorm, mis ĂŒhendab endas kĂ”rge jĂ”udlusega andmebaasihaldussĂŒsteemi ja rakenduste serveri Lua keeles. Tarantoolist pĂ”hinevate lahenduste kĂ”rge töökiirus saavutatakse osaliselt tĂ€nu in-memory andmebaasi reĆŸiimi toele ja vĂ”imalusele tĂ€ita rakenduse Ă€riloogikat samaaegselt andmetega ĂŒhes aadressiruumi. Samuti tagatakse andmete pĂŒsivus ACID-tehingute abil (plaadil peetakse WAL-logi). Tarantool toetab sisseehitatud replikeerimist ja shardingut. Alates versioonist 2.1 toetatakse SQL-kĂŒsitlusi. Tarantoolil on avatud lĂ€htekood ja see levib Simplified BSD litsentsi alusel. Samuti on olemas kommerts Enterprise-versioon.

Tunnetage jĂ”udu! (âŠehk nautige jĂ”udlust)
KÔik eeltoodud teeb Tarantoolist atraktiivse platvormi kÔrge koormusega andmebaasirakenduste loomiseks. Sellistes rakendustes tekib sageli vajadus andmete replikatsiooni jÀrele.
Nagu juba varem öeldi, on Tarantoolis sisseehitatud andmete replikatsioon. Selle tööpÔhimÔte pÔhineb kÔigi meistri (WAL) logis olevate tehingute jÀrjestikusel tÀitmisel replikatsioonides. Tavaliselt kasutatakse seda replikatsiooni (nimetame seda edasi madaltasemeliseks) rakenduse tÔrgeteta toimimise tagamiseks ja/vÔi koormuse jaotamiseks klastrite vahel.

Joonis 1. Replikatsioon klastris
Alternatiivse stsenaariumi nĂ€iteks vĂ”ib olla andmete edastamine, mis on loodud ĂŒhes andmebaasis, teise andmebaasi töötlemiseks/monitoreerimiseks. Viimasel juhul vĂ”ib mugavam lahendus olla kĂ”rgtasemeline replikatsioon â andmete replikatsioon Ă€ri loogika tasemel. See tĂ€hendab, et me ei kasuta valmis lahendust, mis on sisse ehitatud andmebaasihaldussĂŒsteemi, vaid ellu viime replikatsiooni meie loodud rakenduses. Sellel lĂ€henemisel on nii eelised kui ka puudused. Loetleme plusse.
1. Andmeside kokkuhoid:
- saab edastada mitte kÔiki andmeid, vaid ainult nende osa (nÀiteks saab edastada ainult teatud tabeleid, nende teatud veerge vÔi kirjeid, mis vastavad teatud kriteeriumile);
- erinevalt madala taseme replikatsioonist, mis toimub pidevalt asĂŒnkroonses (teostatud praeguses versioonis Tarantool â 1.10) vĂ”i sĂŒnkroonses (mis tehakse tulevastes versioonides Tarantool) reĆŸiimis, saab kĂ”rge taseme replikatsiooni teostada sessioonide kaupa (st rakendus esmalt sĂŒnkroniseerib andmeid â andmevahetuse sessioon, seejĂ€rel toimub replikatsiooni paus, pĂ€rast mida toimub jĂ€rgmine andmevahetuse sessioon jne);
- kui salvestust on mitu korda muudetud, saab edastada ainult selle viimase versiooni (erinevalt madala taseme replikatsioonist, kus jÀljendites jÀrk-jÀrgult esitletakse kÔik muudatused, mis on tehtud meistris).
2. Puuduvad keerukused HTTP vahetuse rakendamisel, mis vĂ”imaldab kauge DB-de sĂŒnkroonimist.

Joonis 2. Replikatsioon HTTP kaudu
3. Andmebaasi struktuurid, mille vahel andmeid edastatakse, ei pea olema identsed (veelgi enam, enamasti on vĂ”imalik kasutada isegi erinevaid andmebaasesĂŒsteeme, programmeerimiskeeli, platvorme jne).

Joonis 3. Replikatsioon heterogeensetes sĂŒsteemides
Miinus seisneb selles, et keskmiselt on programmeerimine keerulisem/kallim kui konfigureerimine, ja valmis funktsionaalsuse seadistamise asemel tuleb oma kujundada.
Kui teie olukorras mÀngivad nimetatud plussid otsustavat rolli (vÔi on vajalik tingimus), siis on mÔtet kasutada kÔrge taseme replikatsiooni. Vaatame mitmeid viise kÔrge taseme replikatsiooni rakendamiseks Tarantooli andmebaasides.
Liikluse minimeerimine
Seega on ĂŒks kĂ”rge taseme replikatsiooni eelistest liikluse kokkuhoid. Selle eelise tĂ€ielikuks vĂ€ljendamiseks on oluline minimeerida andmete mahtu, mis edastatakse igas andmevahetuse sessioonis. Loomulikult ei tohi unustada, et sessiooni lĂ”pus peab andmete vastuvĂ”tja olema sĂŒnkroonitud allikaga (vĂ€hemalt nende andmete osas, mis on seotud replikatsiooniga).
Kuidas aga minimeerida andmete hulka, mis edastatakse kĂ”rge taseme replikatsiooni kĂ€igus? Otsene lahendus vĂ”iks olla andmete valik kuupĂ€eva ja aja pĂ”hjal. Selleks saab kasutada juba tabelis olevat kuupĂ€eva-aja vĂ€lja (kui see on olemas). NĂ€iteks vĂ”ib dokumendil "tellimus" olla vĂ€lja "tellimuse tĂ€itmise nĂ”utud aeg" â tarneaeg. Selle lahenduse probleem seisneb selles, et selle vĂ€lja vÀÀrtused ei pruugi olla jĂ€rjestatud tellimuste loomise jĂ€rjekorras. Seega ei saa me meeles pidada vĂ€lja maksimaalset vÀÀrtust tarneaeg, mis oli edastatud eprevious vahetuse seansi ajal, ja jĂ€rgmise vahetuse seansi ajal filtreerida kĂ”ik kirjed, mille vĂ€lja vÀÀrtus on kĂ”rgem tarneaeg. Vahetuste vahel vĂ”ivad olla lisandunud kirjed, mille vĂ€lja vÀÀrtus on madalam tarneaeg. Samuti vĂ”is tellimus olla muutunud, kuigi see ei mĂ”jutanud vĂ€lja tarneaeg. MĂ”lemal juhul ei edastata muudatusi allikast vastuvĂ”tjale. Nende probleemide lahendamiseks peame andmeid edastama "ĂŒlekattega". See tĂ€hendab, et iga vahetuse seansi ajal edastame kĂ”ik andmed, mille vĂ€lja vÀÀrtus on tarneaeg, ĂŒletades mingi hetk minevikus (nĂ€iteks N tundi alates praegusest hetkest). Siiski on selge, et suurte sĂŒsteemide jaoks on selline lĂ€henemine tugevalt ĂŒlemÀÀrane ja vĂ”ib kaotada liikluse kokkuhoiu, mille poole me pĂŒĂŒdleme. Lisaks ei pruugi edastatavas tabelis olla vĂ€lja, mis on seotud kuupĂ€eva ja kellaajaga.
Teine lahendus, mis on rakendamise seisukohalt keerulisem, seisneb andmete vastuvÔtmise kinnitamises. Sel juhul edastatakse igal vahetuse seansil kÔik andmed, mille vastuvÔtmist ei ole vastuvÔtja kinnitanud. Selle rakendamiseks on vajalik lisada allika tabelisse bool kategooria (nÀiteks, is_transferred). Kui vastuvÔtja kinnitab kirje saamist, saab vastav vÀli vÀÀrtuse true, pÀrast mida see kirje enam vahetustes ei osale. Selle rakendamise variandil on jÀrgmised puudused. Esiteks on vajalik iga edastatud kirje jaoks genereerida ja saata kinnitus. Lihtsalt öeldes vÔib see olla vÔrreldav edastatavate andmete mahu kahekordistamisega ning viia ka kahepoolsete ringide arvu kahekordistumiseni. Teiseks puudub vÔimalus edastada sama kirjet mitmele vastuvÔtjale (esimene vastuvÔtja, kes on selle saanud, kinnitab saamise enda ja kÔigi teiste eest).
TĂ”hus viis, mis ei sisalda eeltoodud puudusi, seisneb edastatavas tabelis muudatuste jĂ€lgimise veeru lisamises. See veerg vĂ”ib olla kuupĂ€ev-aeg ja peab olema rakenduse poolt seadistatud/uuendatud praegustele aegadele iga kord, kui andmeid lisatakse/vĂ”i muudetakse (aatomaarse lisamise/muutmisega). NĂ€iteks nimetame veerg update_time. Salvestades selle veeru maksimaalse vÀÀrtuse edastatud ridade jaoks, saame alustada jĂ€rgmisi andmevahetusseansse sellest vÀÀrtusest (valida kirjed, mille veeru vÀÀrtus update_time, ĂŒletab varem salvestatud vÀÀrtuse). Eelmise lĂ€henemisega seotud probleem on see, et andmete muutused vĂ”ivad toimuda pakettidena. SeetĂ”ttu vĂ”ivad selle veeru vÀÀrtused update_time olla mitteunikaalsed. Seega ei saa seda veergu kasutada andmete osalise (lehe jĂ€rgi) edastamise jaoks. Lehe jĂ€rgi andmete edastamiseks tuleb vĂ€lja mĂ”elda tĂ€iendavad mehhanismid, mis tĂ”enĂ€oliselt on vĂ€ga madala efektiivsusega (nĂ€iteks kĂ”ikide andmebaasist kirje vÀÀrtuse vĂ€ljavĂ”ttmine update_time ĂŒle mÀÀratud ja teatud arvu kirje esitlemine, alustades teatavast nihkest alates valikust).
Andmete edastamise efektiivsust saab parandada, kui tĂ€iustada eelnevat lĂ€henemist. Selleks kasutame muutuste jĂ€lgimise veergu vÀÀrtustena tĂ€isarvulist tĂŒĂŒpi (pikendatud tĂ€isarv). Nimetame veeru row_ver. Selle veeru vÀÀrtus peab jĂ€tkuvalt olema seadistatud/uuendatud iga kord, kui kirje on loodud/muutunud. Kuid sel juhul antakse vĂ€ljal mitte hetke kuupĂ€ev-aeg, vaid mingi loenduri vÀÀrtus, mis on suurenenud ĂŒhiku jagu. SeetĂ”ttu sisaldab veerg row_ver unikaalseid vÀÀrtusi ja saab kasutada mitte ainult "delta" andmete edastamiseks (andmed, mis on lisandunud/muutunud pĂ€rast eelmise andmevahetusseansi lĂ”ppu), vaid ka andmete lihtsaks ja tĂ”husaks lehtedeks jagamiseks.
Viimane pakutud meetod edastatavate andmete vÀhendamiseks kÔrgetasemelise replikatsiooni raames tundub mulle kÔige optimaalsem ja universaalsem. Vaatame seda lÀhemalt.
Andmete edastamine, kasutades ridade versioonide loendurit
Serveri / master osa teostamine
MS SQL Serveris on sarnase lĂ€henemise elluviimiseks olemas spetsiaalne veeru tĂŒĂŒp â rowversion. Igas andmebaasis on loendur, mis suureneb ĂŒhe vĂ”rra iga kord, kui andmeid lisatakse vĂ”i muudetakse tabelis, millel on veerg tĂŒĂŒbiga rowversion. Selle loenduri vÀÀrtus mÀÀratakse automaatselt selle veeru vĂ€ljale uues vĂ”i muudetud rekordis. AndmebaasisĂŒsteem Tarantoolil puudub sarnane sisseehitatud mehhanism. Siiski ei ole Tarantoolis seda keeruline kĂ€sitsi rakendada. Vaatame, kuidas seda teha.
Esiteks natuke terminoloogiat: Tarantoolis nimetatakse tabeleid spaisideks (space) ja rekordeid - tupleiteks (tuple). Tarantoolis saab luua jÀrjestusi (sequence). JÀrjestused on mitte midagi muud kui nimetatud tÀisarvude jÀrjestatud vÀÀrtuste generaatorid. See on tÀpselt see, mida meie eesmÀrkide jaoks vajame. Allpool loome sellise jÀrjestuse.
Enne andmebaasiga Tarantoolis mÔne toimingu tegemist tuleb tÀita jÀrgmine kÀsk:
box.cfg{}Kuna Tarantool hakkab salvestama andmebaasi hetkeseisud (snapshot) ja tehingu ĆŸurnaalid praeguses kataloogis.
Loome jÀrjestuse row_version:
box.schema.sequence.create('row_version',
{ if_not_exists = true }) Valik if_not_exists vĂ”imaldab skripti loomist teha mitmeid kordi: kui objekt eksisteerib, ei pĂŒĂŒa Tarantool seda uuesti luua. Seda valikut kasutatakse kĂ”igis jĂ€rgmistes DDL-kĂ€skudes.
Loome nÀidiseks spaisi.
box.schema.space.create('goods', {
format = {
{
name = 'id',
type = 'unsigned'
},
{
name = 'name',
type = 'string'
},
{
name = 'code',
type = 'unsigned'
},
{
name = 'row_ver',
type = 'unsigned'
}
},
if_not_exists = true
}) Siin mÀÀrasime spaisi nime (goods), vĂ€ljade nimed ja nende tĂŒĂŒbid.
Tarantoolis luuakse automaatselt suurenevad vÀljad samuti jÀrjestuste abil. Loome automaatselt suureneva pÔhivÔtme vÀlja pÔhjal id:
box.schema.sequence.create('goods_id',
{ if_not_exists = true })
box.space.goods:create_index('primary', {
parts = { 'id' },
sequence = 'goods_id',
unique = true,
type = 'HASH',
if_not_exists = true
})Tarantool toetab mitmeid indeksitĂŒĂŒpe. KĂ”ige sagedamini kasutatakse tĂŒĂŒpide TREE ja HASH indeksite ning vastavatesse struktuuridesse. TREE on kĂ”ige universaalsem indeksitĂŒĂŒp. See vĂ”imaldab andmeid vĂ€lja tĂ”mmata jĂ€rjekorras. Kuid vĂ”rdsuste alusel valimise jaoks sobib rohkem HASH. Seega on primaarse vĂ”tme jaoks mĂ”istlik kasutada HASH (nagu me tegime).
Selleks, et kasutada veergu row_ver muudetud andmete edastamiseks, tuleb sellele veerule seostada jĂ€rjestuse vÀÀrtused row_ver. Kuid erinevalt primaarsetest vĂ”tmetest peab veeru vÀÀrtus row_ver kasvama ĂŒhe vĂ”rra mitte ainult uute salvestuste lisamisel, vaid ka olemasolevate muutmisel. Selle jaoks saab kasutada trikke. Tarantoolis on ruumide jaoks kaks tĂŒĂŒpi trikke: before_replace ja on_replace. Trikid kĂ€ivitatakse iga kord, kui andmed ruumis muutuvad (iga muudetud kanti jaoks kĂ€ivitatakse triki funktsioon). Erinevalt on_replace, before_replace-trikkidest vĂ”imaldavad need muuta kanti andmeid, mille jaoks trikk kĂ€ivitatakse. Seega sobib meile viimane tĂŒĂŒp trikke.
box.space.goods:before_replace(function(old, new)
return box.tuple.new({new[1], new[2], new[3],
box.sequence.row_version:next()})
end) Antud trikk asendab veeru vÀÀrtuse row_ver salvestatud kanti jÀrgmise jÀrjestuse vÀÀrtusega. row_version.
Selleks, et saaksime andmeid ruumist vÀlja tÔmmata goods veeru row_ver, loome indeksi:
box.space.goods:create_index('row_ver', {
parts = { 'row_ver' },
unique = true,
type = 'TREE',
if_not_exists = true
}) Indeksi tĂŒĂŒp on puu (TREE), kuna peame andmeid vĂ€lja tĂ”mbama veeru vÀÀrtuste kasvava jĂ€rjekorra jĂ€rgi. row_ver.
Lisame ruumi mÔned andmed:
box.space.goods:insert{nil, 'pen', 123}
box.space.goods:insert{nil, 'pencil', 321}
box.space.goods:insert{nil, 'brush', 100}
box.space.goods:insert{nil, 'watercolour', 456}
box.space.goods:insert{nil, 'album', 101}
box.space.goods:insert{nil, 'notebook', 800}
box.space.goods:insert{nil, 'rubber', 531}
box.space.goods:insert{nil, 'ruler', 135} Kuna esimene vĂ€li on automaatselt suurenev loendaja, edastame selle asemel nil. Tarantool asendab selle automaatselt jĂ€rgmise vÀÀrtusega. Samuti vĂ”ib veergude vÀÀrtuste jaoks edastada nil â vĂ”i ei pea vÀÀrtust ĂŒldse mÀÀrama, kuna see veerg asub ruumis viimases positsioonis. row_ver Kontrollime sisestamise tulemust:
Kontrollime sisestuse tulemust:
tarantool> box.space.goods:select()
---
- - [1, 'plii', 123, 1]
- [2, 'plii', 321, 2]
- [3, 'harja', 100, 3]
- [4, 'akvarell', 456, 4]
- [5, 'album', 101, 5]
- [6, 'mÀrkmik', 800, 6]
- [7, 'kumm', 531, 7]
- [8, 'joonlaud', 135, 8]
... Nagu nĂ€eme, tĂ€itus esimene ja viimane vĂ€li automaatselt. NĂŒĂŒd on lihtne kirjutada funktsioon lehekĂŒlje kaupa muudatuste tĂ”mbamiseks spais. goods:
local page_size = 5
local function get_goods(row_ver)
local index = box.space.goods.index.row_ver
local goods = {}
local counter = 0
for _, tuple in index:pairs(row_ver, {
iterator = 'GT' }) do
local obj = tuple:tomap({ names_only = true })
table.insert(goods, obj)
counter = counter + 1
if counter >= page_size then
break
end
end
return goods
end Funktsioon vÔtab parameetrina vÀÀrtuse, row_ver, millest alates tuleb muudatuste allalaadimine, ja tagastab portsjoni muudetud andmetest.
Andmete valimine Tarantoolis toimub indeksite kaudu. Funktsioon get_goods kasutab indeksil iteratsioonimeetodit row_ver muudetud andmete saamiseks. Iteraatori tĂŒĂŒp â GT (Greater Than, suurem kui). See tĂ€hendab, et iterator liigub jĂ€rjestikku indeksivÀÀrtuste juures alates edastatud vĂ”tme (vĂ€lja vÀÀrtuse) row_ver).
Iteraator tagastab tuple'it. Et saaksime pikkade andmete edastamist HTTP kaudu, on vajalik tuple'ite konverteerimine struktkuuri, mis sobib edasiseks serializedamiseks. NÀites kasutatakse selle jaoks tavapÀrast funktsiooni tomap. Selle asemel, et kasutada tomap , vÔime kirjutada oma funktsiooni. NÀiteks vÔime soovida vÀli nimi, mitte edastada vÀli code ja lisada vÀli kommentaar:
local function unflatten_goods(tuple)
local obj = {}
obj.id = tuple.id
obj.goods_name = tuple.name
obj.comment = 'mÔni kommentaar'
obj.row_ver = tuple.row_ver
return obj
end Kuvatud andmete lehekĂŒlje suurus (registreid ĂŒhe portsjoni kohta) mÀÀratakse muutuja kaudu page_size. NĂ€ites on vÀÀrtus page_size vĂ”rdub 5. Reaalses programmis on lehe suurusel tavaliselt suurem tĂ€htsus. See sĂ”ltub ruumikottide keskmisest suurusest. Optimaalne lehe suurus vĂ”ib sĂ”ltumatult katsetamise teel leida, mÔÔtes andmete edastamise aega. Mida suurem on lehe suurus, seda vĂ€hem on ringreise edastava ja vastuvĂ”tva osapoole vahel. Nii saab vĂ€hendada muutuste ĂŒleslaadimise koguaega. Siiski, kui lehe suurus on liiga suur, kulutame serveri soariku töötlusele liiga kaua aega. Selle tulemusena vĂ”ivad tekkida viivitused teistele pĂ€ringutele, mis serverisse jĂ”uavad. Parameeter page_size saab laadida konfiguratsioonifailist. Iga edastatava ruumi jaoks vĂ”ib mÀÀrata oma vÀÀrtuse. Samas vĂ”ib enamiku ruumide jaoks sobida vaikimisi vÀÀrtus (nt 100).
Teeme funktsiooni get_goods:
tarantool> get_goods(0)
---
- - rida_versioon: 1
kood: 123
nimi: pliiats
id: 1
- rida_versioon: 2
kood: 321
nimi: pliiats
id: 2
- rida_versioon: 3
kood: 100
nimi: pintsel
id: 3
- rida_versioon: 4
kood: 456
nimi: akvarell
id: 4
- rida_versioon: 5
kood: 101
nimi: album
id: 5
... VĂ”tame vĂ€lja vĂ€lja vÀÀrtuse row_ver viimasest reast ja kutsume funktsiooni uuesti ĂŒles:
tarantool> get_goods(5)
---
- - rida_versioon: 6
kood: 800
nimi: vihik
id: 6
- rida_versioon: 7
kood: 531
nimi: kumm
id: 7
- rida_versioon: 8
kood: 135
nimi: joonlaud
id: 8
...Ja veel kord:
tarantool> get_goods(8)
---
- []
... Nagu nĂ€eme, tagastab funktsioon sellisel kasutamisel kĂ”ik ruumi kirjed lehekaupa. goodsViimase lehe taga jĂ€rgneb tĂŒhi valik.
Teeme muudatusi ruumis:
box.space.goods:update(4, {{'=', 6, 'mÀrkmik'}})
box.space.goods:insert{nil, 'klamber', 234}
box.space.goods:insert{nil, 'kaust', 432} Muutsime vĂ€lja vÀÀrtust nimi ĂŒhe kirje jaoks ja lisasime kaks uut kirjet.
Korratakse viimast funktsiooni kutset:
tarantool> get_goods(8)
---
- - rida_versioon: 9
kood: 800
nimi: mÀrkmik
id: 6
- rida_versioon: 10
kood: 234
nimi: klamber
id: 9
- rida_versioon: 11
kood: 432
nimi: kaust
id: 10
... Funktsioon tagastas muudetud ja lisatud kirjed. Nii et funktsioon get_goods lubab saada andmeid, mis on muutunud alates selle viimase kutsumise hetkest, mis ongi kÀsitletava replikeerimismeetodi alus.
JÀtame tulemuste edastamise HTTP kaudu JSON formaadis selle artikli raames vÀlja. Selle kohta saab lugeda siit:
Kliendi/slave osa rakendamine
Vaadakem, kuidas nÀeb vÀlja vastuvÔtva poole rakendamine. Loome vastuvÔtva poole ruumi laaditud andmete hoidmiseks:
box.schema.space.create('goods', {
format = {
{
name = 'id',
type = 'unsigned'
},
{
name = 'name',
type = 'string'
},
{
name = 'code',
type = 'unsigned'
}
},
if_not_exists = true
})
box.space.goods:create_index('primary', {
parts = { 'id' },
sequence = 'goods_id',
unique = true,
type = 'HASH',
if_not_exists = true
}) Ruumide struktuur meenutab allika ruumi struktuuri. Kuid kuna me ei plaani edastada saadud andmeid kuskile mujale, puudub row_ver saaja ruumis veerg. Veerus id salvestatakse allika identifikaatorid. Seega pole vastuvÔtja pooltel vajalik, et see oleks automaatselt suurenev.
Lisaks sellele vajame ruumi vÀÀrtuste talletamiseks. row_ver:
box.schema.space.create('row_ver', {
format = {
{
name = 'space_name',
type = 'string'
},
{
name = 'value',
type = 'string'
}
},
if_not_exists = true
})
box.space.row_ver:create_index('primary', {
parts = { 'space_name' },
unique = true,
type = 'HASH',
if_not_exists = true
}) Iga laaditava ruumi (vÀli space_name) salvestame siin viimase laetud vÀÀrtuse row_ver (vÀli value). Peamise vÔtmena toimib veerg space_name.
Loome funktsiooni ruumi andmete laadimiseks goods HTTP kaudu. Selleks vajame teeki, mis ŃДалОзŃĐ”Ń HTTP-klienti. JĂ€rgmine rida laadib teegi ja loob HTTP-klientide eksemplari:
local http_client = require('http.client').new()Samuti vajame teeki JSON-i deserialiseerimiseks:
local json = require('json')Seda on piisavalt, et luua andmete laadimise funktsioon:
local function load_data(url, row_ver)
local url = ('%s?rowVer=%s'):format(url,
tostring(row_ver))
local body = nil
local data = http_client:request('GET', url, body, {
keepalive_idle = 1,
keepalive_interval = 1
})
return json.decode(data.body)
end Funktsioon tÀidab HTTP-pÀringu aadressile url, edastab selle row_ver parameetrina ja tagastab deserialiseeritud pÀringu tulemuse.
Saadud andmete salvestamise funktsioon nÀeb vÀlja jÀrgmiselt:
local function save_goods(goods)
local n = #goods
box.atomic(function()
for i = 1, n do
local obj = goods[i]
box.space.goods:put(
obj.id, obj.name, obj.code)
end
end)
end Andmete salvestamise tsĂŒkkel ruumi goods on paigutatud tehingusse (selleks kasutatakse funktsiooni box.atomic) diskiga tehingute arvu vĂ€hendamiseks.
LĂ”puks vĂ”ib kohaliku ruumi goods allikaga sĂŒnkroonimise funktsiooni rakendada nii:
local function sync_goods()
local tuple = box.space.row_ver:get('goods')
local row_ver = tuple and tuple.value or 0
ââ set your url here:
local url = 'http://127.0.0.1:81/test/goods/list'
while true do
local goods = load_goods(url, row_ver)
local count = #goods
if count == 0 then
return
end
save_goods(goods)
row_ver = goods[count].rowVer
box.space.row_ver:put({'goods', row_ver})
end
end Esmalt loeme eelnevalt salvestatud vÀÀrtuse row_ver ruumi goods. Kui seda ei ole (esimene vahetuse seanss), siis vĂ”tame selle aluseks. row_ver null. See further, we perform page-by-page loading of modified data from the source at the specified url. On each iteration, we save the obtained data into the corresponding local space and update the value row_ver (in the space row_ver and in the variable row_ver) â we take the value row_ver from the last line of the loaded data.
To protect against accidental looping (in case of a program error), the loop while can be replaced with for:
for _ = 1, max_req do ... As a result of the function execution sync_goods space goods in the receiver will contain the latest versions of all records from the space goods in the source.
Clearly, this method cannot be used to transmit data deletion. If such a need arises, a deletion flag can be used. We add to the space goods a boolean field is_deleted and instead of physically deleting the record, we use logical deletion â we set the value of the field is_deleted vÀÀrtuseks true. Sometimes, instead of a boolean field is_deleted it is more convenient to use a field deleted, which stores the date-time of logical deletion of the record. After performing logical deletion, the marked record will be transferred from the source to the receiver (according to the logic discussed above).
The sequence row_ver can be used for transferring data from other spaces: there is no need to create a separate sequence for each space being transferred.
We have discussed an efficient method of high-level data replication in applications using the Tarantool DBMS.
JĂ€reldused
- The Tarantool DBMS is an attractive, promising product for creating high-load applications.
- High-level data replication has several advantages over low-level replication.
- The high-level replication method discussed in the article allows minimizing the amount of data transferred by only sending those records that have changed since the last exchange session.
Allikas: habr.com
