Bonjou, m ap kreye aplikasyon pou DBMS
Santi pouvwa a! (...aka jwi pèfòmans lan)
Tout sa ki anwo yo fè Tarantool yon platfòm atire pou kreye aplikasyon pou gwo chaj ki travay ak baz done. Nan aplikasyon sa yo, souvan gen yon bezwen pou replikasyon done.
Kòm mansyone pi wo a, Tarantool gen replikasyon done entegre. Prensip la nan operasyon li yo se sekans egzekite sou kopi tout tranzaksyon ki genyen nan boutèy la mèt (WAL). Anjeneral replikasyon sa yo (nou pral plis rele li nivo ki ba) yo itilize pou asire tolerans fay aplikasyon ak/oswa pou distribye chay lekti a ant nœuds gwoup yo.
Diri. 1. Replikasyon nan yon gwoup
Yon egzanp yon senaryo altènatif ta transfere done ki te kreye nan yon baz done nan yon lòt baz done pou trete/siveyans. Nan dènye ka a, yon solisyon pi pratik ka sèvi ak wo nivo replikasyon - replikasyon done nan nivo lojik biznis aplikasyon an. Moun sa yo. Nou pa sèvi ak yon solisyon ki pare ki entegre nan DBMS la, men nou aplike replikasyon poukont nou nan aplikasyon n ap devlope a. Apwòch sa a gen tou de avantaj ak dezavantaj. Ann fè lis avantaj yo.
1. Ekonomi trafik:
- Ou pa ka transfere tout done yo, men se sèlman yon pati nan li (pa egzanp, ou ka transfere sèlman kèk tab, kèk nan kolòn yo oswa dosye ki satisfè yon sèten kritè);
- Kontrèman ak replikasyon ba-nivo, ki fèt kontinyèlman nan mòd asynchrone (aplike nan vèsyon aktyèl Tarantool - 1.10) oswa synchrone (pou aplike nan vèsyon ki vin apre nan Tarantool), replikasyon wo nivo ka fèt nan sesyon yo (sa vle di, la. aplikasyon an premye senkronize done yo - yon sesyon echanj done, Lè sa a, gen yon poz nan replikasyon, apre sa pwochen sesyon echanj la rive, elatriye);
- si yon dosye te chanje plizyè fwa, ou ka transfere sèlman dènye vèsyon li (kontrèman ak replikasyon ki ba-nivo, nan ki tout chanjman ki fèt sou mèt la pral jwe tounen sekans sou kopi yo).
2. Pa gen okenn difikilte ak aplikasyon HTTP echanj, ki pèmèt ou senkronize baz done aleka.
Diri. 2. Replikasyon sou HTTP
3. Estrikti baz done ki genyen ant done yo transfere yo pa oblije menm bagay la (anplis de sa, nan ka jeneral la, li se menm posib yo sèvi ak diferan DBMS, lang pwogramasyon, platfòm, elatriye).
Diri. 3. Replikasyon nan sistèm etewojèn
Dezavantaj la se ke, an mwayèn, pwogramasyon se pi difisil / koute chè pase konfigirasyon, epi olye pou yo personnaliser fonksyonalite entegre a, ou pral oblije aplike pwòp ou a.
Si nan sitiyasyon ou avantaj ki anwo yo enpòtan anpil (oswa se yon kondisyon ki nesesè), Lè sa a, li fè sans pou itilize replikasyon wo nivo. Ann gade plizyè fason pou aplike replikasyon done wo nivo nan DBMS Tarantool.
Minimize trafik
Se konsa, youn nan avantaj ki genyen nan replikasyon wo nivo se ekonomi trafik. Nan lòd pou avantaj sa a yo dwe konplètman reyalize, li nesesè pou misyon pou minimize kantite done transfere pandan chak sesyon echanj. Natirèlman, nou pa ta dwe bliye ke nan fen sesyon an, reseptè done a dwe senkronize ak sous la (omwen pou pati sa a nan done yo ki enplike nan replikasyon).
Ki jan yo minimize kantite done transfere pandan replikasyon wo nivo? Yon solisyon senp ta ka chwazi done pa dat ak lè. Pou fè sa, ou ka itilize jaden dat-lè ki deja egziste nan tablo a (si li egziste). Pou egzanp, yon dokiman "lòd" ka gen yon jaden "tan ekzekisyon lòd obligatwa" - delivery_time
. Pwoblèm nan ak solisyon sa a se ke valè yo nan jaden sa a pa oblije se nan sekans ki koresponn ak kreyasyon an nan lòd. Se konsa, nou pa ka sonje valè maksimòm jaden an delivery_time
, transmèt pandan sesyon echanj anvan an, epi pandan sesyon echanj pwochen an chwazi tout dosye ki gen yon valè jaden ki pi wo delivery_time
. Dosye ki gen yon valè jaden ki pi ba yo ka te ajoute ant sesyon echanj yo delivery_time
. Epitou, lòd la te kapab sibi chanjman, ki kanmenm pa te afekte jaden an delivery_time
. Nan de ka yo, chanjman yo pa pral transfere soti nan sous la nan destinasyon an. Pou rezoud pwoblèm sa yo, nou pral bezwen transfere done "sipèpoze". Moun sa yo. nan chak sesyon echanj nou pral transfere tout done ak valè jaden an delivery_time
, depase kèk pwen nan tan lontan an (pa egzanp, N èdtan nan moman aktyèl la). Sepandan, li evidan ke pou gwo sistèm apwòch sa a se trè redondants epi li ka diminye ekonomi trafik ke nou ap fè efò pou yo pa anyen. Anplis de sa, tab la ke yo te transfere ka pa gen yon jaden ki asosye ak yon dat-lè.
Yon lòt solisyon, ki pi konplèks an tèm de aplikasyon, se rekonèt resevwa done yo. Nan ka sa a, pandan chak sesyon echanj, tout done yo transmèt, resi a pa te konfime pa moun k ap resevwa a. Pou aplike sa, w ap bezwen ajoute yon kolòn Boolean nan tab sous la (pa egzanp, is_transferred
). Si reseptè a rekonèt li resevwa dosye a, jaden ki koresponn lan pran valè a true
, apre sa antre a pa patisipe ankò nan echanj. Opsyon aplikasyon sa a gen dezavantaj sa yo. Premyèman, pou chak dosye transfere, yon rekonesans dwe pwodwi epi voye. Apeprè pale, sa a ta ka konparab ak double kantite done transfere ak ki mennen ale nan double kantite roundtrips. Dezyèmman, pa gen okenn posibilite pou voye menm dosye a bay plizyè reseptè (premye reseptè a ap konfime resi pou tèt li ak pou tout lòt yo).
Yon metòd ki pa gen dezavantaj yo bay pi wo a se ajoute yon kolòn nan tab la transmèt pou swiv chanjman nan ranje li yo. Yon kolòn sa a ka nan kalite dat-lè epi aplikasyon an dwe mete/mete ajou nan tan aktyèl la chak fwa yo ajoute/chanje dosye (atomik ak adisyon/chanjman an). Kòm yon egzanp, ann rele kolòn nan update_time
. Lè nou sove valè maksimòm kolòn sa a pou dosye transfere yo, nou ka kòmanse pwochen sesyon echanj la ak valè sa a (chwazi dosye ki gen valè jaden an). update_time
, depase valè ki te deja estoke). Pwoblèm nan ak dènye apwòch la se ke chanjman done ka rive nan lo. Kòm yon rezilta nan valè yo jaden nan kolòn nan update_time
ka pa inik. Kidonk, kolòn sa a pa ka itilize pou pwodiksyon done pòsyon (paj pa paj). Pou montre done paj pa paj, w ap oblije envante mekanis adisyonèl ki gen plis chans gen efikasite trè ba (pa egzanp, rekipere nan baz done a tout dosye ki gen valè a. update_time
pi wo pase yon sèl bay ak pwodwi yon sèten kantite dosye, kòmanse nan yon konpanse sèten depi nan konmansman an nan echantiyon an).
Ou ka amelyore efikasite nan transfè done pa yon ti kras amelyore apwòch anvan an. Pou fè sa, nou pral sèvi ak kalite a nonb antye relatif (long nonb antye relatif) kòm valè yo jaden kolòn pou swiv chanjman yo. Ann bay non kolòn nan row_ver
. Valè jaden kolòn sa a dwe toujou mete/mete ajou chak fwa yo kreye/modifye yon dosye. Men, nan ka sa a, jaden an pa pral plase aktyèl dat-lè, men valè a nan kèk kontwa, ogmante pa youn. Kòm yon rezilta, kolòn nan row_ver
pral gen valè inik epi yo ka itilize pa sèlman pou montre done "delta" (done te ajoute/chanje depi nan fen sesyon echanj anvan an), men tou pou tou senpleman ak efektivman kraze l an paj.
Metòd ki sot pase yo pwopoze pou minimize kantite done transfere nan kad replikasyon wo nivo sanble pi bon ak inivèsèl la. Ann gade li an plis detay.
Pase done lè l sèvi avèk yon kontè vèsyon ranje
Aplikasyon pati sèvè/mèt la
Nan MS SQL sèvè, gen yon kalite kolòn espesyal pou aplike apwòch sa a - rowversion
. Chak baz done gen yon kontwa ki ogmante pa youn chak fwa yo ajoute/chanje yon dosye nan yon tablo ki gen yon kolòn tankou rowversion
. Valè kontwa sa a otomatikman asiyen nan jaden kolòn sa a nan dosye ajoute/chanje a. DBMS Tarantool pa gen yon mekanis entegre menm jan an. Sepandan, nan Tarantool li pa difisil pou aplike li manyèlman. Ann gade kijan sa fèt.
Premyèman, yon ti tèminoloji: tab nan Tarantool yo rele espas, ak dosye yo rele tuple. Nan Tarantool ou ka kreye sekans. Sekans yo pa gen anyen plis pase dèlko non de valè nonb antye relatif. Moun sa yo. sa a se egzakteman sa nou bezwen pou objektif nou yo. Anba a nou pral kreye yon sekans konsa.
Anvan ou fè nenpòt operasyon baz done nan Tarantool, ou bezwen kouri lòd sa a:
box.cfg{}
Kòm yon rezilta, Tarantool pral kòmanse ekri snapshots baz done ak mòso tranzaksyon nan anyè aktyèl la.
Ann kreye yon sekans row_version
:
box.schema.sequence.create('row_version',
{ if_not_exists = true })
Opsyon if_not_exists
pèmèt script kreyasyon an dwe egzekite plizyè fwa: si objè a egziste, Tarantool pa pral eseye kreye li ankò. Opsyon sa a pral itilize nan tout kòmandman DDL ki vin apre yo.
Ann kreye yon espas kòm yon egzanp.
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
})
Isit la nou mete non espas la (goods
), non jaden ak kalite yo.
Jaden oto-enkreman nan Tarantool yo kreye tou lè l sèvi avèk sekans. Ann kreye yon kle prensipal oto-enkreman pa jaden 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 sipòte plizyè kalite endèks. Endèks ki pi souvan itilize yo se TREE ak HASH, ki baze sou estrikti ki koresponn ak non an. TREE se kalite endèks ki pi versatile. Li pèmèt ou rekipere done nan yon fason òganize. Men, pou seleksyon egalite, HASH pi apwopriye. An konsekans, li rekòmande pou itilize HASH pou kle prensipal la (ki se sa nou te fè).
Pou itilize kolòn nan row_ver
pou transfere done chanje, ou bezwen mare valè sekans nan jaden yo nan kolòn sa a row_ver
. Men, kontrèman ak kle prensipal la, valè jaden an kolòn row_ver
ta dwe ogmante pa yon sèl non sèlman lè ajoute nouvo dosye, men tou lè chanje dosye ki deja egziste. Ou ka itilize deklanche pou sa. Tarantool gen de kalite deklanchman espas: before_replace
и on_replace
. Deklanche yo tire chak fwa done yo nan espas ki la chanje (pou chak tuple ki afekte nan chanjman yo, yon fonksyon deklanche lanse). Kontrèman ak on_replace
, before_replace
-triggers pèmèt ou modifye done yo nan tuple la pou ki deklanche la egzekite. An konsekans, dènye kalite deklanche kostim nou.
box.space.goods:before_replace(function(old, new)
return box.tuple.new({new[1], new[2], new[3],
box.sequence.row_version:next()})
end)
Deklanche sa a ranplase valè jaden an row_ver
ki estoke tuple nan pwochen valè sekans lan row_version
.
Yo nan lòd yo kapab ekstrè done ki soti nan espas goods
pa kolòn row_ver
, ann kreye yon endèks:
box.space.goods:create_index('row_ver', {
parts = { 'row_ver' },
unique = true,
type = 'TREE',
if_not_exists = true
})
Kalite endèks - pye bwa (TREE
), paske nou pral bezwen ekstrè done yo nan lòd monte nan valè yo nan kolòn nan row_ver
.
Ann ajoute kèk done nan espas la:
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}
Paske Premye jaden an se yon kontwa oto-enkreman; nou pase nil olye. Tarantool pral otomatikman ranplase valè kap vini an. Menm jan an tou, kòm valè a nan jaden yo kolòn row_ver
ou ka pase nil - oswa ou pa presize valè a ditou, paske kolòn sa a okipe dènye pozisyon nan espas la.
Ann tcheke rezilta ensèsyon an:
tarantool> box.space.goods:select()
---
- - [1, 'pen', 123, 1]
- [2, 'pencil', 321, 2]
- [3, 'brush', 100, 3]
- [4, 'watercolour', 456, 4]
- [5, 'album', 101, 5]
- [6, 'notebook', 800, 6]
- [7, 'rubber', 531, 7]
- [8, 'ruler', 135, 8]
...
Kòm ou ka wè, premye ak dènye jaden yo ranpli otomatikman. Koulye a, li pral fasil yo ekri yon fonksyon pou uploading paj-pa-paj nan chanjman espas 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
Fonksyon an pran kòm yon paramèt valè a row_ver
, kòmanse nan ki li nesesè dechaje chanjman, epi retounen yon pòsyon nan done yo chanje.
Yo fè echantiyon done nan Tarantool atravè endèks. Fonksyon get_goods
itilize yon iteratè pa endèks row_ver
pou resevwa done ki chanje. Kalite iteratè se GT (Greater Than, pi gran pase). Sa vle di ke iteratè a pral sekans travèse valè endèks yo kòmanse nan kle a pase (valè jaden an. row_ver
).
Iteratè a retounen tuples. Yo nan lòd yo imedyatman kapab transfere done atravè HTTP, li nesesè konvèti tuple yo nan yon estrikti pratik pou serializasyon ki vin apre. Egzanp lan sèvi ak fonksyon estanda pou sa tomap
. Olye pou yo itilize tomap
ou ka ekri pwòp fonksyon ou. Pou egzanp, nou ta ka vle chanje non yon jaden name
, pa pase jaden an code
epi ajoute yon jaden comment
:
local function unflatten_goods(tuple)
local obj = {}
obj.id = tuple.id
obj.goods_name = tuple.name
obj.comment = 'some comment'
obj.row_ver = tuple.row_ver
return obj
end
Gwosè paj done pwodiksyon an (kantite dosye nan yon sèl pòsyon) se varyab la detèmine page_size
. Nan egzanp lan valè a page_size
se 5. Nan yon pwogram reyèl, gwosè paj la anjeneral enpòtan plis. Sa depann de gwosè mwayèn nan tuple espas la. Gwosè optimal paj la ka detèmine anpirik lè w mezire tan transfè done. Plis gwosè paj la pi gwo, se pi piti kantite ale ant kote yo voye ak k ap resevwa yo. Nan fason sa a ou ka diminye tan an jeneral pou telechaje chanjman yo. Sepandan, si gwosè paj la twò gwo, nou pral pase twò lontan sou sèvè a seri echantiyon an. Kòm yon rezilta, ka gen reta nan pwosesis lòt demann ki vini sou sèvè a. Paramèt page_size
ka chaje nan dosye konfigirasyon an. Pou chak espas transmèt, ou ka mete valè pwòp li yo. Sepandan, pou pifò espas valè default (pa egzanp, 100) ka apwopriye.
Ann egzekite fonksyon an get_goods
:
tarantool> get_goods(0)
---
- - row_ver: 1
code: 123
name: pen
id: 1
- row_ver: 2
code: 321
name: pencil
id: 2
- row_ver: 3
code: 100
name: brush
id: 3
- row_ver: 4
code: 456
name: watercolour
id: 4
- row_ver: 5
code: 101
name: album
id: 5
...
Ann pran valè jaden an row_ver
soti nan dènye liy lan epi rele fonksyon an ankò:
tarantool> get_goods(5)
---
- - row_ver: 6
code: 800
name: notebook
id: 6
- row_ver: 7
code: 531
name: rubber
id: 7
- row_ver: 8
code: 135
name: ruler
id: 8
...
Yon lòt fwa ankò:
tarantool> get_goods(8)
---
- []
...
Kòm ou ka wè, lè yo itilize fason sa a, fonksyon an retounen tout dosye espas paj pa paj goods
. Dènye paj la swiv pa yon seleksyon vid.
Ann fè chanjman nan espas la:
box.space.goods:update(4, {{'=', 6, 'copybook'}})
box.space.goods:insert{nil, 'clip', 234}
box.space.goods:insert{nil, 'folder', 432}
Nou te chanje valè jaden an name
pou yon antre epi ajoute de nouvo antre.
Ann repete dènye apèl fonksyon an:
tarantool> get_goods(8)
---
- - row_ver: 9
code: 800
name: copybook
id: 6
- row_ver: 10
code: 234
name: clip
id: 9
- row_ver: 11
code: 432
name: folder
id: 10
...
Fonksyon an te retounen dosye yo chanje ak ajoute. Se konsa, fonksyon an get_goods
pèmèt ou resevwa done ki chanje depi dènye apèl li a, ki se baz metòd replikasyon an konsidere.
Nou pral kite emisyon rezilta yo atravè HTTP nan fòm JSON deyò sijè ki abòde lan atik sa a. Ou ka li sou sa a isit la:
Aplikasyon pati kliyan/esklav la
Ann gade nan ki sa aplikasyon bò k ap resevwa a sanble. Ann kreye yon espas sou bò k ap resevwa a pou estoke done telechaje yo:
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
})
Estrikti espas la sanble ak estrikti espas ki nan sous la. Men, depi nou pa pral pase done yo resevwa nenpòt lòt kote, kolòn nan row_ver
pa nan espas moun k ap resevwa a. Nan jaden id
idantifyan sous yo pral anrejistre. Se poutèt sa, sou bò reseptè a pa gen okenn bezwen fè li oto-enkreman.
Anplis de sa, nou bezwen yon espas pou sove valè 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
})
Pou chak espas chaje (jaden space_name
) nou pral sove dènye valè a chaje isit la row_ver
(jaden value
). Kolòn nan aji kòm kle prensipal la space_name
.
Ann kreye yon fonksyon pou chaje done espas goods
atravè HTTP. Pou fè sa, nou bezwen yon bibliyotèk ki aplike yon kliyan HTTP. Liy sa a chaje bibliyotèk la epi enstansye kliyan HTTP a:
local http_client = require('http.client').new()
Nou bezwen tou yon bibliyotèk pou json deserialization:
local json = require('json')
Sa a se ase yo kreye yon fonksyon loading done:
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
Fonksyon an egzekite yon demann HTTP nan adrès url la epi voye li row_ver
kòm yon paramèt epi li retounen rezilta deserialize demann lan.
Fonksyon pou sove done resevwa yo sanble sa a:
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
Sik pou konsève pou done nan espas goods
mete nan yon tranzaksyon (yo se fonksyon an itilize pou sa a box.atomic
) diminye kantite operasyon ki gen kapasite.
Finalman, fonksyon an senkronizasyon espas lokal la goods
ak yon sous ou ka aplike li tankou sa a:
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
Premyèman, nou li valè ki te deja sove a row_ver
pou espas goods
. Si li manke (premye sesyon echanj), Lè sa a, nou pran li kòm row_ver
zewo. Apre sa, nan sik la nou fè yon telechaje paj pa paj nan done yo chanje soti nan sous la nan url la espesifye. Nan chak iterasyon, nou sove done yo resevwa nan espas lokal ki apwopriye a epi mete ajou valè a row_ver
(nan espas row_ver
ak nan varyab la row_ver
) - pran valè a row_ver
soti nan dènye liy done chaje yo.
Pou pwoteje kont bouk aksidan (nan ka ta gen yon erè nan pwogram nan), bouk la while
ka ranplase pa for
:
for _ = 1, max_req do ...
Kòm yon rezilta nan egzekite fonksyon an sync_goods
espas goods
reseptè a pral genyen dènye vèsyon yo nan tout dosye espas goods
nan sous la.
Li evidan, efase done pa ka difize nan fason sa a. Si yon bezwen sa a egziste, ou ka itilize yon mak efase. Ajoute nan espas goods
jaden boolean is_deleted
ak olye pou yo efase fizikman yon dosye, nou itilize efase lojik - nou mete valè jaden an is_deleted
nan sans true
. Pafwa olye de yon jaden boolean is_deleted
li pi pratik pou itilize jaden an deleted
, ki estoke dat-lè efase lojik dosye a. Apre yo fin fè yon efase lojik, dosye ki make pou efase a pral transfere soti nan sous la nan destinasyon an (dapre lojik ki te diskite pi wo a).
Sekans row_ver
ka itilize pou transmèt done ki soti nan lòt espas: pa gen okenn nesesite yo kreye yon sekans separe pou chak espas transmèt.
Nou te gade yon fason efikas nan replikasyon done wo nivo nan aplikasyon lè l sèvi avèk DBMS Tarantool.
Jwenn
- Tarantool DBMS se yon pwodwi atiran, pwomèt pou kreye aplikasyon pou gwo chaj.
- Replikasyon done wo nivo gen yon kantite avantaj sou replikasyon ki ba.
- Metòd replikasyon wo nivo diskite nan atik la pèmèt ou minimize kantite done transfere lè w transfere sèlman dosye sa yo ki chanje depi dènye sesyon echanj la.
Sous: www.habr.com