Mataas na antas ng pagtitiklop sa Tarantool DBMS

Kumusta, gumagawa ako ng mga application para sa DBMS Tarantool ay isang platform na binuo ng Mail.ru Group na pinagsasama ang isang high-performance na DBMS at isang application server sa wikang Lua. Ang mataas na bilis ng mga solusyon batay sa Tarantool ay nakakamit, sa partikular, dahil sa suporta para sa in-memory mode ng DBMS at ang kakayahang magsagawa ng application business logic sa isang solong address space na may data. Kasabay nito, ang pagtitiyaga ng data ay sinisiguro gamit ang mga transaksyon sa ACID (isang WAL log ay pinananatili sa disk). Ang Tarantool ay may built-in na suporta para sa pagtitiklop at sharding. Simula sa bersyon 2.1, sinusuportahan ang mga query sa wikang SQL. Ang Tarantool ay open source at lisensyado sa ilalim ng Simplified BSD license. Mayroon ding komersyal na bersyon ng Enterprise.

Mataas na antas ng pagtitiklop sa Tarantool DBMS
Damahin ang kapangyarihan! (...aka enjoy sa performance)

Ginagawa ng lahat ng nasa itaas ang Tarantool na isang kaakit-akit na platform para sa paglikha ng mga high-load na application na gumagana sa mga database. Sa ganitong mga application, madalas na kailangan para sa pagtitiklop ng data.

Tulad ng nabanggit sa itaas, ang Tarantool ay may built-in na pagtitiklop ng data. Ang prinsipyo ng pagpapatakbo nito ay ang sunud-sunod na pagpapatupad sa mga replika ng lahat ng mga transaksyon na nakapaloob sa master log (WAL). Kadalasan ang ganitong pagtitiklop (tatawagin pa natin ito mababang antas) ay ginagamit para matiyak ang application fault tolerance at/o para ipamahagi ang reading load sa pagitan ng mga cluster node.

Mataas na antas ng pagtitiklop sa Tarantool DBMS
kanin. 1. Pagtitiklop sa loob ng isang kumpol

Ang isang halimbawa ng alternatibong senaryo ay ang paglilipat ng data na nilikha sa isang database patungo sa isa pang database para sa pagproseso/pagsubaybay. Sa huling kaso, ang isang mas maginhawang solusyon ay maaaring gamitin mataas na lebel pagtitiklop - pagtitiklop ng data sa antas ng lohika ng negosyo ng aplikasyon. Yung. Hindi kami gumagamit ng isang handa na solusyon na binuo sa DBMS, ngunit nagpapatupad ng pagtitiklop sa aming sarili sa loob ng application na aming binuo. Ang pamamaraang ito ay may parehong mga pakinabang at disadvantages. Ilista natin ang mga pakinabang.

1. Pagtitipid sa trapiko:

  • Hindi mo maaaring ilipat ang lahat ng data, ngunit bahagi lamang nito (halimbawa, maaari mo lamang ilipat ang ilang mga talahanayan, ilan sa kanilang mga hanay o talaan na nakakatugon sa isang tiyak na pamantayan);
  • Hindi tulad ng mababang antas ng pagtitiklop, na patuloy na isinasagawa sa asynchronous (ipinatupad sa kasalukuyang bersyon ng Tarantool - 1.10) o kasabay (ipapatupad sa mga susunod na bersyon ng Tarantool) mode, ang mataas na antas na pagtitiklop ay maaaring isagawa sa mga session (ibig sabihin, ang ang application ay unang nagsi-synchronize ng data - isang data ng exchange session, pagkatapos ay mayroong isang pause sa pagtitiklop, pagkatapos kung saan ang susunod na exchange session ay nangyayari, atbp.);
  • kung ang isang rekord ay nagbago ng ilang beses, maaari mo lamang ilipat ang pinakabagong bersyon nito (hindi tulad ng mababang antas na pagtitiklop, kung saan ang lahat ng mga pagbabagong ginawa sa master ay ipe-play pabalik nang sunud-sunod sa mga replika).

2. Walang mga paghihirap sa pagpapatupad ng HTTP exchange, na nagpapahintulot sa iyo na i-synchronize ang mga malalayong database.

Mataas na antas ng pagtitiklop sa Tarantool DBMS
kanin. 2. Pagtitiklop sa HTTP

3. Ang mga istruktura ng database sa pagitan ng kung saan ang data ay inililipat ay hindi kailangang maging pareho (bukod dito, sa pangkalahatang kaso, posible pa ring gumamit ng iba't ibang DBMS, programming language, platform, atbp.).

Mataas na antas ng pagtitiklop sa Tarantool DBMS
kanin. 3. Pagtitiklop sa magkakaibang sistema

Ang downside ay, sa karaniwan, ang programming ay mas mahirap/mahal kaysa sa configuration, at sa halip na i-customize ang built-in na functionality, kailangan mong ipatupad ang iyong sarili.

Kung sa iyong sitwasyon ang mga pakinabang sa itaas ay mahalaga (o isang kinakailangang kondisyon), kung gayon makatuwirang gumamit ng mataas na antas ng pagtitiklop. Tingnan natin ang ilang paraan para ipatupad ang mataas na antas ng replikasyon ng data sa Tarantool DBMS.

Pag-minimize ng trapiko

Kaya, ang isa sa mga pakinabang ng mataas na antas ng pagtitiklop ay ang pagtitipid sa trapiko. Upang ganap na maisakatuparan ang kalamangan na ito, kinakailangan upang mabawasan ang dami ng data na inilipat sa bawat sesyon ng palitan. Siyempre, hindi natin dapat kalimutan na sa pagtatapos ng session, ang data receiver ay dapat na naka-synchronize sa source (kahit na para sa bahaging iyon ng data na kasangkot sa pagtitiklop).

Paano bawasan ang dami ng data na inilipat sa panahon ng mataas na antas ng pagtitiklop? Ang isang tapat na solusyon ay maaaring pumili ng data ayon sa petsa at oras. Upang gawin ito, maaari mong gamitin ang field ng petsa-oras na mayroon na sa talahanayan (kung mayroon). Halimbawa, ang isang "order" na dokumento ay maaaring may field na "kinakailangang oras ng pagpapatupad ng order" - delivery_time. Ang problema sa solusyon na ito ay ang mga halaga sa larangang ito ay hindi kailangang nasa pagkakasunud-sunod na tumutugma sa paglikha ng mga order. Kaya hindi namin matandaan ang maximum na halaga ng field delivery_time, na ipinadala sa nakaraang exchange session, at sa susunod na exchange session piliin ang lahat ng record na may mas mataas na field value delivery_time. Maaaring naidagdag ang mga tala na may mas mababang halaga ng field sa pagitan ng mga exchange session delivery_time. Gayundin, ang order ay maaaring sumailalim sa mga pagbabago, na gayunpaman ay hindi nakakaapekto sa larangan delivery_time. Sa parehong mga kaso, ang mga pagbabago ay hindi ililipat mula sa pinagmulan patungo sa patutunguhan. Upang malutas ang mga problemang ito, kakailanganin naming maglipat ng data na "nagpapatong". Yung. sa bawat exchange session ililipat namin ang lahat ng data na may field value delivery_time, lumalampas sa ilang punto sa nakaraan (halimbawa, N oras mula sa kasalukuyang sandali). Gayunpaman, malinaw na para sa malalaking sistema ang diskarte na ito ay lubhang kalabisan at maaaring mabawasan ang pagtitipid sa trapiko na aming pinagsusumikapan. Bilang karagdagan, ang talahanayang inililipat ay maaaring walang field na nauugnay sa petsa-oras.

Ang isa pang solusyon, mas kumplikado sa mga tuntunin ng pagpapatupad, ay ang pagkilala sa pagtanggap ng data. Sa kasong ito, sa bawat sesyon ng palitan, ang lahat ng data ay ipinadala, ang pagtanggap nito ay hindi nakumpirma ng tatanggap. Upang ipatupad ito, kakailanganin mong magdagdag ng Boolean column sa source table (halimbawa, is_transferred). Kung kinikilala ng receiver ang pagtanggap ng record, ang katumbas na field ay kukuha ng halaga true, pagkatapos nito ay hindi na kasali ang entry sa mga palitan. Ang opsyon sa pagpapatupad na ito ay may mga sumusunod na disadvantages. Una, para sa bawat rekord na inilipat, isang pagkilala ay dapat mabuo at ipadala. Sa halos pagsasalita, ito ay maihahambing sa pagdodoble sa dami ng data na inilipat at humahantong sa pagdodoble ng bilang ng mga roundtrip. Pangalawa, walang posibilidad na magpadala ng parehong record sa ilang mga receiver (ang unang tatanggap na makatanggap ay magkukumpirma ng resibo para sa sarili nito at para sa lahat ng iba pa).

Ang isang paraan na walang mga disadvantages na ibinigay sa itaas ay ang magdagdag ng column sa ipinadalang talahanayan upang subaybayan ang mga pagbabago sa mga row nito. Ang nasabing column ay maaaring may uri ng petsa-oras at dapat itakda/i-update ng application sa kasalukuyang oras sa bawat oras na idinaragdag/binabago ang mga talaan (atomically kasama ang pagdaragdag/pagbabago). Bilang halimbawa, tawagan natin ang column update_time. Sa pamamagitan ng pag-save ng maximum na halaga ng field ng column na ito para sa mga nailipat na tala, maaari nating simulan ang susunod na exchange session gamit ang halagang ito (piliin ang mga talaan na may halaga ng field update_time, na lumalampas sa dating nakaimbak na halaga). Ang problema sa huling diskarte ay ang mga pagbabago sa data ay maaaring mangyari sa mga batch. Bilang resulta ng mga halaga ng field sa column update_time maaaring hindi natatangi. Kaya, hindi magagamit ang column na ito para sa output ng data na nakabahagi (page-by-page). Upang ipakita ang pahina ng data sa bawat pahina, kakailanganin mong mag-imbento ng mga karagdagang mekanismo na malamang na may napakababang kahusayan (halimbawa, pagkuha mula sa database ng lahat ng mga talaan na may halaga update_time mas mataas kaysa sa isang naibigay na isa at gumagawa ng isang tiyak na bilang ng mga tala, simula sa isang tiyak na offset mula sa simula ng sample).

Maaari mong pagbutihin ang kahusayan ng paglilipat ng data sa pamamagitan ng bahagyang pagpapabuti sa nakaraang diskarte. Upang gawin ito, gagamitin namin ang uri ng integer (mahabang integer) bilang mga halaga ng field ng column para sa pagsubaybay sa mga pagbabago. Pangalanan natin ang column row_ver. Ang halaga ng patlang ng column na ito ay dapat pa ring itakda/i-update sa bawat oras na ang isang tala ay ginawa/binago. Ngunit sa kasong ito, hindi itatalaga sa field ang kasalukuyang petsa-oras, ngunit ang halaga ng ilang counter, ay nadagdagan ng isa. Bilang resulta, ang hanay row_ver ay maglalaman ng mga natatanging halaga at maaaring gamitin hindi lamang upang ipakita ang data ng "delta" (data na idinagdag/binago mula noong katapusan ng nakaraang sesyon ng palitan), kundi pati na rin para simple at epektibong hatiin ito sa mga pahina.

Ang huling iminungkahing paraan ng pagliit ng dami ng data na inilipat sa loob ng balangkas ng mataas na antas ng pagtitiklop ay tila sa akin ang pinakamainam at unibersal. Tingnan natin ito nang mas detalyado.

Pagpasa ng Data Gamit ang Row Version Counter

Pagpapatupad ng server/master part

Sa MS SQL Server, mayroong isang espesyal na uri ng hanay upang ipatupad ang pamamaraang ito - rowversion. Ang bawat database ay may isang counter na tumataas ng isa sa bawat oras na ang isang tala ay idinagdag/binago sa isang talahanayan na may katulad na column rowversion. Ang halaga ng counter na ito ay awtomatikong itinalaga sa field ng column na ito sa idinagdag/binagong tala. Ang Tarantool DBMS ay walang katulad na built-in na mekanismo. Gayunpaman, sa Tarantool hindi mahirap ipatupad ito nang manu-mano. Tingnan natin kung paano ito ginagawa.

Una, isang maliit na terminolohiya: ang mga talahanayan sa Tarantool ay tinatawag na mga puwang, at ang mga tala ay tinatawag na tuples. Sa Tarantool maaari kang lumikha ng mga pagkakasunud-sunod. Ang mga pagkakasunud-sunod ay hindi hihigit sa pinangalanang mga generator ng mga nakaayos na halaga ng integer. Yung. ito mismo ang kailangan natin para sa ating mga layunin. Sa ibaba ay lilikha tayo ng gayong pagkakasunud-sunod.

Bago magsagawa ng anumang operasyon ng database sa Tarantool, kailangan mong patakbuhin ang sumusunod na command:

box.cfg{}

Bilang resulta, magsisimula ang Tarantool sa pagsulat ng mga snapshot ng database at mga log ng transaksyon sa kasalukuyang direktoryo.

Gumawa tayo ng sequence row_version:

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

Pagpipilian if_not_exists nagbibigay-daan sa paglikha ng script na maisakatuparan nang maraming beses: kung umiiral ang bagay, hindi na susubukan ng Tarantool na likhain itong muli. Gagamitin ang opsyong ito sa lahat ng kasunod na DDL command.

Gumawa tayo ng puwang bilang halimbawa.

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

Dito namin itinakda ang pangalan ng espasyo (goods), mga pangalan ng field at kanilang mga uri.

Ang mga patlang ng auto-incrementing sa Tarantool ay nilikha din gamit ang mga sequence. Gumawa tayo ng auto-incrementing primary key ayon sa field 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
})

Sinusuportahan ng Tarantool ang ilang uri ng mga index. Ang pinakakaraniwang ginagamit na mga index ay ang mga uri ng TREE at HASH, na nakabatay sa mga istrukturang naaayon sa pangalan. Ang TREE ay ang pinaka-versatile na uri ng index. Binibigyang-daan ka nitong kunin ang data sa isang organisadong paraan. Ngunit para sa pagpili ng pagkakapantay-pantay, mas angkop ang HASH. Alinsunod dito, ipinapayong gamitin ang HASH para sa pangunahing susi (na kung ano ang ginawa namin).

Para gamitin ang column row_ver upang mailipat ang nabagong data, kailangan mong itali ang mga halaga ng pagkakasunud-sunod sa mga patlang ng hanay na ito row_ver. Ngunit hindi tulad ng pangunahing susi, ang halaga ng field ng column row_ver dapat tumaas ng isa hindi lamang kapag nagdadagdag ng mga bagong tala, kundi pati na rin kapag binabago ang mga umiiral na. Maaari kang gumamit ng mga trigger para dito. Ang Tarantool ay may dalawang uri ng space trigger: before_replace ΠΈ on_replace. Ang mga trigger ay pinapagana sa tuwing nagbabago ang data sa espasyo (para sa bawat tuple na apektado ng mga pagbabago, isang trigger function ang inilulunsad). Unlike on_replace, before_replaceBinibigyang-daan ka ng mga trigger na baguhin ang data ng tuple kung saan isinasagawa ang trigger. Alinsunod dito, ang huling uri ng mga trigger ay nababagay sa amin.

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

Pinapalitan ng sumusunod na trigger ang field value row_ver naka-imbak na tuple sa susunod na halaga ng sequence row_version.

Upang makapag-extract ng data mula sa espasyo goods ayon sa hanay row_ver, gumawa tayo ng index:

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

Uri ng index - puno (TREE), dahil kakailanganin nating kunin ang data sa pataas na pagkakasunud-sunod ng mga halaga sa hanay row_ver.

Magdagdag tayo ng ilang data sa espasyo:

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}

kasi Ang unang field ay isang auto-incrementing counter; pumasa kami sa nil sa halip. Awtomatikong papalitan ng Tarantool ang susunod na halaga. Katulad nito, bilang ang halaga ng mga field ng column row_ver maaari mong ipasa ang nil - o hindi tukuyin ang halaga sa lahat, dahil ang hanay na ito ay sumasakop sa huling posisyon sa espasyo.

Suriin natin ang resulta ng pagpapasok:

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

Tulad ng nakikita mo, ang una at huling mga patlang ay awtomatikong napunan. Ngayon ay magiging madali nang magsulat ng isang function para sa page-by-page na pag-upload ng mga pagbabago sa espasyo 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

Kinukuha ng function bilang parameter ang halaga row_ver, simula kung saan kinakailangan na mag-unload ng mga pagbabago, at ibalik ang isang bahagi ng binagong data.

Ang data sampling sa Tarantool ay ginagawa sa pamamagitan ng mga index. Function get_goods gumagamit ng iterator ayon sa index row_ver para makatanggap ng binagong data. Ang uri ng iterator ay GT (Greater than, greater than). Nangangahulugan ito na ang iterator ay sunud-sunod na tatawid sa mga halaga ng index simula sa naipasa na key (field value row_ver).

Ang iterator ay nagbabalik ng mga tuple. Upang pagkatapos ay makapaglipat ng data sa pamamagitan ng HTTP, kinakailangan na i-convert ang mga tuple sa isang istraktura na maginhawa para sa kasunod na serialization. Ang halimbawa ay gumagamit ng karaniwang function para dito tomap. Sa halip na gamitin tomap maaari kang sumulat ng iyong sariling function. Halimbawa, maaari naming palitan ang pangalan ng isang field name, huwag dumaan sa field code at magdagdag ng field 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

Ang laki ng pahina ng data ng output (ang bilang ng mga tala sa isang bahagi) ay tinutukoy ng variable page_size. Sa halimbawa ang halaga page_size ay 5. Sa isang tunay na programa, ang laki ng pahina ay karaniwang mas mahalaga. Depende ito sa average na laki ng space tuple. Ang pinakamainam na laki ng pahina ay maaaring matukoy nang empirically sa pamamagitan ng pagsukat ng oras ng paglilipat ng data. Kung mas malaki ang laki ng pahina, mas maliit ang bilang ng mga roundtrip sa pagitan ng pagpapadala at pagtanggap ng mga panig. Sa ganitong paraan maaari mong bawasan ang kabuuang oras para sa pag-download ng mga pagbabago. Gayunpaman, kung masyadong malaki ang laki ng page, magtatagal kami sa server sa pagse-serialize ng sample. Bilang resulta, maaaring may mga pagkaantala sa pagproseso ng iba pang mga kahilingan na dumarating sa server. Parameter page_size maaaring i-load mula sa configuration file. Para sa bawat ipinadalang espasyo, maaari mong itakda ang sarili nitong halaga. Gayunpaman, para sa karamihan ng mga puwang ang default na halaga (halimbawa, 100) ay maaaring angkop.

Gawin natin ang function 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
...

Kunin natin ang field value row_ver mula sa huling linya at tawagan muli ang function:

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

Muli:

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

Gaya ng nakikita mo, kapag ginamit sa ganitong paraan, ibinabalik ng function ang lahat ng mga talaan ng espasyo sa bawat pahina goods. Ang huling pahina ay sinusundan ng isang walang laman na seleksyon.

Gumawa tayo ng mga pagbabago sa espasyo:

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

Binago namin ang halaga ng field name para sa isang entry at nagdagdag ng dalawang bagong entry.

Ulitin natin ang huling function call:

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

Ibinalik ng function ang binago at idinagdag na mga tala. Kaya ang function get_goods nagbibigay-daan sa iyong makatanggap ng data na nagbago mula noong huling tawag nito, na siyang batayan ng pamamaraan ng pagtitiklop na isinasaalang-alang.

Iiwan namin ang pagpapalabas ng mga resulta sa pamamagitan ng HTTP sa anyo ng JSON sa labas ng saklaw ng artikulong ito. Maaari mong basahin ang tungkol dito: https://habr.com/ru/company/mailru/blog/272141/

Pagpapatupad ng bahagi ng kliyente/alipin

Tingnan natin kung ano ang hitsura ng pagpapatupad ng receiving side. Gumawa tayo ng puwang sa receiving side para iimbak ang na-download na data:

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

Ang istraktura ng espasyo ay kahawig ng istraktura ng espasyo sa pinagmulan. Ngunit dahil hindi namin ipapasa ang natanggap na data kahit saan pa, ang column row_ver ay wala sa espasyo ng tatanggap. Sa field id itatala ang mga source identifier. Samakatuwid, sa gilid ng receiver ay hindi na kailangang gawin itong awtomatikong pagdaragdag.

Bilang karagdagan, kailangan namin ng isang puwang upang i-save ang mga halaga 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
})

Para sa bawat na-load na espasyo (field space_name) ise-save namin ang huling na-load na halaga dito row_ver (patlang value). Ang column ay gumaganap bilang pangunahing susi space_name.

Gumawa tayo ng function para mag-load ng data ng espasyo goods sa pamamagitan ng HTTP. Para magawa ito, kailangan namin ng library na nagpapatupad ng HTTP client. Ang sumusunod na linya ay naglo-load sa library at nag-i-instantiate ng HTTP client:

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

Kailangan din namin ng library para sa json deserialization:

local json = require('json')

Ito ay sapat na upang lumikha ng isang data loading function:

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

Ang function ay nagsasagawa ng HTTP na kahilingan sa url address at ipinapadala ito row_ver bilang parameter at ibinabalik ang deserialized na resulta ng kahilingan.

Ang function para sa pag-save ng natanggap na data ay ganito ang hitsura:

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

Cycle ng pag-save ng data sa espasyo goods inilagay sa isang transaksyon (ginagamit ang function para dito box.atomic) upang bawasan ang bilang ng mga pagpapatakbo ng disk.

Panghuli, ang lokal na function ng pag-synchronize ng espasyo goods sa isang mapagkukunan maaari mong ipatupad ito tulad nito:

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

Una naming basahin ang dating na-save na halaga row_ver para sa espasyo goods. Kung ito ay nawawala (ang unang exchange session), pagkatapos ay kunin namin ito bilang row_ver sero. Susunod sa cycle, nagsasagawa kami ng page-by-page na pag-download ng binagong data mula sa pinagmulan sa tinukoy na url. Sa bawat pag-ulit, sine-save namin ang natanggap na data sa naaangkop na lokal na espasyo at ina-update ang halaga row_ver (sa kalawakan row_ver at sa variable row_ver) - kunin ang halaga row_ver mula sa huling linya ng na-load na data.

Upang maprotektahan laban sa hindi sinasadyang pag-loop (sa kaso ng isang error sa programa), ang loop while maaaring palitan ng for:

for _ = 1, max_req do ...

Bilang resulta ng pagpapatupad ng function sync_goods space goods ang receiver ay maglalaman ng pinakabagong mga bersyon ng lahat ng mga talaan sa espasyo goods sa pinanggalingan.

Malinaw, ang pagtanggal ng data ay hindi maaaring i-broadcast sa ganitong paraan. Kung mayroong ganoong pangangailangan, maaari kang gumamit ng marka ng pagtanggal. Idagdag sa espasyo goods boolean na patlang is_deleted at sa halip na pisikal na magtanggal ng tala, gumagamit kami ng lohikal na pagtanggal - itinakda namin ang halaga ng field is_deleted sa kahulugan true. Minsan sa halip na isang boolean field is_deleted mas maginhawang gamitin ang field deleted, na nag-iimbak ng petsa-oras ng lohikal na pagtanggal ng tala. Pagkatapos magsagawa ng lohikal na pagtanggal, ang rekord na minarkahan para sa pagtanggal ay ililipat mula sa pinagmulan patungo sa patutunguhan (ayon sa lohika na tinalakay sa itaas).

Sequence row_ver ay maaaring gamitin upang magpadala ng data mula sa iba pang mga espasyo: hindi na kailangang lumikha ng isang hiwalay na pagkakasunud-sunod para sa bawat ipinadalang espasyo.

Tumingin kami sa isang epektibong paraan ng mataas na antas ng pagtitiklop ng data sa mga application gamit ang Tarantool DBMS.

Natuklasan

  1. Ang Tarantool DBMS ay isang kaakit-akit, promising na produkto para sa paglikha ng mga high-load na application.
  2. Ang mataas na antas ng pagtitiklop ng data ay may ilang mga pakinabang sa mababang antas ng pagtitiklop.
  3. Ang mataas na antas na paraan ng pagtitiklop na tinalakay sa artikulo ay nagbibigay-daan sa iyo na i-minimize ang dami ng inilipat na data sa pamamagitan ng paglilipat lamang ng mga talaan na nagbago mula noong huling exchange session.

Pinagmulan: www.habr.com

Magdagdag ng komento