Goi-mailako erreplikazioa Tarantool DBMSn

Kaixo, DBMSrako aplikazioak sortzen ari naiz Tarantool Mail.ru Group-ek garatutako plataforma bat da, errendimendu handiko DBMS bat eta Lua hizkuntzan aplikazio zerbitzari bat konbinatzen dituena. Tarantool-en oinarritutako soluzioen abiadura handia lortzen da, batez ere, DBMS-en memoria-moduaren euskarriarengatik eta aplikazioen negozio-logika exekutatzeko datuekin helbide-espazio bakarrean exekutatzeko gaitasunagatik. Aldi berean, datuen iraunkortasuna bermatzen da ACID transakzioak erabiliz (WAL erregistroa mantentzen da diskoan). Tarantool-ek erreplika eta zatiketa egiteko euskarria du. 2.1 bertsiotik hasita, SQL hizkuntzako kontsultak onartzen dira. Tarantool kode irekia da eta BSD sinplifikatu lizentziapean dago lizentzia. Enterprise bertsio komertziala ere badago.

Goi-mailako erreplikazioa Tarantool DBMSn
Sentitu indarra! (... gozatu emanaldiaz)

Aurreko guztia, Tarantool plataforma erakargarria da datu-baseekin lan egiten duten karga handiko aplikazioak sortzeko. Horrelako aplikazioetan, askotan, datuak erreplikatzeko beharra dago.

Goian esan bezala, Tarantool-ek datuen erreplika integratua du. Bere funtzionamenduaren printzipioa erregistro maisuan (WAL) jasotako transakzio guztiak errepliketan sekuentzialki exekutatzen ditu. Normalean errepikapen hori (gehiago deituko diogu maila baxua) aplikazioaren akatsen tolerantzia ziurtatzeko eta/edo irakurketa-karga cluster-nodoen artean banatzeko erabiltzen da.

Goi-mailako erreplikazioa Tarantool DBMSn
Arroza. 1. Erreplikazioa kluster baten barruan

Eszenatoki alternatibo baten adibide bat datu-base batean sortutako datuak beste datu-base batera transferitzea izango litzateke prozesatzeko/monitorizaziorako. Azken kasu honetan, irtenbide erosoagoa erabiltzea izan daiteke maila altua erreplikazioa - datuen erreplikazioa aplikazioaren negozio logika mailan. Horiek. Ez dugu DBMSan txertatutako irtenbide prestaturik erabiltzen, garatzen ari garen aplikazioaren barruan erreplikazioa gure kabuz inplementatzen dugu. Ikuspegi honek abantailak eta desabantailak ditu. Zerrenda ditzagun abantailak.

1. Trafiko aurreztea:

  • Ezin dituzu datu guztiak transferitu, zati bat baizik (adibidez, irizpide jakin bat betetzen duten taula batzuk, haien zutabe batzuk edo erregistro batzuk bakarrik transferitu ditzakezu);
  • Behe-mailako erreplikazioa ez bezala, zeina etengabe egiten den modu asinkronoan (Tarantool-en egungo bertsioan inplementatuta - 1.10) edo sinkronoan (Tarantool-en ondorengo bertsioetan inplementatuko dena) moduan, goi-mailako erreplikazioa saioetan egin daiteke (hau da, aplikazioak lehenik datuak sinkronizatzen ditu - truke-saioko datuak, gero errepliketan eten bat dago, eta ondoren hurrengo truke-saioa gertatzen da, etab.);
  • Erregistro bat hainbat aldiz aldatu bada, bere azken bertsioa soilik transferi dezakezu (maila baxuko erreplikazioa ez bezala, non maisuan egindako aldaketa guztiak errepliketan sekuentzialki erreproduzituko baitira).

2. HTTP trukea ezartzeko ez dago zailtasunik, urruneko datu-baseak sinkronizatzeko aukera ematen duena.

Goi-mailako erreplikazioa Tarantool DBMSn
Arroza. 2. HTTP bidezko erreplikazioa

3. Datuak transferitzen diren datu-baseen egiturak ez dira zertan berdinak izan (gainera, kasu orokorrean, DBMS, programazio lengoaia, plataforma eta abar desberdinak ere erabil daitezke).

Goi-mailako erreplikazioa Tarantool DBMSn
Arroza. 3. Erreplika sistema heterogeneoetan

Alde txarra da, batez beste, programazioa konfigurazioa baino zailagoa/kostuagoa dela, eta integratutako funtzionaltasuna pertsonalizatu beharrean, zurea ezarri beharko duzula.

Zure egoeran goiko abantailak erabakigarriak badira (edo beharrezko baldintza badira), orduan zentzuzkoa da goi-mailako erreplikazioa erabiltzea. Ikus ditzagun maila altuko datuen erreplikazioa Tarantool DBMSn ezartzeko hainbat modu.

Trafikoa gutxitzea

Beraz, goi-mailako erreplikazioaren abantailetako bat trafikoa aurreztea da. Abantaila hau guztiz gauzatzeko, beharrezkoa da truke-saio bakoitzean transferitutako datu kopurua gutxitzea. Jakina, ez dugu ahaztu behar saioaren amaieran datu-hartzailea iturriarekin sinkronizatu behar dela (errepliketan parte hartzen duen datuen zati horretarako behintzat).

Nola murriztu transferitutako datu kopurua maila altuko errepliketan? Irtenbide erraz bat datuak dataren eta orduaren arabera hautatzea izan liteke. Horretarako, taulan lehendik dagoen data-ordu eremua erabil dezakezu (baldin badago). Esate baterako, "eskaera" dokumentu batek "beharrezko eskaera exekutatzeko denbora" eremua izan dezake - delivery_time. Irtenbide honen arazoa da eremu honetako balioek ez dutela zertan aginduak sortzeari dagokion sekuentzian egon. Beraz, ezin dugu gogoratu eremuaren gehienezko balioa delivery_time, aurreko truke saioan transmititu eta hurrengo truke saioan eremu-balio handiagoa duten erregistro guztiak hautatu delivery_time. Baliteke eremu-balio txikiagoa duten erregistroak truke-saioen artean gehitu izana delivery_time. Era berean, aginduak aldaketak izan zezakeen, eta horrek, hala ere, ez zuen eremuan eraginik izan delivery_time. Bi kasuetan, aldaketak ez dira iturritik helmugara eramango. Arazo hauek konpontzeko, datuak "gainjarriz" transferitu beharko ditugu. Horiek. truke-saio bakoitzean datu guztiak eremuaren balioarekin transferituko ditugu delivery_time, iraganeko punturen bat gaindituz (adibidez, uneko unetik N ordu). Hala ere, bistakoa da sistema handietarako ikuspegi hori oso erredundantea dela eta ahalegintzen ari garen trafiko-aurrezpena ezerezean murriztu dezakeela. Gainera, transferitzen ari den taulak baliteke data-orduarekin lotutako eremurik ez izatea.

Beste irtenbide bat, inplementazioari dagokionez konplexuagoa, datuak jaso izana aitortzea da. Kasu honetan, truke-saio bakoitzean, datu guztiak igortzen dira, hartzaileak ez duela jaso izana berretsi. Hau ezartzeko, zutabe boolear bat gehitu beharko duzu sorburu-taulan (adibidez, is_transferred). Hartzaileak erregistroa jaso duela aitortzen badu, dagokion eremuak hartuko du balioa true, eta ondoren sarrera ez da gehiago trukeetan parte hartzen. Ezarpen-aukera honek honako desabantaila hauek ditu. Lehenik eta behin, transferitutako erregistro bakoitzeko, aitorpen bat sortu eta bidali behar da. Gutxi gorabehera, transferitutako datu-kopurua bikoiztearekin eta joan-etorrien kopurua bikoiztearekin parekoa izan daiteke. Bigarrenik, ez dago erregistro bera hainbat hartzaileri bidaltzeko aukerarik (jasotzen duen lehen hartzaileak berretsiko du jaso duela beretzat eta beste guztientzat).

Goian emandako desabantailak ez dituen metodo bat transmititutako taulari zutabe bat gehitzea da bere errenkadetan izandako aldaketen jarraipena egiteko. Zutabe hori data-ordu motakoa izan daiteke eta aplikazioak uneko ordura ezarri/eguneratu behar du erregistroak gehitzen/aldatzen diren bakoitzean (atomikoki gehikuntza/aldaketarekin). Adibide gisa, dei diezaiogun zutabeari update_time. Transferitutako erregistroetarako zutabe honen gehienezko eremu-balioa gordeta, hurrengo truke-saioa has dezakegu balio honekin (hautatu eremuaren balioa duten erregistroak update_time, aurrez gordetako balioa gaindituz). Azken ikuspegi honen arazoa da datuen aldaketak sortetan gerta daitezkeela. Zutabeko eremuen balioen ondorioz update_time baliteke bakarra ez izatea. Beraz, zutabe hau ezin da zatika (orriz orrialde) datuen irteerarako erabili. Datuak orrialdez orrialde bistaratzeko, ziurrenik oso eraginkortasun txikia izango duten mekanismo osagarriak asmatu beharko dituzu (adibidez, datu-basetik balio duten erregistro guztiak berreskuratzea. update_time emandako bat baino handiagoa eta erregistro kopuru jakin bat ekoizten duena, laginaren hasierako desplazamendu jakin batetik abiatuta).

Datuen transferentziaren eraginkortasuna hobetu dezakezu aurreko ikuspegia apur bat hobetuz. Horretarako, zenbaki oso mota (oso luzea) erabiliko dugu zutabe-eremuaren balio gisa aldaketen jarraipena egiteko. Izena eman diezaiogun zutabeari row_ver. Zutabe honen eremuaren balioa oraindik ezarri/eguneratu behar da erregistro bat sortzen/aldatzen den bakoitzean. Baina kasu honetan, eremuari ez zaio uneko data-ordua esleituko, kontagailu batzuen balioa baizik, bat handitu. Ondorioz, zutabea row_ver balio esklusiboak izango ditu eta "delta" datuak bistaratzeko ez ezik (aurreko truke-saioaren amaieratik gehitu/aldatu diren datuak), baizik eta orrietan modu erraz eta eraginkorrean banatzeko ere erabil daiteke.

Goi-mailako erreplikaren esparruan transferitutako datu-kopurua minimizatzeko proposatutako azken metodoa egokiena eta unibertsalena iruditzen zait. Ikus dezagun zehatzago.

Datuak pasatzea errenkada-bertsio-kontagailua erabiliz

Zerbitzari/master zatiaren ezarpena

MS SQL Server-en, zutabe mota berezi bat dago ikuspegi hau ezartzeko - rowversion. Datu-base bakoitzak erregistro bat gehitzen/aldatzen den bakoitzean bat handitzen duen kontagailu bat du antzeko zutabe bat duen taula batean rowversion. Kontagailu honen balioa automatikoki esleitzen zaio zutabe honen eremuari gehitutako/aldatutako erregistroan. Tarantool DBMS-k ez du barne-mekanismo antzekorik. Hala ere, Tarantool-en ez da zaila eskuz ezartzea. Ikus dezagun nola egiten den.

Lehenik eta behin, terminologia apur bat: Tarantool-en taulei espazio deitzen zaie, eta erregistroei tuplak. Tarantool-en sekuentziak sor ditzakezu. Sekuentziak balio oso ordenatuen sorgailu izendatuak baino ez dira. Horiek. horixe da gure helburuetarako behar duguna. Jarraian halako sekuentzia bat sortuko dugu.

Tarantool-en datu-baseko edozein eragiketa egin aurretik, komando hau exekutatu behar duzu:

box.cfg{}

Ondorioz, Tarantool-ek datu-basearen argazkiak eta transakzioen erregistroak uneko direktorioan idazten hasiko da.

Sor dezagun sekuentzia bat row_version:

box.schema.sequence.create('row_version',
    { if_not_exists = true })

Aukera if_not_exists sorkuntza scripta hainbat aldiz exekutatzeko aukera ematen du: objektua existitzen bada, Tarantool ez da berriro sortzen saiatuko. Aukera hau hurrengo DDL komando guztietan erabiliko da.

Sor dezagun espazio bat adibide gisa.

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
})

Hemen jartzen dugu espazioaren izena (goods), eremu-izenak eta haien motak.

Tarantool-en automatikoki gehitzeko eremuak ere sortzen dira sekuentziak erabiliz. Sortu dezagun automatikoki gehitzen den gako nagusi bat eremuz 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-ek hainbat indize mota onartzen ditu. Gehien erabiltzen diren indizeak TREE eta HASH motak dira, izenari dagozkion egituretan oinarritzen direnak. ZUHAITZA indize mota aldakorrena da. Datuak modu antolatuan berreskuratzeko aukera ematen du. Baina berdintasuna aukeratzeko, HASH da egokiagoa. Horren arabera, lehen mailako gakorako HASH erabiltzea komeni da (hori da guk egin duguna).

Zutabea erabiltzeko row_ver aldatutako datuak transferitzeko, sekuentzia-balioak zutabe honetako eremuetara lotu behar dituzu row_ver. Baina gako nagusia ez bezala, zutabearen eremuaren balioa row_ver bat handitu beharko litzateke erregistro berriak gehitzean ez ezik, daudenak aldatzean ere. Horretarako abiarazleak erabil ditzakezu. Tarantool-ek bi espazio-abiarazle mota ditu: before_replace ΠΈ on_replace. Abiarazleak espazioko datuak aldatzen diren bakoitzean abiarazten dira (aldaketek eragindako tupla bakoitzeko, abiarazte funtzio bat abiarazten da). Ez bezala on_replace, before_replace-triggers-ek trigger-a exekutatzen den tuplaren datuak aldatzeko aukera ematen du. Horren arabera, azken abiarazle mota egokitzen zaigu.

box.space.goods:before_replace(function(old, new)
    return box.tuple.new({new[1], new[2], new[3],
        box.sequence.row_version:next()})
end)

Ondorengo abiarazleak eremuaren balioa ordezkatzen du row_ver gordetako tupla sekuentziaren hurrengo baliora row_version.

Espaziotik datuak atera ahal izateko goods zutabeka row_ver, sor dezagun indize bat:

box.space.goods:create_index('row_ver', {
    parts = { 'row_ver' },
    unique = true,
    type = 'TREE',
    if_not_exists = true
})

Indize mota - zuhaitza (TREE), zeren datuak zutabeko balioen goranzko ordenan atera beharko ditugu row_ver.

Gehi ditzagun datu batzuk espaziora:

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}

Zeren Lehenengo eremua automatikoki gehitzen den kontagailua da; horren ordez, zero pasatzen dugu. Tarantool-ek automatikoki ordezkatuko du hurrengo balioa. Era berean, zutabe-eremuen balioa bezala row_ver nil pasa dezakezu - edo baliorik ez zehaztu, zeren zutabe honek espazioko azken posizioa hartzen du.

Ikus dezagun txertatzeko emaitza:

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]
...

Ikus dezakezunez, lehenengo eta azken eremuak automatikoki betetzen dira. Orain erraza izango da espazio-aldaketak orrialdez orrialde kargatzeko funtzio bat idaztea 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

Funtzioak parametro gisa hartzen du balioa row_ver, bertatik aldaketak deskargatu behar dira eta aldatutako datuen zati bat itzultzen du.

Tarantool-en datuen laginketa indizeen bidez egiten da. Funtzioa get_goods indizearen arabera iteratzailea erabiltzen du row_ver aldatutako datuak jasotzeko. Iteratzaile mota GT da (Greater Than, Greater than). Horrek esan nahi du iteratzaileak sekuentzialki zeharkatuko dituela indize-balioak emandako gakotik hasita (eremuaren balioa row_ver).

Iteratzaileak tuplak itzultzen ditu. Ondoren datuak HTTP bidez transferitu ahal izateko, beharrezkoa da tuplak ondorengo serializaziorako erosoa den egitura batean bihurtzea. Adibideak funtzio estandarra erabiltzen du horretarako tomap. Erabili beharrean tomap zure funtzioa idatz dezakezu. Adibidez, baliteke eremu bati izena aldatu nahi izatea name, ez pasa zelaia code eta gehitu eremu bat 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

Irteerako datuen orriaren tamaina (zati bateko erregistro kopurua) aldagaiak zehazten du page_size. Adibidean balioa page_size 5 da. Programa erreal batean, orriaren tamainak axola handiagoa du normalean. Espazio-tuplaren batez besteko tamainaren araberakoa da. Orrialdearen tamaina optimoa enpirikoki zehaztu daiteke datuak transferitzeko denbora neurtuz. Zenbat eta handiagoa izan orriaren tamaina, orduan eta txikiagoa izango da joan-etorriko bidalketa eta jasotzaileen artean. Horrela aldaketak deskargatzeko denbora orokorra murriztu dezakezu. Hala ere, orriaren tamaina handiegia bada, denbora gehiegi igaroko dugu zerbitzarian lagina seriatzen. Ondorioz, zerbitzarira datozen beste eskaera batzuk prozesatzeko atzerapenak egon daitezke. Parametroa page_size konfigurazio fitxategitik kargatu daiteke. Igorritako espazio bakoitzeko, bere balioa ezar dezakezu. Hala ere, espazio gehienetarako balio lehenetsia (adibidez, 100) egokia izan daiteke.

Exekutatu dezagun funtzioa 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
...

Har dezagun eremuaren balioa row_ver azken lerrotik eta deitu berriro funtzioari:

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
...

Berriz ere:

tarantool> get_goods(8)
---
- []
...

Ikus dezakezunez, horrela erabiltzen denean, funtzioak espazio-erregistro guztiak orrialdez orrialde itzultzen ditu goods. Azken orrialdearen atzetik hautaketa huts bat dago.

Egin ditzagun aldaketak espazioan:

box.space.goods:update(4, {{'=', 6, 'copybook'}})
box.space.goods:insert{nil, 'clip', 234}
box.space.goods:insert{nil, 'folder', 432}

Eremuaren balioa aldatu dugu name sarrera baterako eta bi sarrera berri gehitu zituen.

Errepikatu dezagun azken funtzio-deia:

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
...

Funtzioak aldatutako eta gehitutako erregistroak itzuli zituen. Beraz, funtzioa get_goods azken deialditik aldatu diren datuak jasotzeko aukera ematen du, hau da, kontuan hartzen ari den erreplika-metodoaren oinarria.

Emaitzen igorpena HTTP bidez JSON forman artikulu honen esparrutik kanpo utziko dugu. Honi buruz irakur dezakezu hemen: https://habr.com/ru/company/mailru/blog/272141/

Bezero/esklabo zatia ezartzea

Ikus dezagun nolakoa den alde hartzailearen ezarpena. Sortu dezagun espazio bat hartzailearen aldean deskargatutako datuak gordetzeko:

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
})

Espazioaren egiturak iturriko espazioaren egituraren antza du. Baina jasotako datuak beste inora pasatuko ez ditugunez, zutabea row_ver ez dago hartzailearen espazioan. Eremuan id iturri-identifikatzaileak erregistratuko dira. Hori dela eta, hartzailearen aldetik ez dago automatikoki gehikuntzarik egin beharrik.

Horrez gain, balioak gordetzeko espazio bat behar dugu 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
})

Kargatutako espazio bakoitzeko (eremua space_name) kargatutako azken balioa hemen gordeko dugu row_ver (eremua value). Zutabeak gako nagusi gisa jokatzen du space_name.

Sortu dezagun funtzio bat espazioko datuak kargatzeko goods HTTP bidez. Horretarako, HTTP bezero bat inplementatzen duen liburutegi bat behar dugu. Hurrengo lerroak liburutegia kargatzen du eta HTTP bezeroa instantziatzen du:

local http_client = require('http.client').new()

Json deserializaziorako liburutegi bat ere behar dugu:

local json = require('json')

Hau nahikoa da datuak kargatzeko funtzio bat sortzeko:

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

Funtzioak HTTP eskaera bat exekutatzen du url helbidera eta bidaltzen du row_ver parametro gisa eta eskaeraren emaitza deserializatua itzultzen du.

Jasotako datuak gordetzeko funtzioak itxura hau du:

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

Datuak espazioan gordetzeko zikloa goods transakzio batean jartzen da (funtzioa horretarako erabiltzen da box.atomic) diskoaren eragiketa kopurua murrizteko.

Azkenik, tokiko espazioaren sinkronizazio funtzioa goods iturri batekin honela inplementatu dezakezu:

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

Lehenik eta behin aurrez gordetako balioa irakurriko dugu row_ver espaziorako goods. Falta bada (lehenengo truke saioa), orduan bezala hartzen dugu row_ver zero. Jarraian, zikloan aldatutako datuen orrialdez orrialdeko deskarga bat egiten dugu iturburutik zehaztutako URLan. Iterazio bakoitzean, jasotako datuak tokiko espazio egokian gordetzen ditugu eta balioa eguneratzen dugu row_ver (espazioan row_ver eta aldagaian row_ver) - hartu balioa row_ver kargatutako datuen azken lerrotik.

Ustekabeko begiztatik babesteko (programan akatsen bat izanez gero), begizta while ordezkatu daiteke for:

for _ = 1, max_req do ...

Funtzioa exekutatzearen ondorioz sync_goods espazioa goods hargailuak espazio-erregistro guztien azken bertsioak izango ditu goods iturrian.

Jakina, datuak ezabatzea ezin da modu honetan igorri. Behar hori badago, ezabatzeko marka erabil dezakezu. Gehitu espaziora goods eremu boolearra is_deleted eta erregistro bat fisikoki ezabatu beharrean, ezabatze logikoa erabiltzen dugu - eremuaren balioa ezartzen dugu is_deleted esanahian sartu true. Batzuetan eremu boolear baten ordez is_deleted eremua erabiltzea erosoagoa da deleted, erregistroaren ezabatze logikoaren data-ordua gordetzen duena. Ezabatze logikoa egin ondoren, ezabatzeko markatutako erregistroa iturritik helmugara eramango da (goian aztertutako logikaren arabera).

Sekuentzia row_ver beste espazio batzuetako datuak transmititzeko erabil daiteke: ez dago transmititutako espazio bakoitzeko sekuentzia bereizirik sortu beharrik.

Tarantool DBMS erabiltzen duten aplikazioetan goi-mailako datuak erreplikatzeko modu eraginkorra aztertu dugu.

Findings

  1. Tarantool DBMS produktu erakargarria eta itxaropentsua da karga handiko aplikazioak sortzeko.
  2. Goi-mailako datuen erreplikazioak abantaila ugari ditu maila baxuko erreplikazioaren aldean.
  3. Artikuluan eztabaidatutako goi-mailako erreplikazio-metodoak transferitutako datuen kopurua minimizatzeko aukera ematen du, azken truke-saiotik aldatu diren erregistroak soilik transferituz.

Iturria: www.habr.com

Gehitu iruzkin berria