Replikasi peringkat tinggi dalam Tarantool DBMS

Helo, saya sedang mencipta aplikasi untuk DBMS Tarantool ialah platform yang dibangunkan oleh Mail.ru Group yang menggabungkan DBMS berprestasi tinggi dan pelayan aplikasi dalam bahasa Lua. Kelajuan tinggi penyelesaian berdasarkan Tarantool dicapai, khususnya, kerana sokongan untuk mod dalam memori DBMS dan keupayaan untuk melaksanakan logik perniagaan aplikasi dalam satu ruang alamat dengan data. Pada masa yang sama, ketekunan data dipastikan menggunakan transaksi ACID (log WAL dikekalkan pada cakera). Tarantool mempunyai sokongan terbina dalam untuk replikasi dan sharding. Bermula dari versi 2.1, pertanyaan dalam bahasa SQL disokong. Tarantool adalah sumber terbuka dan dilesenkan di bawah lesen BSD Mudah. Terdapat juga versi Perusahaan komersial.

Replikasi peringkat tinggi dalam Tarantool DBMS
Rasakan kuasanya! (…aka menikmati persembahan)

Semua perkara di atas menjadikan Tarantool sebagai platform yang menarik untuk mencipta aplikasi beban tinggi yang berfungsi dengan pangkalan data. Dalam aplikasi sedemikian, selalunya terdapat keperluan untuk replikasi data.

Seperti yang dinyatakan di atas, Tarantool mempunyai replikasi data terbina dalam. Prinsip operasinya adalah untuk melaksanakan secara berurutan pada replika semua transaksi yang terkandung dalam log induk (WAL). Biasanya replikasi sedemikian (kami akan memanggilnya lagi Level rendah) digunakan untuk memastikan toleransi kesalahan aplikasi dan/atau untuk mengagihkan beban bacaan antara nod kelompok.

Replikasi peringkat tinggi dalam Tarantool DBMS
nasi. 1. Replikasi dalam kelompok

Contoh senario alternatif ialah memindahkan data yang dibuat dalam satu pangkalan data ke pangkalan data lain untuk pemprosesan/pemantauan. Dalam kes kedua, penyelesaian yang lebih mudah mungkin digunakan tahap tinggi replikasi - replikasi data pada peringkat logik perniagaan aplikasi. Itu. Kami tidak menggunakan penyelesaian sedia terbina dalam DBMS, tetapi melaksanakan replikasi sendiri dalam aplikasi yang sedang kami bangunkan. Pendekatan ini mempunyai kelebihan dan kekurangan. Jom senaraikan kelebihannya.

1. Penjimatan trafik:

  • Anda tidak boleh memindahkan semua data, tetapi hanya sebahagian daripadanya (contohnya, anda boleh memindahkan hanya beberapa jadual, beberapa lajur atau rekodnya yang memenuhi kriteria tertentu);
  • Tidak seperti replikasi peringkat rendah, yang dilakukan secara berterusan dalam mod tak segerak (dilaksanakan dalam versi semasa Tarantool - 1.10) atau segerak (untuk dilaksanakan dalam mod Tarantool versi berikutnya), replikasi peringkat tinggi boleh dilakukan dalam sesi (iaitu, aplikasi mula-mula menyegerakkan data - data sesi pertukaran, kemudian terdapat jeda dalam replikasi, selepas itu sesi pertukaran seterusnya berlaku, dsb.);
  • jika rekod telah berubah beberapa kali, anda hanya boleh memindahkan versi terkininya (tidak seperti replikasi peringkat rendah, di mana semua perubahan yang dibuat pada induk akan dimainkan semula secara berurutan pada replika).

2. Tiada masalah dengan melaksanakan pertukaran HTTP, yang membolehkan anda menyegerakkan pangkalan data jauh.

Replikasi peringkat tinggi dalam Tarantool DBMS
nasi. 2. Replikasi melalui HTTP

3. Struktur pangkalan data di antara data yang dipindahkan tidak semestinya sama (lebih-lebih lagi, dalam kes umum, bahkan mungkin untuk menggunakan DBMS, bahasa pengaturcaraan, platform, dll. yang berbeza).

Replikasi peringkat tinggi dalam Tarantool DBMS
nasi. 3. Replikasi dalam sistem heterogen

Kelemahannya ialah, secara purata, pengaturcaraan lebih sukar/mahal daripada konfigurasi, dan bukannya menyesuaikan fungsi terbina dalam, anda perlu melaksanakan sendiri.

Jika dalam situasi anda kelebihan di atas adalah penting (atau merupakan syarat yang diperlukan), maka masuk akal untuk menggunakan replikasi peringkat tinggi. Mari lihat beberapa cara untuk melaksanakan replikasi data peringkat tinggi dalam DBMS Tarantool.

Pengurangan lalu lintas

Jadi, salah satu kelebihan replikasi peringkat tinggi ialah penjimatan trafik. Agar kelebihan ini dapat direalisasikan sepenuhnya, adalah perlu untuk meminimumkan jumlah data yang dipindahkan semasa setiap sesi pertukaran. Sudah tentu, kita tidak boleh lupa bahawa pada akhir sesi, penerima data mesti disegerakkan dengan sumber (sekurang-kurangnya untuk bahagian data yang terlibat dalam replikasi).

Bagaimana untuk meminimumkan jumlah data yang dipindahkan semasa replikasi peringkat tinggi? Penyelesaian yang mudah ialah memilih data mengikut tarikh dan masa. Untuk melakukan ini, anda boleh menggunakan medan tarikh-masa yang sedia ada dalam jadual (jika wujud). Sebagai contoh, dokumen "pesanan" mungkin mempunyai medan "masa pelaksanaan pesanan yang diperlukan" - delivery_time. Masalah dengan penyelesaian ini ialah nilai dalam medan ini tidak perlu berada dalam urutan yang sepadan dengan penciptaan pesanan. Jadi kita tidak boleh ingat nilai medan maksimum delivery_time, dihantar semasa sesi pertukaran sebelumnya, dan semasa sesi pertukaran seterusnya pilih semua rekod dengan nilai medan yang lebih tinggi delivery_time. Rekod dengan nilai medan yang lebih rendah mungkin telah ditambah antara sesi pertukaran delivery_time. Juga, pesanan itu mungkin telah mengalami perubahan, yang bagaimanapun tidak menjejaskan medan delivery_time. Dalam kedua-dua kes, perubahan tidak akan dipindahkan dari sumber ke destinasi. Untuk menyelesaikan masalah ini, kami perlu memindahkan data "bertindih". Itu. dalam setiap sesi pertukaran kami akan memindahkan semua data dengan nilai medan delivery_time, melebihi beberapa titik pada masa lalu (contohnya, N jam dari saat semasa). Walau bagaimanapun, adalah jelas bahawa untuk sistem yang besar pendekatan ini sangat berlebihan dan boleh mengurangkan penjimatan trafik yang kami usahakan kepada sia-sia. Selain itu, jadual yang dipindahkan mungkin tidak mempunyai medan yang dikaitkan dengan tarikh-masa.

Penyelesaian lain, lebih kompleks dari segi pelaksanaan, adalah dengan mengakui penerimaan data. Dalam kes ini, semasa setiap sesi pertukaran, semua data dihantar, yang resitnya belum disahkan oleh penerima. Untuk melaksanakan ini, anda perlu menambah lajur Boolean pada jadual sumber (contohnya, is_transferred). Jika penerima mengakui penerimaan rekod, medan yang sepadan mengambil nilainya true, selepas itu penyertaan tidak lagi terlibat dalam pertukaran. Pilihan pelaksanaan ini mempunyai kelemahan berikut. Pertama, bagi setiap rekod yang dipindahkan, pengakuan mesti dijana dan dihantar. Secara kasarnya, ini boleh dibandingkan dengan menggandakan jumlah data yang dipindahkan dan membawa kepada menggandakan bilangan perjalanan pergi balik. Kedua, tidak ada kemungkinan untuk menghantar rekod yang sama kepada beberapa penerima (penerima pertama yang menerima akan mengesahkan penerimaan untuk dirinya sendiri dan untuk semua yang lain).

Kaedah yang tidak mempunyai kelemahan yang diberikan di atas ialah menambah lajur pada jadual yang dipindahkan untuk menjejaki perubahan dalam barisnya. Lajur sedemikian boleh daripada jenis tarikh-masa dan mesti ditetapkan/kemas kini oleh aplikasi kepada masa semasa setiap rekod masa ditambah/diubah (secara atom dengan penambahan/perubahan). Sebagai contoh, mari kita panggil lajur update_time. Dengan menyimpan nilai medan maksimum lajur ini untuk rekod yang dipindahkan, kita boleh memulakan sesi pertukaran seterusnya dengan nilai ini (pilih rekod dengan nilai medan update_time, melebihi nilai yang disimpan sebelum ini). Masalah dengan pendekatan yang terakhir ialah perubahan data boleh berlaku dalam kelompok. Hasil daripada nilai medan dalam lajur update_time mungkin tidak unik. Oleh itu, lajur ini tidak boleh digunakan untuk output data bahagian (halaman demi halaman). Untuk memaparkan halaman data mengikut halaman, anda perlu mencipta mekanisme tambahan yang berkemungkinan besar mempunyai kecekapan yang sangat rendah (contohnya, mendapatkan semula daripada pangkalan data semua rekod dengan nilai update_time lebih tinggi daripada yang diberikan dan menghasilkan bilangan rekod tertentu, bermula dari offset tertentu dari permulaan sampel).

Anda boleh meningkatkan kecekapan pemindahan data dengan menambah baik sedikit pendekatan sebelumnya. Untuk melakukan ini, kami akan menggunakan jenis integer (integer panjang) sebagai nilai medan lajur untuk menjejaki perubahan. Mari namakan lajur row_ver. Nilai medan lajur ini mesti tetap ditetapkan/kemas kini setiap kali rekod dibuat/diubah suai. Tetapi dalam kes ini, medan tidak akan diberikan tarikh-masa semasa, tetapi nilai beberapa kaunter, meningkat sebanyak satu. Akibatnya, lajur row_ver akan mengandungi nilai unik dan boleh digunakan bukan sahaja untuk memaparkan data "delta" (data ditambah/diubah sejak akhir sesi pertukaran sebelumnya), tetapi juga untuk memecahkannya secara ringkas dan berkesan kepada halaman.

Kaedah terakhir yang dicadangkan untuk meminimumkan jumlah data yang dipindahkan dalam rangka kerja replikasi peringkat tinggi nampaknya paling optimum dan universal. Mari kita lihat dengan lebih terperinci.

Menghantar Data Menggunakan Pembilang Versi Baris

Pelaksanaan bahagian pelayan/ induk

Dalam MS SQL Server, terdapat jenis lajur khas untuk melaksanakan pendekatan ini - rowversion. Setiap pangkalan data mempunyai pembilang yang meningkat sebanyak satu setiap kali rekod ditambah/diubah dalam jadual yang mempunyai lajur seperti rowversion. Nilai kaunter ini secara automatik diberikan kepada medan lajur ini dalam rekod yang ditambah/diubah. DBMS Tarantool tidak mempunyai mekanisme terbina dalam yang serupa. Walau bagaimanapun, dalam Tarantool tidak sukar untuk melaksanakannya secara manual. Mari lihat bagaimana ini dilakukan.

Pertama, sedikit istilah: jadual dalam Tarantool dipanggil ruang, dan rekod dipanggil tupel. Dalam Tarantool anda boleh membuat urutan. Jujukan tidak lebih daripada penjana dinamakan nilai integer tertib. Itu. inilah yang kita perlukan untuk tujuan kita. Di bawah ini kita akan membuat urutan sedemikian.

Sebelum melakukan sebarang operasi pangkalan data dalam Tarantool, anda perlu menjalankan arahan berikut:

box.cfg{}

Akibatnya, Tarantool akan mula menulis petikan pangkalan data dan log transaksi ke direktori semasa.

Mari buat urutan row_version:

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

Pilihan if_not_exists membenarkan skrip penciptaan dilaksanakan beberapa kali: jika objek wujud, Tarantool tidak akan cuba menciptanya lagi. Pilihan ini akan digunakan dalam semua arahan DDL berikutnya.

Mari buat ruang sebagai contoh.

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

Di sini kita tetapkan nama ruang (goods), nama medan dan jenisnya.

Medan penambahan automatik dalam Tarantool juga dibuat menggunakan jujukan. Mari kita buat kunci utama auto-increment mengikut medan 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 menyokong beberapa jenis indeks. Indeks yang paling biasa digunakan ialah jenis TREE dan HASH, yang berdasarkan struktur yang sepadan dengan nama. TREE ialah jenis indeks yang paling serba boleh. Ia membolehkan anda mendapatkan semula data secara teratur. Tetapi untuk pemilihan kesamarataan, HASH lebih sesuai. Oleh itu, adalah dinasihatkan untuk menggunakan HASH untuk kunci utama (iaitu yang kami lakukan).

Untuk menggunakan lajur row_ver untuk memindahkan data yang diubah, anda perlu mengikat nilai jujukan ke medan lajur ini row_ver. Tetapi tidak seperti kunci utama, nilai medan lajur row_ver harus meningkat satu bukan sahaja apabila menambah rekod baharu, tetapi juga apabila menukar rekod sedia ada. Anda boleh menggunakan pencetus untuk ini. Tarantool mempunyai dua jenis pencetus ruang: before_replace ΠΈ on_replace. Pencetus dicetuskan apabila data dalam ruang berubah (untuk setiap tuple yang terjejas oleh perubahan, fungsi pencetus dilancarkan). Tidak seperti on_replace, before_replace-triggers membolehkan anda mengubah suai data tuple yang mana pencetusnya dilaksanakan. Sehubungan itu, jenis pencetus terakhir sesuai dengan kita.

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

Pencetus berikut menggantikan nilai medan row_ver tuple disimpan ke nilai urutan seterusnya row_version.

Untuk dapat mengekstrak data dari angkasa goods mengikut lajur row_ver, mari buat indeks:

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

Jenis indeks - pokok (TREE), kerana kita perlu mengekstrak data dalam susunan menaik nilai dalam lajur row_ver.

Mari tambahkan beberapa data pada ruang:

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}

Kerana Medan pertama ialah kaunter kenaikan automatik; sebaliknya kami melepasi sifar. Tarantool akan menggantikan nilai seterusnya secara automatik. Begitu juga, sebagai nilai medan lajur row_ver anda boleh lulus nil - atau tidak menentukan nilai sama sekali, kerana lajur ini menduduki kedudukan terakhir dalam ruang.

Mari kita semak hasil sisipan:

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

Seperti yang anda lihat, medan pertama dan terakhir diisi secara automatik. Kini ia akan menjadi mudah untuk menulis fungsi untuk memuat naik halaman demi halaman perubahan ruang 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

Fungsi mengambil sebagai parameter nilai row_ver, bermula dari mana ia perlu untuk memunggah perubahan, dan mengembalikan sebahagian daripada data yang diubah.

Persampelan data dalam Tarantool dilakukan melalui indeks. Fungsi get_goods menggunakan iterator mengikut indeks row_ver untuk menerima data yang diubah. Jenis iterator ialah GT (Lebih Besar Daripada, lebih besar daripada). Ini bermakna bahawa iterator akan melintasi nilai indeks secara berurutan bermula dari kunci yang diluluskan (nilai medan row_ver).

Iterator mengembalikan tupel. Untuk seterusnya dapat memindahkan data melalui HTTP, adalah perlu untuk menukar tupel kepada struktur yang mudah untuk penyirian berikutnya. Contoh menggunakan fungsi standard untuk ini tomap. Daripada menggunakan tomap anda boleh menulis fungsi anda sendiri. Sebagai contoh, kita mungkin mahu menamakan semula medan name, jangan melepasi padang code dan tambah medan 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

Saiz halaman data output (bilangan rekod dalam satu bahagian) ditentukan oleh pembolehubah page_size. Dalam contoh nilai page_size ialah 5. Dalam program sebenar, saiz halaman biasanya lebih penting. Ia bergantung pada saiz purata tuple ruang. Saiz halaman yang optimum boleh ditentukan secara empirik dengan mengukur masa pemindahan data. Semakin besar saiz halaman, semakin kecil bilangan perjalanan pergi balik antara pihak penghantar dan penerima. Dengan cara ini anda boleh mengurangkan masa keseluruhan untuk memuat turun perubahan. Walau bagaimanapun, jika saiz halaman terlalu besar, kami akan menghabiskan terlalu lama pada pelayan untuk mensiri sampel. Akibatnya, mungkin terdapat kelewatan dalam memproses permintaan lain yang datang ke pelayan. Parameter page_size boleh dimuatkan daripada fail konfigurasi. Untuk setiap ruang yang dihantar, anda boleh menetapkan nilainya sendiri. Walau bagaimanapun, untuk kebanyakan ruang nilai lalai (contohnya, 100) mungkin sesuai.

Mari kita laksanakan fungsi 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
...

Mari kita ambil nilai medan row_ver dari baris terakhir dan panggil fungsi itu semula:

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

Sekali lagi:

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

Seperti yang anda lihat, apabila digunakan dengan cara ini, fungsi mengembalikan semua rekod ruang halaman demi halaman goods. Halaman terakhir diikuti dengan pilihan kosong.

Mari buat perubahan pada ruang:

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

Kami telah menukar nilai medan name untuk satu entri dan menambah dua entri baharu.

Mari ulangi panggilan fungsi terakhir:

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

Fungsi mengembalikan rekod yang diubah dan ditambah. Jadi fungsinya get_goods membolehkan anda menerima data yang telah berubah sejak panggilan terakhirnya, yang merupakan asas kaedah replikasi yang sedang dipertimbangkan.

Kami akan meninggalkan pengeluaran hasil melalui HTTP dalam bentuk JSON di luar skop artikel ini. Anda boleh membaca tentang ini di sini: https://habr.com/ru/company/mailru/blog/272141/

Pelaksanaan bahagian klien/hamba

Mari kita lihat bagaimana pelaksanaan pihak penerima. Mari buat ruang di bahagian penerima untuk menyimpan data yang dimuat turun:

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

Struktur ruang menyerupai struktur ruang dalam sumber. Tetapi kerana kami tidak akan menghantar data yang diterima ke tempat lain, lajur row_ver tiada dalam ruang penerima. Di padang id pengecam sumber akan direkodkan. Oleh itu, pada bahagian penerima tidak perlu membuatnya meningkat secara automatik.

Di samping itu, kita memerlukan ruang untuk menyimpan nilai 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
})

Untuk setiap ruang yang dimuatkan (medan space_name) kami akan menyimpan nilai yang terakhir dimuatkan di sini row_ver (padang value). Lajur bertindak sebagai kunci utama space_name.

Mari buat fungsi untuk memuatkan data ruang goods melalui HTTP. Untuk melakukan ini, kami memerlukan perpustakaan yang melaksanakan klien HTTP. Baris berikut memuatkan perpustakaan dan membuat instantiate klien HTTP:

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

Kami juga memerlukan perpustakaan untuk penyahserialisasian json:

local json = require('json')

Ini cukup untuk mencipta fungsi pemuatan data:

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

Fungsi melaksanakan permintaan HTTP ke alamat url dan menghantarnya row_ver sebagai parameter dan mengembalikan hasil deserialisasi permintaan.

Fungsi untuk menyimpan data yang diterima kelihatan seperti ini:

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

Kitaran menyimpan data ke angkasa goods diletakkan dalam transaksi (fungsi ini digunakan untuk ini box.atomic) untuk mengurangkan bilangan operasi cakera.

Akhir sekali, fungsi penyegerakan ruang tempatan goods dengan sumber anda boleh melaksanakannya seperti ini:

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

Mula-mula kita membaca nilai yang disimpan sebelum ini row_ver untuk ruang goods. Jika ia hilang (sesi pertukaran pertama), maka kami ambil sebagai row_ver sifar. Seterusnya dalam kitaran kami melakukan muat turun halaman demi halaman bagi data yang diubah daripada sumber pada url yang ditentukan. Pada setiap lelaran, kami menyimpan data yang diterima ke ruang setempat yang sesuai dan mengemas kini nilainya row_ver (dalam angkasa row_ver dan dalam pembolehubah row_ver) - ambil nilai row_ver daripada baris terakhir data yang dimuatkan.

Untuk melindungi daripada gelung tidak sengaja (sekiranya berlaku ralat dalam program), gelung while boleh digantikan dengan for:

for _ = 1, max_req do ...

Hasil daripada melaksanakan fungsi sync_goods angkasa lepas goods penerima akan mengandungi versi terkini semua rekod ruang goods dalam sumber.

Jelas sekali, pemadaman data tidak boleh disiarkan dengan cara ini. Jika keperluan sedemikian wujud, anda boleh menggunakan tanda pemadaman. Tambahkan ke ruang goods medan boolean is_deleted dan bukannya memadam rekod secara fizikal, kami menggunakan pemadaman logik - kami menetapkan nilai medan is_deleted menjadi makna true. Kadangkala bukannya medan boolean is_deleted ia adalah lebih mudah untuk menggunakan padang deleted, yang menyimpan tarikh-masa pemadaman logik rekod. Selepas melakukan pemadaman logik, rekod yang ditandakan untuk pemadaman akan dipindahkan dari sumber ke destinasi (mengikut logik yang dibincangkan di atas).

Urutan row_ver boleh digunakan untuk menghantar data dari ruang lain: tidak perlu mencipta urutan berasingan untuk setiap ruang yang dihantar.

Kami melihat cara yang berkesan untuk replikasi data peringkat tinggi dalam aplikasi menggunakan Tarantool DBMS.

Penemuan

  1. Tarantool DBMS ialah produk yang menarik dan menjanjikan untuk mencipta aplikasi beban tinggi.
  2. Replikasi data peringkat tinggi mempunyai beberapa kelebihan berbanding replikasi peringkat rendah.
  3. Kaedah replikasi peringkat tinggi yang dibincangkan dalam artikel membolehkan anda meminimumkan jumlah data yang dipindahkan dengan memindahkan hanya rekod yang telah berubah sejak sesi pertukaran terakhir.

Sumber: www.habr.com

Tambah komen