Replicatie op hoog niveau in Tarantool DBMS

Hallo, ik maak applicaties voor DBMS Tarantool is een platform ontwikkeld door Mail.ru Group dat een krachtig DBMS en een applicatieserver in de Lua-taal combineert. De hoge snelheid van oplossingen op basis van Tarantool wordt met name bereikt door ondersteuning van de in-memory-modus van het DBMS en de mogelijkheid om applicatie-bedrijfslogica uit te voeren in een enkele adresruimte met gegevens. Tegelijkertijd wordt de persistentie van de gegevens verzekerd door middel van ACID-transacties (er wordt een WAL-logboek op de schijf bijgehouden). Tarantool heeft ingebouwde ondersteuning voor replicatie en sharding. Vanaf versie 2.1 worden queries in de SQL-taal ondersteund. Tarantool is open source en gelicentieerd onder de Simplified BSD-licentie. Er is ook een commerciële Enterprise-versie.

Replicatie op hoog niveau in Tarantool DBMS
Voel de kracht! (…ook wel genieten van de voorstelling)

Al het bovenstaande maakt Tarantool een aantrekkelijk platform voor het maken van toepassingen met hoge belasting die met databases werken. Bij dergelijke toepassingen is er vaak behoefte aan gegevensreplicatie.

Zoals hierboven vermeld, heeft Tarantool ingebouwde gegevensreplicatie. Het principe van de werking ervan is om op replica's alle transacties in de masterlog (WAL) opeenvolgend uit te voeren. Meestal is een dergelijke replicatie (we zullen het verder noemen laag niveau) wordt gebruikt om de fouttolerantie van toepassingen te garanderen en/of om de leesbelasting tussen clusterknooppunten te verdelen.

Replicatie op hoog niveau in Tarantool DBMS
Rijst. 1. Replicatie binnen een cluster

Een voorbeeld van een alternatief scenario is het overbrengen van gegevens die in de ene database zijn gemaakt naar een andere database voor verwerking/monitoring. In het laatste geval kan het gebruik van een handiger oplossing zijn hoog niveau replicatie - gegevensreplicatie op het bedrijfslogicaniveau van de applicatie. Die. We gebruiken geen kant-en-klare oplossing ingebouwd in het DBMS, maar implementeren zelf replicatie binnen de applicatie die we ontwikkelen. Deze aanpak heeft zowel voor- als nadelen. Laten we de voordelen op een rij zetten.

1. Verkeersbesparingen:

  • U kunt niet alle gegevens overbrengen, maar slechts een deel ervan (u kunt bijvoorbeeld slechts enkele tabellen, enkele van hun kolommen of records overbrengen die aan een bepaald criterium voldoen);
  • In tegenstelling tot replicatie op laag niveau, die continu wordt uitgevoerd in de asynchrone (geïmplementeerd in de huidige versie van Tarantool - 1.10) of synchrone (te implementeren in volgende versies van Tarantool) modus, kan replicatie op hoog niveau worden uitgevoerd in sessies (d.w.z. de applicatie synchroniseert eerst de gegevens - een gegevensuitwisselingssessie, daarna is er een pauze in de replicatie, waarna de volgende uitwisselingssessie plaatsvindt, enz.);
  • als een record meerdere keren is gewijzigd, kunt u alleen de nieuwste versie overbrengen (in tegenstelling tot replicatie op laag niveau, waarbij alle wijzigingen die op de master zijn aangebracht, opeenvolgend op de replica's worden afgespeeld).

2. Er zijn geen problemen bij het implementeren van HTTP-uitwisseling, waarmee u externe databases kunt synchroniseren.

Replicatie op hoog niveau in Tarantool DBMS
Rijst. 2. Replicatie via HTTP

3. De databasestructuren waartussen gegevens worden overgedragen hoeven niet dezelfde te zijn (bovendien is het in het algemeen zelfs mogelijk om verschillende DBMS'en, programmeertalen, platforms, enz. te gebruiken).

Replicatie op hoog niveau in Tarantool DBMS
Rijst. 3. Replicatie in heterogene systemen

Het nadeel is dat programmeren gemiddeld moeilijker/duurder is dan configuratie, en in plaats van de ingebouwde functionaliteit aan te passen, zul je je eigen functionaliteit moeten implementeren.

Als in jouw situatie bovenstaande voordelen cruciaal zijn (of een noodzakelijke voorwaarde zijn), dan is het zinvol om replicatie op hoog niveau in te zetten. Laten we eens kijken naar verschillende manieren om gegevensreplicatie op hoog niveau te implementeren in het Tarantool DBMS.

Verkeersminimalisatie

Een van de voordelen van replicatie op hoog niveau is dus verkeersbesparing. Om dit voordeel volledig te kunnen realiseren, is het noodzakelijk om de hoeveelheid gegevens die tijdens elke uitwisselingssessie wordt overgedragen te minimaliseren. Uiteraard mogen we niet vergeten dat aan het einde van de sessie de dataontvanger gesynchroniseerd moet worden met de bron (althans voor dat deel van de data dat betrokken is bij replicatie).

Hoe minimaliseer ik de hoeveelheid gegevens die wordt overgedragen tijdens replicatie op hoog niveau? Een eenvoudige oplossing zou kunnen zijn om gegevens op datum en tijd te selecteren. Om dit te doen, kunt u het datum-tijdveld gebruiken dat al in de tabel bestaat (als dit bestaat). Een “order”-document kan bijvoorbeeld het veld “vereiste uitvoeringstijd van de order” hebben - delivery_time. Het probleem met deze oplossing is dat de waarden in dit veld niet in de volgorde hoeven te staan ​​die overeenkomt met het aanmaken van orders. We kunnen de maximale veldwaarde dus niet onthouden delivery_time, verzonden tijdens de vorige uitwisselingssessie, en selecteer tijdens de volgende uitwisselingssessie alle records met een hogere veldwaarde delivery_time. Het kan zijn dat records met een lagere veldwaarde tussen uitwisselingssessies zijn toegevoegd delivery_time. Ook had de bestelling wijzigingen kunnen ondergaan, die desalniettemin geen invloed hadden op het veld delivery_time. In beide gevallen worden de wijzigingen niet van de bron naar de bestemming overgebracht. Om deze problemen op te lossen, zullen we gegevens "overlappend" moeten overbrengen. Die. bij elke uitwisselingssessie dragen we alle gegevens met de veldwaarde over delivery_time, die een bepaald punt in het verleden overschrijdt (bijvoorbeeld N uur vanaf het huidige moment). Het is echter duidelijk dat deze aanpak voor grote systemen zeer redundant is en de verkeersbesparingen waar we naar streven tot niets kan reduceren. Bovendien mag de tabel die wordt overgedragen geen veld hebben dat aan een datum-tijd is gekoppeld.

Een andere oplossing, complexer qua implementatie, is het bevestigen van de ontvangst van gegevens. In dit geval worden tijdens elke uitwisselingssessie alle gegevens verzonden waarvan de ontvangst niet door de ontvanger is bevestigd. Om dit te implementeren, moet u een Booleaanse kolom aan de brontabel toevoegen (bijvoorbeeld is_transferred). Als de ontvanger de ontvangst van het record bevestigt, neemt het overeenkomstige veld de waarde over true, waarna de inzending niet langer betrokken is bij uitwisselingen. Deze implementatieoptie heeft de volgende nadelen. Ten eerste moet voor elk overgedragen record een ontvangstbevestiging worden gegenereerd en verzonden. Grofweg zou dit vergelijkbaar kunnen zijn met een verdubbeling van de hoeveelheid overgedragen gegevens, wat zou leiden tot een verdubbeling van het aantal retourvluchten. Ten tweede is het niet mogelijk om hetzelfde record naar meerdere ontvangers te sturen (de eerste ontvanger die deze ontvangt, bevestigt de ontvangst voor zichzelf en voor alle anderen).

Een methode die de hierboven gegeven nadelen niet heeft, is het toevoegen van een kolom aan de overgedragen tabel om veranderingen in de rijen bij te houden. Zo'n kolom kan van het datum-tijd-type zijn en moet door de applicatie worden ingesteld/bijgewerkt naar de huidige tijd telkens wanneer records worden toegevoegd/gewijzigd (atomisch met de toevoeging/wijziging). Laten we als voorbeeld de kolom noemen update_time. Door de maximale veldwaarde van deze kolom op te slaan voor de overgedragen records, kunnen we de volgende uitwisselingssessie met deze waarde starten (selecteer records met de veldwaarde update_time, die de eerder opgeslagen waarde overschrijdt). Het probleem met deze laatste aanpak is dat gegevenswijzigingen batchgewijs kunnen plaatsvinden. Als gevolg van de veldwaarden in de kolom update_time is misschien niet uniek. Deze kolom kan dus niet worden gebruikt voor geportioneerde (pagina-voor-pagina) gegevensuitvoer. Om gegevens pagina voor pagina weer te geven, zult u aanvullende mechanismen moeten uitvinden die hoogstwaarschijnlijk een zeer lage efficiëntie zullen hebben (bijvoorbeeld door alle records met de waarde uit de database op te halen update_time hoger is dan een gegeven en een bepaald aantal records produceert, beginnend vanaf een bepaalde offset vanaf het begin van de steekproef).

U kunt de efficiëntie van de gegevensoverdracht verbeteren door de vorige aanpak enigszins te verbeteren. Om dit te doen, zullen we het type geheel getal (lang geheel getal) gebruiken als kolomveldwaarden voor het bijhouden van wijzigingen. Laten we de kolom een ​​naam geven row_ver. De veldwaarde van deze kolom moet nog steeds worden ingesteld/bijgewerkt telkens wanneer een record wordt aangemaakt/gewijzigd. Maar in dit geval krijgt het veld niet de huidige datum-tijd toegewezen, maar de waarde van een teller, verhoogd met één. Het gevolg is dat de kolom row_ver zal unieke waarden bevatten en kan niet alleen worden gebruikt om “delta”-gegevens weer te geven (gegevens toegevoegd/gewijzigd sinds het einde van de vorige uitwisselingssessie), maar ook om deze eenvoudig en effectief op te splitsen in pagina’s.

De laatst voorgestelde methode om de hoeveelheid overgedragen gegevens te minimaliseren in het kader van replicatie op hoog niveau lijkt mij de meest optimale en universele. Laten we het in meer detail bekijken.

Gegevens doorgeven met behulp van een rijversieteller

Implementatie van het server/master gedeelte

In MS SQL Server is er een speciaal kolomtype om deze aanpak te implementeren: rowversion. Elke database heeft een teller die met één wordt verhoogd telkens wanneer een record wordt toegevoegd/gewijzigd in een tabel met een kolom zoals rowversion. De waarde van deze teller wordt automatisch toegewezen aan het veld van deze kolom in het toegevoegde/gewijzigde record. Het Tarantool DBMS heeft geen soortgelijk ingebouwd mechanisme. In Tarantool is het echter niet moeilijk om het handmatig te implementeren. Laten we eens kijken hoe dit wordt gedaan.

Eerst een beetje terminologie: tabellen in Tarantool worden spaties genoemd, en records worden tupels genoemd. In Tarantool kun je reeksen maken. Reeksen zijn niets meer dan benoemde generatoren van geordende gehele waarden. Die. dit is precies wat we nodig hebben voor onze doeleinden. Hieronder zullen we zo'n reeks maken.

Voordat u een databasebewerking in Tarantool uitvoert, moet u de volgende opdracht uitvoeren:

box.cfg{}

Als gevolg hiervan begint Tarantool database-snapshots en transactielogboeken naar de huidige map te schrijven.

Laten we een reeks maken row_version:

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

optie if_not_exists staat toe dat het creatiescript meerdere keren wordt uitgevoerd: als het object bestaat, zal Tarantool niet proberen het opnieuw te maken. Deze optie wordt gebruikt in alle volgende DDL-opdrachten.

Laten we als voorbeeld een ruimte maken.

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

Hier stellen we de naam van de ruimte in (goods), veldnamen en hun typen.

Automatisch oplopende velden in Tarantool worden ook gemaakt met behulp van reeksen. Laten we een automatisch oplopende primaire sleutel per veld maken 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 ondersteunt verschillende soorten indexen. De meest gebruikte indexen zijn TREE- en HASH-typen, die zijn gebaseerd op structuren die overeenkomen met de naam. TREE is het meest veelzijdige indextype. Hiermee kunt u gegevens op een georganiseerde manier ophalen. Maar voor gelijkheidsselectie is HASH geschikter. Daarom is het raadzaam om HASH voor de primaire sleutel te gebruiken (wat we ook hebben gedaan).

Om de kolom te gebruiken row_ver om gewijzigde gegevens over te dragen, moet u reekswaarden aan de velden van deze kolom binden row_ver. Maar in tegenstelling tot de primaire sleutel, de kolomveldwaarde row_ver zou niet alleen met één moeten toenemen bij het toevoegen van nieuwe records, maar ook bij het wijzigen van bestaande records. Hiervoor kun je triggers gebruiken. Tarantool heeft twee soorten ruimtetriggers: before_replace и on_replace. Triggers worden geactiveerd wanneer de gegevens in de ruimte veranderen (voor elke tuple die door de wijzigingen wordt beïnvloed, wordt een triggerfunctie gestart). in tegenstelling tot on_replace, before_replaceMet -triggers kunt u de gegevens wijzigen van de tupel waarvoor de trigger wordt uitgevoerd. Dienovereenkomstig past het laatste type triggers bij ons.

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

De volgende trigger vervangt de veldwaarde row_ver opgeslagen tupel naar de volgende waarde van de reeks row_version.

Om data uit de ruimte te kunnen halen goods per kolom row_ver, laten we een index maken:

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

Indextype - boom (TREE), omdat we zullen de gegevens moeten extraheren in oplopende volgorde van de waarden in de kolom row_ver.

Laten we wat gegevens aan de ruimte toevoegen:

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}

Omdat Het eerste veld is een automatisch oplopende teller; in plaats daarvan passeren we nul. Tarantool vervangt automatisch de volgende waarde. Op dezelfde manier als de waarde van de kolomvelden row_ver je kunt nul doorgeven - of de waarde helemaal niet opgeven, omdat deze kolom bezet de laatste positie in de ruimte.

Laten we het invoegresultaat controleren:

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

Zoals u kunt zien, worden het eerste en het laatste veld automatisch ingevuld. Nu zal het gemakkelijk zijn om een ​​functie te schrijven voor het pagina-voor-pagina uploaden van ruimtewijzigingen 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

De functie neemt als parameter de waarde row_ver, vanaf waar het nodig is om wijzigingen te verwijderen, en retourneert een deel van de gewijzigde gegevens.

Gegevensbemonstering in Tarantool gebeurt via indexen. Functie get_goods gebruikt een iterator per index row_ver gewijzigde gegevens ontvangen. Iteratortype is GT (groter dan, groter dan). Dit betekent dat de iterator opeenvolgend de indexwaarden zal doorlopen, beginnend bij de doorgegeven sleutel (veldwaarde row_ver).

De iterator retourneert tupels. Om vervolgens gegevens via HTTP te kunnen overbrengen, is het noodzakelijk om de tupels om te zetten naar een structuur die geschikt is voor latere serialisatie. In het voorbeeld wordt hiervoor de standaardfunctie gebruikt tomap. In plaats van gebruiken tomap u kunt uw eigen functie schrijven. We willen bijvoorbeeld de naam van een veld wijzigen name, passeer het veld niet code en voeg een veld toe 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

De paginagrootte van de uitvoergegevens (het aantal records in één portie) wordt bepaald door de variabele page_size. In het voorbeeld de waarde page_size is 5. In een echt programma is de paginagrootte meestal belangrijker. Het hangt af van de gemiddelde grootte van het ruimtetupel. Het optimale paginaformaat kan empirisch worden bepaald door de gegevensoverdrachttijd te meten. Hoe groter het paginaformaat, hoe kleiner het aantal retourvluchten tussen de verzendende en ontvangende kant. Op deze manier kunt u de totale tijd voor het downloaden van wijzigingen verkorten. Als het paginaformaat echter te groot is, zullen we te lang op de server doorbrengen met het serialiseren van het voorbeeld. Als gevolg hiervan kunnen er vertragingen optreden bij het verwerken van andere verzoeken die naar de server komen. Parameter page_size kan vanuit het configuratiebestand worden geladen. Voor elke verzonden ruimte kunt u een eigen waarde instellen. Voor de meeste spaties kan de standaardwaarde (bijvoorbeeld 100) echter geschikt zijn.

Laten we de functie uitvoeren 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
...

Laten we de veldwaarde nemen row_ver vanaf de laatste regel en roep de functie opnieuw aan:

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

Alweer:

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

Zoals u kunt zien, retourneert de functie, wanneer deze op deze manier wordt gebruikt, alle ruimterecords pagina voor pagina goods. De laatste pagina wordt gevolgd door een lege selectie.

Laten we wijzigingen aanbrengen in de ruimte:

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

We hebben de veldwaarde gewijzigd name voor één inzending en twee nieuwe inzendingen toegevoegd.

Laten we de laatste functieaanroep herhalen:

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

De functie retourneerde de gewijzigde en toegevoegde records. De functie dus get_goods Hiermee kunt u gegevens ontvangen die zijn gewijzigd sinds de laatste oproep, wat de basis vormt van de replicatiemethode die wordt overwogen.

Het uitgeven van resultaten via HTTP in de vorm van JSON laten we buiten het bestek van dit artikel. Hier kun je meer over lezen: https://habr.com/ru/company/mailru/blog/272141/

Implementatie van het client/slave-gedeelte

Laten we eens kijken hoe de implementatie van de ontvangende kant eruit ziet. Laten we een ruimte aan de ontvangende kant maken om de gedownloade gegevens op te slaan:

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

De structuur van de ruimte lijkt op de structuur van de ruimte in de bron. Maar aangezien we de ontvangen gegevens nergens anders gaan doorgeven, is de column row_ver bevindt zich niet in de ruimte van de ontvanger. In het veld id bronidentificaties worden geregistreerd. Daarom is het aan de ontvangerzijde niet nodig om het automatisch te verhogen.

Bovendien hebben we ruimte nodig om waarden op te slaan 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
})

Voor elke geladen ruimte (field space_name) slaan we hier de laatst geladen waarde op row_ver (veld value). De kolom fungeert als de primaire sleutel space_name.

Laten we een functie maken om ruimtegegevens te laden goods via HTTP. Om dit te doen hebben we een bibliotheek nodig die een HTTP-client implementeert. Met de volgende regel wordt de bibliotheek geladen en wordt de HTTP-client geïnstantieerd:

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

We hebben ook een bibliotheek nodig voor json-deserialisatie:

local json = require('json')

Dit is voldoende om een ​​functie voor het laden van gegevens te creëren:

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

De functie voert een HTTP-verzoek uit naar het URL-adres en verzendt dit row_ver als parameter en retourneert het gedeserialiseerde resultaat van de aanvraag.

De functie voor het opslaan van ontvangen gegevens ziet er als volgt uit:

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

Cyclus van het opslaan van gegevens in de ruimte goods in een transactie geplaatst (hiervoor wordt de functie gebruikt box.atomic) om het aantal schijfbewerkingen te verminderen.

Tenslotte de synchronisatiefunctie van de lokale ruimte goods met een bron kun je het als volgt implementeren:

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

Eerst lezen we de eerder opgeslagen waarde row_ver voor ruimte goods. Als het ontbreekt (de eerste uitwisselingssessie), nemen we het als row_ver nul. Vervolgens voeren we in de cyclus een pagina-voor-pagina download uit van de gewijzigde gegevens van de bron op de opgegeven URL. Bij elke iteratie slaan we de ontvangen gegevens op in de juiste lokale ruimte en werken we de waarde bij row_ver (in de ruimte row_ver en in de variabele row_ver) - neem de waarde row_ver vanaf de laatste regel met geladen gegevens.

Om te beschermen tegen onbedoelde herhaling (in geval van een fout in het programma), kan de lus while kan worden vervangen door for:

for _ = 1, max_req do ...

Als gevolg van het uitvoeren van de functie sync_goods ruimte goods de ontvanger bevat de nieuwste versies van alle ruimterecords goods in de bron.

Uiteraard kan het verwijderen van gegevens niet op deze manier worden uitgezonden. Als een dergelijke noodzaak bestaat, kunt u een verwijderteken gebruiken. Voeg toe aan ruimte goods Booleaans veld is_deleted en in plaats van een record fysiek te verwijderen, gebruiken we logische verwijdering - we stellen de veldwaarde in is_deleted in betekenis true. Soms in plaats van een Booleaans veld is_deleted het is handiger om het veld te gebruiken deleted, waarin de datum-tijd van de logische verwijdering van het record wordt opgeslagen. Na het uitvoeren van een logische verwijdering wordt het record dat is gemarkeerd voor verwijdering overgedragen van de bron naar de bestemming (volgens de hierboven besproken logica).

Volgorde row_ver kan worden gebruikt om gegevens uit andere ruimtes te verzenden: het is niet nodig om voor elke verzonden ruimte een aparte reeks te creëren.

We hebben gekeken naar een effectieve manier voor gegevensreplicatie op hoog niveau in applicaties met behulp van het Tarantool DBMS.

Bevindingen

  1. Tarantool DBMS is een aantrekkelijk, veelbelovend product voor het creëren van toepassingen met hoge belasting.
  2. Gegevensreplicatie op hoog niveau heeft een aantal voordelen ten opzichte van replicatie op laag niveau.
  3. Met de replicatiemethode op hoog niveau die in het artikel wordt besproken, kunt u de hoeveelheid overgedragen gegevens minimaliseren door alleen de records over te dragen die sinds de laatste uitwisselingssessie zijn gewijzigd.

Bron: www.habr.com

Voeg een reactie