Replicazione di altu livellu in Tarantool DBMS

Ciao, creanu applicazioni per DBMS Tarantool hè una piattaforma sviluppata da Mail.ru Group chì combina un DBMS high-performance è un servitore di applicazioni in lingua Lua. L'alta velocità di suluzione basata nantu à Tarantool hè ottenuta, in particulare, per via di u supportu per u modu in-memoria di u DBMS è a capacità di eseguisce a logica di l'applicazione di l'affari in un spaziu di indirizzu unicu cù dati. À u listessu tempu, a persistenza di dati hè assicurata cù transazzione ACID (un log WAL hè mantinutu nantu à u discu). Tarantool hà un supportu integratu per a replicazione è sharding. Partendu da a versione 2.1, e dumande in lingua SQL sò supportate. Tarantool hè open source è licenziatu sottu a licenza Simplified BSD. Ci hè ancu una versione cummerciale cummerciale.

Replicazione di altu livellu in Tarantool DBMS
Sentite u putere! (…aka gode di u spettaculu)

Tuttu ciò chì sopra face Tarantool una piattaforma attraente per creà applicazioni d'alta carica chì travaglianu cù basa di dati. In tali applicazioni, ci hè spessu bisognu di replicazione di dati.

Cumu l'esitatu sopra, Tarantool hà una replicazione di dati integrata. U principiu di u so funziunamentu hè di eseguisce sequenzialmente nantu à e rèpliche tutte e transazzione cuntenute in u logu maestru (WAL). Di solitu tali replicazione (avemu più chjamatu livellu bassu) hè aduprata per assicurà a tolleranza à i difetti di l'applicazione è / o per distribuisce a carica di lettura trà i nodi di cluster.

Replicazione di altu livellu in Tarantool DBMS
Risu. 1. Replicazione in un cluster

Un esempiu di un scenariu alternativu seria u trasferimentu di dati creati in una basa di dati à una altra basa di dati per u processu / monitoraghju. In l'ultimu casu, una suluzione più còmuda pò esse di utilizà altu livellu replicazione - replicazione di dati à u livellu di logica cummerciale di l'applicazione. Quelli. Ùn usemu micca una soluzione pronta integrata in u DBMS, ma implementemu a replicazione per noi stessu in l'applicazione chì sviluppemu. Stu approcciu hà dui vantaghji è svantaghji. Elenchemu i vantaghji.

1. Risparmiu di trafficu:

  • Ùn pudete micca trasfiriri tutti i dati, ma solu una parte di questu (per esempiu, pudete trasfiriri solu qualchi tavulini, alcune di e so culonni o registri chì risponde à un certu criteriu);
  • A cuntrariu di a replicazione di livellu bassu, chì hè realizatu continuamente in modu asincronu (implementatu in a versione attuale di Tarantool - 1.10) o sincronu (per esse implementatu in versioni successive di Tarantool), a replicazione di altu livellu pò esse realizatu in sessioni (vale à dì, l'applicazione prima sincronizza i dati - una data di sessione di scambiu, dopu ci hè una pausa in a replicazione, dopu chì a prossima sessione di scambiu si trova, etc.);
  • se un registru hà cambiatu parechje volte, pudete trasferisce solu a so ultima versione (a cuntrariu di a replicazione di bassu livellu, in quale tutti i cambiamenti fatti nantu à u maestru seranu ghjucati in sequenza nantu à e rèpliche).

2. Ùn ci hè micca difficultà cù l'implementazione di u scambiu HTTP, chì permette di sincronizà e basa di dati remoti.

Replicazione di altu livellu in Tarantool DBMS
Risu. 2. Replicazione nantu à HTTP

3. E strutture di basa di dati trà quale a data hè trasferita ùn deve esse micca listessi (in più, in u casu generale, hè ancu pussibule di utilizà diverse DBMS, linguaggi di prugrammazione, piattaforme, etc.).

Replicazione di altu livellu in Tarantool DBMS
Risu. 3. Replicazione in sistemi eterogenei

U svantaghju hè chì, in media, a prugrammazione hè più difficiuli/costu chè a cunfigurazione, è invece di persunalizà a funziunalità integrata, avete da implementà u vostru propiu.

Se in a vostra situazione i vantaghji sopra sò cruciali (o sò una cundizione necessaria), allora hè sensu di utilizà a replicazione d'altu livellu. Fighjemu parechje manere di implementà a replicazione di dati d'altu livellu in u DBMS Tarantool.

Minimizazione di u trafficu

Dunque, unu di i vantaghji di a replicazione d'altu livellu hè u risparmiu di trafficu. Per fà stu vantaghju per esse realizatu cumplettamente, hè necessariu di minimizzà a quantità di dati trasferiti durante ogni sessione di scambiu. Di sicuru, ùn devemu micca scurdatu chì à a fine di a sessione, u receptore di dati deve esse sincronizatu cù a fonte (almenu per quella parte di e dati chì hè implicatu in a replicazione).

Cumu minimizzà a quantità di dati trasferiti durante a replicazione d'altu livellu? Una soluzione simplice puderia esse selezziunà e dati per data è ora. Per fà questu, pudete aduprà u campu di data-ora chì esiste digià in a tavula (se esiste). Per esempiu, un documentu "ordine" pò avè un campu "tempu di esecuzione di l'ordine necessariu" - delivery_time. U prublema cù sta suluzione hè chì i valori in questu campu ùn anu micca esse in a sequenza chì currisponde à a creazione di ordini. Allora ùn pudemu micca ricurdà u valore massimu di u campu delivery_time, trasmessa durante a sessione di scambiu precedente, è durante a prossima sessione di scambiu selezziunate tutti i registri cù un valore di campu più altu delivery_time. I registri cù un valore di campu più bassu pò esse aghjuntu trà e sessioni di scambiu delivery_time. Inoltre, l'ordine puderia avè subitu cambiamenti, chì però ùn anu micca affettatu u campu delivery_time. In i dui casi, i cambiamenti ùn saranu micca trasferiti da a fonte à u destinazione. À scioglie sti prublemi, avemu bisognu di trasfiriri dati "overlapping". Quelli. in ogni sessione di scambiu avemu da trasfiriri tutti i dati cù u valore di u campu delivery_time, sopra à qualchì puntu in u passatu (per esempiu, N ore da u mumentu attuale). In ogni casu, hè ovvi chì per i grandi sistemi stu approcciu hè assai redundante è pò riduce u risparmiu di trafficu chì avemu striving for à nunda. Inoltre, a tavula trasferita ùn pò micca avè un campu assuciatu cù una data-ora.

Una altra suluzione, più cumplessa in quantu à l'implementazione, hè di ricunnosce a ricezione di dati. In questu casu, durante ogni sessione di scambiu, tutte e dati sò trasmessi, a ricivuta di quale ùn hè micca stata cunfirmata da u destinatariu. Per implementà questu, avete bisognu di aghjunghje una colonna booleana à a tavola fonte (per esempiu, is_transferred). Se u ricevitore ricunnosce u ricivutu di u recordu, u campu currispondente piglia u valore true, dopu chì l'entrata ùn hè più implicata in scambii. Questa opzione di implementazione hà i seguenti svantaghji. Prima, per ogni record trasferitu, un ricunniscenza deve esse generatu è mandatu. À pocu pressu, questu puderia esse paragunabile à duppià a quantità di dati trasferiti è chì porta à radduppià u numeru di andata e ritorno. Siconda, ùn ci hè micca a pussibilità di mandà u stessu registru à parechji receptori (u primu ricevitore à riceve cunfirmà a ricivuta per ellu stessu è per tutti l'altri).

Un metudu chì ùn hà micca i disadvantages datu sopra hè di aghjunghje una colonna à a tavula trasmessa per seguità i cambiamenti in e so fila. Una tale colonna pò esse di tippu di data-ora è deve esse stabilita / aghjurnata da l'applicazione à l'ora attuale ogni volta chì i registri sò aghjuntu / cambiati (atomicamente cù l'aghjunzione / cambiamentu). Per esempiu, chjamemu a colonna update_time. Salvendu u valore massimu di u campu di sta colonna per i registri trasferiti, pudemu inizià a prossima sessione di scambiu cù stu valore (selezziunà i registri cù u valore di u campu). update_time, superendu u valore precedentemente almacenatu). U prublema cù l'ultimu approcciu hè chì i cambiamenti di dati ponu accade in batch. In u risultatu di i valori di u campu in a colonna update_time pò micca esse unicu. Cusì, sta colonna ùn pò micca esse aduprata per l'output di dati porzionati (pagina per pagina). Per vede dati pagina per pagina, avete da inventà meccanismi supplementari chì probabilmente anu una efficienza assai bassa (per esempiu, ricuperà da a basa di dati tutti i registri cù u valore. update_time più altu ch'è un datu è pruduce un certu nùmeru di registri, partendu da un certu offset da u principiu di u sample).

Pudete migliurà l'efficienza di u trasferimentu di dati migliurendu pocu l'approcciu precedente. Per fà questu, useremu u tipu interu (interu longu) cum'è i valori di u campu di a colonna per seguità i cambiamenti. Chjamemu a colonna row_ver. U valore di u campu di sta colonna deve esse sempre stabilitu / aghjurnatu ogni volta chì un registru hè creatu / mudificatu. Ma in questu casu, u campu ùn serà micca attribuitu a data-ora attuale, ma u valore di qualchì contatore, aumentatu da unu. In u risultatu, a colonna row_ver cuntene valori unichi è ponu esse aduprati micca solu per visualizà dati "delta" (dati aghjuntu / cambiatu da a fine di a sessione di scambiu precedente), ma ancu per sparghje in pagine in modu simplice è efficace.

L'ultimu mètudu prupostu di minimizzà a quantità di dati trasferiti in u quadru di replicazione d'altu livellu mi pari u più ottimali è universale. Fighjemu in più detail.

Passà Dati Utilizendu un Contatore di Versione di Fila

Implementazione di u servitore / parte maestru

In MS SQL Server, ci hè un tipu di colonna speciale per implementà stu approcciu - rowversion. Ogni basa di dati hà un contatore chì aumenta da unu ogni volta chì un record hè aghjuntu / cambiatu in una tavula chì hà una colonna cum'è rowversion. U valore di stu contatore hè automaticamente assignatu à u campu di sta colonna in u record aghjuntu / cambiatu. U DBMS Tarantool ùn hà micca un mecanismu integratu simili. Tuttavia, in Tarantool ùn hè micca difficiule di implementà manualmente. Fighjemu cumu si faci questu.

Prima, un pocu di terminologia: i tavule in Tarantool sò chjamati spazii, è i registri sò chjamati tuples. In Tarantool pudete creà sequenze. E sequenze ùn sò più cà generatori chjamati di valori interi ordinati. Quelli. questu hè esattamente ciò chì avemu bisognu per i nostri scopi. Sottu avemu da creà un tali sequenza.

Prima di fà qualsiasi operazione di basa di dati in Tarantool, avete bisognu di eseguisce u cumandimu seguente:

box.cfg{}

In u risultatu, Tarantool hà da cumincià à scrive snapshots di basa di dati è logs di transazzione in u cartulare attuale.

Creemu una sequenza row_version:

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

Opzione if_not_exists permette à u script di creazione per esse eseguitu parechje volte: se l'ughjettu esiste, Tarantool ùn pruvà micca di creà di novu. Questa opzione serà aduprata in tutti i cumandamenti DDL successivi.

Creemu un spaziu cum'è un esempiu.

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

Quì avemu stabilitu u nome di u spaziu (goods), nomi di campu è i so tipi.

I campi auto-incrementanti in Tarantool sò ancu creati cù sequenze. Creemu una chjave primaria auto-incrementante per campu 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 supporta parechji tipi d'indici. L'indici più cumunimenti usati sò i tipi TREE è HASH, chì sò basati nantu à strutture currispondenti à u nome. TREE hè u tipu d'indici più versatile. Si permette à voi à ritruvà dati in una manera urganizata. Ma per a selezzione di ugualità, HASH hè più adattatu. Per quessa, hè cunsigliatu di utilizà HASH per a chjave primaria (chì hè ciò chì avemu fattu).

Per utilizà a colonna row_ver per trasfiriri dati cambiati, avete bisognu di ligà i valori di sequenza à i campi di sta colonna row_ver. Ma à u cuntrariu di a chjave primaria, u valore di u campu di a colonna row_ver duverebbe aumentà da unu micca solu quandu aghjunghjenu novi registri, ma ancu quandu cambiate quelli esistenti. Pudete aduprà triggers per questu. Tarantool hà dui tipi di scatuli spaziali: before_replace и on_replace. I triggers sò sparati ogni volta chì i dati in u spaziu cambianu (per ogni tupla affettata da i cambiamenti, una funzione trigger hè lanciata). A cuntrariu on_replace, before_replace-triggers permettenu di mudificà i dati di a tupla per quale u trigger hè eseguitu. Per quessa, l'ultimu tipu di triggers ci cunvene.

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

U trigger seguente rimpiazza u valore di u campu row_ver tuple guardatu à u prossimu valore di a sequenza row_version.

Per esse in gradu di caccià dati da u spaziu goods per colonna row_ver, creemu un indice:

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

Tipu d'indice - arbre (TREE), perchè avemu bisognu di caccià i dati in ordine crescente di i valori in a colonna row_ver.

Aghjunghjemu qualchi dati à u spaziu:

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}

Perchè U primu campu hè un contatore auto-incrementante; invece passemu nil. Tarantool sustituverà automaticamente u prossimu valore. In listessu modu, cum'è u valore di i campi di colonna row_ver pudete passà nil - o micca specificà u valore in tuttu, perchè sta colonna occupa l'ultima pusizioni in u spaziu.

Cuntrollamu u risultatu di l'inserzione:

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

Comu pudete vede, i primi è l'ultimi campi sò riempiti automaticamente. Avà serà faciule scrive una funzione per a carica pagina per pagina di cambiamenti di spaziu 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

A funzione piglia cum'è paràmetru u valore row_ver, partendu da quale hè necessariu di scaricà cambiamenti, è torna una parte di i dati cambiati.

U campionamentu di dati in Tarantool hè fattu per mezu di indici. Funzione get_goods usa un iteratore per indice row_ver per riceve dati cambiati. U tipu di iteratore hè GT (Greater Than, più grande di). Questu significa chì l'iteratore traverserà in sequenza i valori di l'indice partendu da a chjave passata (valore di campu row_ver).

L'iteratore torna tuple. Per pudè dopu trasfiriri dati via HTTP, hè necessariu di cunvertisce e tuple in una struttura cunvene per a serializazione successiva. L'esempiu usa a funzione standard per questu tomap. Invece di utilizà tomap pudete scrive a vostra propria funzione. Per esempiu, pudemu vulemu rinumate un campu name, ùn passà u campu code è aghjunghje un campu 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

A dimensione di a pagina di i dati di output (u nùmeru di registri in una parte) hè determinata da a variàbile page_size. In l'esempiu u valore page_size hè 5. In un veru prugramma, a dimensione di a pagina di solitu importa più. Dipende da a dimensione media di a tupla spaziale. A dimensione ottima di a pagina pò esse determinata empiricamente per mezu di u tempu di trasferimentu di dati. A più grande hè a dimensione di a pagina, u più chjucu u numeru di roundtrips trà i lati di l'inviu è u ricivutu. In questu modu, pudete riduce u tempu generale per scaricà i cambiamenti. In ogni casu, se a dimensione di a pagina hè troppu grande, passeremu troppu longu nantu à u servitore serializing the sample. In u risultatu, pò esse ritardi in u processu di altre dumande chì venenu à u servitore. Parametru page_size pò esse caricatu da u schedariu di cunfigurazione. Per ogni spaziu trasmessu, pudete stabilisce u so propiu valore. In ogni casu, per a maiò parte di i spazii u valore predeterminatu (per esempiu, 100) pò esse adattatu.

Eseguimu a funzione 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
...

Pigliemu u valore di u campu row_ver da l'ultima linea è chjamate a funzione di novu:

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

Torna una volta:

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

Comu pudete vede, quandu s'utilice in questu modu, a funzione torna tutti i registri spaziali pagina per pagina goods. L'ultima pagina hè seguita da una selezzione viota.

Facemu cambiamenti à u spaziu:

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

Avemu cambiatu u valore di u campu name per una entrata è aghjunghje dui novi entrate.

Ripitemu l'ultima funzione chjamata:

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

A funzione hà tornatu i registri cambiati è aghjunti. Allora a funzione get_goods permette di riceve dati chì hà cambiatu da a so ultima chjamata, chì hè a basa di u metudu di replicazione in cunsiderà.

Lasceremu l'emissione di risultati via HTTP in forma di JSON fora di u scopu di stu articulu. Pudete leghje nantu à questu quì: https://habr.com/ru/company/mailru/blog/272141/

Implementazione di a parte client/slave

Fighjemu ciò chì l'implementazione di u latu ricevente pare. Creemu un spaziu in u latu di ricezione per almacenà i dati scaricati:

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

A struttura di u spaziu s'assumiglia à a struttura di u spaziu in a fonte. Ma siccomu ùn avemu da passà i dati ricevuti in ogni locu, a colonna row_ver ùn hè micca in u spaziu di u destinatariu. In campu id identificatori di fonte seranu registrati. Dunque, da u latu di u ricevitore ùn ci hè bisognu di fà l'autu-incrementing.

Inoltre, avemu bisognu di un spaziu per salvà i valori 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
})

Per ogni spaziu caricatu (campu space_name) salveremu l'ultimu valore caricatu quì row_ver (campu value). A colonna agisce cum'è a chjave primaria space_name.

Creemu una funzione per carica dati spaziali goods via HTTP. Per fà questu, avemu bisognu di una biblioteca chì implementa un cliente HTTP. A seguente linea carica a biblioteca è instantiate u cliente HTTP:

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

Avemu ancu bisognu di una biblioteca per a deserializazione json:

local json = require('json')

Questu hè abbastanza per creà una funzione di carica di dati:

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

A funzione eseguisce una dumanda HTTP à l'indirizzu url è u manda row_ver cum'è un paràmetru è torna u risultatu deserializatu di a dumanda.

A funzione per salvà i dati ricevuti hè cusì:

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

Ciclu di salvezza di dati à u spaziu goods postu in una transazzione (a funzione hè aduprata per questu box.atomic) per riduce u numeru di operazioni di discu.

Infine, a funzione di sincronizazione spaziale lucale goods cù una fonte pudete implementà cusì:

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

Prima avemu lettu u valore salvatu prima row_ver per u spaziu goods. S'ellu manca (a prima sessione di scambiu), allora u pigliemu cum'è row_ver zeru. In seguitu in u ciculu facemu un scaricamentu pagina per pagina di i dati cambiati da a fonte à l'url specificata. À ogni iterazione, salvemu i dati ricevuti in u spaziu lucale appropritatu è aghjurnà u valore row_ver (in u spaziu row_ver è in a variabile row_ver) - piglià u valore row_ver da l'ultima linea di dati caricati.

Per pruteggiri contru à u looping accidintali (in casu di un errore in u prugramma), u ciclu while pò esse rimpiazzatu da for:

for _ = 1, max_req do ...

Cum'è u risultatu di eseguisce a funzione sync_goods spaziu goods u ricevitore cuntene l'ultime versioni di tutti i registri spaziali goods in a fonte.

Ovviamente, a cancellazione di dati ùn pò esse trasmessa in questu modu. Se un tali bisognu esiste, pudete aduprà una marca di eliminazione. Aghjunghjite à u spaziu goods campu booleanu is_deleted è invece di sguassà fisicamente un registru, usemu l'eliminazione logica - avemu stabilitu u valore di u campu is_deleted in significatu true. Calchì volta invece di un campu booleanu is_deleted hè più còmuda à aduprà u campu deleted, chì guarda a data-ora di l'eliminazione logica di u record. Dopu avè realizatu una eliminazione logica, u registru marcatu per a cancellazione serà trasferitu da a fonte à a destinazione (sicondu a logica discutata sopra).

Sequenza row_ver pò esse usatu per trasmette dati da altri spazii: ùn ci hè bisognu di creà una sequenza separata per ogni spaziu trasmessu.

Avemu vistu un modu efficace di replicazione di dati d'altu livellu in l'applicazioni chì utilizanu u DBMS Tarantool.

scuperti

  1. Tarantool DBMS hè un pruduttu attraente è promettente per a creazione di applicazioni d'alta carica.
  2. A replicazione di dati d'altu livellu hà una quantità di vantaghji nantu à a replicazione di livellu bassu.
  3. U metudu di replicazione d'altu livellu discutitu in l'articulu permette di minimizzà a quantità di dati trasferiti trasfirendu solu quelli registri chì anu cambiatu da l'ultima sessione di scambiu.

Source: www.habr.com

Add a comment