Replikasi tingkat tinggi di Tarantool DBMS

Halo, Saya membuat aplikasi untuk DBMS Tarantool adalah platform yang dikembangkan oleh Mail.ru Group yang menggabungkan DBMS berkinerja tinggi dan server aplikasi dalam bahasa Lua. Solusi berkecepatan tinggi berdasarkan Tarantool dicapai, khususnya, karena dukungan untuk mode DBMS dalam memori dan kemampuan untuk menjalankan logika bisnis aplikasi dalam satu ruang alamat dengan data. Pada saat yang sama, persistensi data dipastikan menggunakan transaksi ACID (log WAL disimpan di disk). Tarantool memiliki dukungan bawaan untuk replikasi dan sharding. Mulai dari versi 2.1, kueri dalam bahasa SQL didukung. Tarantool bersifat open source dan berlisensi di bawah lisensi BSD Sederhana. Ada juga versi Perusahaan komersial.

Replikasi tingkat tinggi di Tarantool DBMS
Rasakan kekuatannya! (…alias nikmati pertunjukannya)

Semua hal di atas menjadikan Tarantool platform yang menarik untuk membuat aplikasi beban tinggi yang bekerja dengan database. Dalam aplikasi seperti itu, sering kali diperlukan replikasi data.

Seperti disebutkan di atas, Tarantool memiliki replikasi data bawaan. Prinsip operasinya adalah mengeksekusi secara berurutan pada replika semua transaksi yang terdapat dalam master log (WAL). Biasanya replikasi seperti itu (selanjutnya kita akan menyebutnya level rendah) digunakan untuk memastikan toleransi kesalahan aplikasi dan/atau untuk mendistribusikan beban pembacaan antar node cluster.

Replikasi tingkat tinggi di Tarantool DBMS
Beras. 1. Replikasi dalam sebuah cluster

Contoh skenario alternatif adalah mentransfer data yang dibuat dalam satu database ke database lain untuk diproses/dipantau. Dalam kasus terakhir, solusi yang lebih mudah mungkin adalah dengan menggunakan level tinggi replikasi - replikasi data pada tingkat logika bisnis aplikasi. Itu. Kami tidak menggunakan solusi siap pakai yang dibangun ke dalam DBMS, tetapi menerapkan replikasi kami sendiri dalam aplikasi yang kami kembangkan. Pendekatan ini memiliki kelebihan dan kekurangan. Mari kita daftar keuntungannya.

1. Penghematan lalu lintas:

  • Anda tidak dapat mentransfer semua data, tetapi hanya sebagian saja (misalnya, Anda hanya dapat mentransfer beberapa tabel, beberapa kolom, atau rekamannya yang memenuhi kriteria tertentu);
  • Tidak seperti replikasi tingkat rendah, yang dilakukan terus menerus dalam mode asinkron (diimplementasikan pada versi Tarantool - 1.10 saat ini) atau sinkron (untuk diterapkan pada versi Tarantool berikutnya), replikasi tingkat tinggi dapat dilakukan dalam sesi (yaitu, aplikasi pertama-tama menyinkronkan data - sesi pertukaran data, kemudian ada jeda dalam replikasi, setelah itu terjadi sesi pertukaran berikutnya, dll.);
  • jika rekaman telah diubah beberapa kali, Anda hanya dapat mentransfer versi terbarunya (tidak seperti replikasi tingkat rendah, di mana semua perubahan yang dibuat pada master akan diputar ulang secara berurutan pada replika).

2. Tidak ada kesulitan dalam mengimplementasikan pertukaran HTTP, yang memungkinkan Anda menyinkronkan database jarak jauh.

Replikasi tingkat tinggi di Tarantool DBMS
Beras. 2. Replikasi melalui HTTP

3. Struktur database tempat data ditransfer tidak harus sama (selain itu, secara umum, bahkan dimungkinkan untuk menggunakan DBMS, bahasa pemrograman, platform, dll. yang berbeda).

Replikasi tingkat tinggi di Tarantool DBMS
Beras. 3. Replikasi dalam sistem heterogen

Kelemahannya adalah, rata-rata, pemrograman lebih sulit/mahal dibandingkan konfigurasi, dan alih-alih menyesuaikan fungsionalitas bawaan, Anda harus mengimplementasikan fungsionalitas Anda sendiri.

Jika dalam situasi Anda keuntungan di atas sangat penting (atau merupakan kondisi yang diperlukan), maka masuk akal untuk menggunakan replikasi tingkat tinggi. Mari kita lihat beberapa cara untuk mengimplementasikan replikasi data tingkat tinggi di Tarantool DBMS.

Minimalkan lalu lintas

Jadi, salah satu keuntungan replikasi tingkat tinggi adalah penghematan lalu lintas. Agar keuntungan ini dapat terwujud sepenuhnya, jumlah data yang ditransfer selama setiap sesi pertukaran perlu diminimalkan. Tentu saja, kita tidak boleh lupa bahwa di akhir sesi, penerima data harus disinkronkan dengan sumbernya (setidaknya untuk bagian data yang terlibat dalam replikasi).

Bagaimana cara meminimalkan jumlah data yang ditransfer selama replikasi tingkat tinggi? Solusi langsungnya adalah dengan memilih data berdasarkan tanggal dan waktu. Untuk melakukan ini, Anda bisa menggunakan bidang tanggal-waktu yang sudah ada di tabel (jika ada). Misalnya, dokumen "pesanan" mungkin memiliki bidang "waktu eksekusi pesanan yang diperlukan" - delivery_time. Masalah dengan solusi ini adalah nilai dalam bidang ini tidak harus berada dalam urutan yang sesuai dengan pembuatan pesanan. Jadi kami tidak dapat mengingat nilai bidang maksimum delivery_time, dikirimkan selama sesi pertukaran sebelumnya, dan selama sesi pertukaran berikutnya pilih semua catatan dengan nilai bidang yang lebih tinggi delivery_time. Catatan dengan nilai bidang yang lebih rendah mungkin telah ditambahkan di antara sesi pertukaran delivery_time. Selain itu, tatanannya bisa saja mengalami perubahan, namun tidak mempengaruhi lapangan delivery_time. Dalam kedua kasus tersebut, perubahan tidak akan ditransfer dari sumber ke tujuan. Untuk mengatasi masalah ini, kita perlu mentransfer data yang "tumpang tindih". Itu. di setiap sesi pertukaran kami akan mentransfer semua data dengan nilai field delivery_time, melebihi suatu titik di masa lalu (misalnya, N jam dari momen saat ini). Namun, jelas bahwa untuk sistem besar, pendekatan ini sangat mubazir dan dapat mengurangi penghematan lalu lintas yang kita perjuangkan menjadi sia-sia. Selain itu, tabel yang ditransfer mungkin tidak memiliki bidang yang terkait dengan tanggal-waktu.

Solusi lain, yang implementasinya lebih kompleks, adalah mengakui penerimaan data. Dalam hal ini, selama setiap sesi pertukaran, semua data dikirimkan, yang penerimaannya belum dikonfirmasi oleh penerima. Untuk menerapkan ini, Anda perlu menambahkan kolom Boolean ke tabel sumber (misalnya, is_transferred). Jika penerima mengakui penerimaan catatan, bidang terkait akan mengambil nilainya true, setelah itu entri tersebut tidak lagi terlibat dalam pertukaran. Opsi implementasi ini memiliki kelemahan sebagai berikut. Pertama, untuk setiap rekaman yang ditransfer, pengakuan harus dibuat dan dikirim. Secara kasar, hal ini dapat disamakan dengan menggandakan jumlah data yang ditransfer dan menyebabkan dua kali lipat jumlah perjalanan pulang pergi. Kedua, tidak ada kemungkinan mengirim catatan yang sama ke beberapa penerima (penerima pertama akan mengkonfirmasi penerimaan untuk dirinya sendiri dan untuk semua penerima lainnya).

Metode yang tidak memiliki kelemahan di atas adalah menambahkan kolom ke tabel yang dikirimkan untuk melacak perubahan pada barisnya. Kolom tersebut dapat bertipe tanggal-waktu dan harus disetel/diperbarui oleh aplikasi ke waktu saat ini setiap kali catatan ditambahkan/diubah (secara atomis dengan penambahan/perubahan). Sebagai contoh, sebut saja kolom update_time. Dengan menyimpan nilai bidang maksimum kolom ini untuk catatan yang ditransfer, kita dapat memulai sesi pertukaran berikutnya dengan nilai ini (pilih catatan dengan nilai bidang update_time, melebihi nilai yang disimpan sebelumnya). Masalah dengan pendekatan terakhir adalah perubahan data dapat terjadi secara batch. Akibat nilai field pada kolom tersebut update_time mungkin tidak unik. Oleh karena itu, kolom ini tidak dapat digunakan untuk keluaran data berporsi (halaman demi halaman). Untuk menampilkan data halaman demi halaman, Anda harus menciptakan mekanisme tambahan yang kemungkinan besar memiliki efisiensi yang sangat rendah (misalnya, mengambil dari database semua catatan dengan nilai update_time lebih tinggi dari nilai tertentu dan menghasilkan sejumlah rekaman tertentu, dimulai dari offset tertentu dari awal sampel).

Anda dapat meningkatkan efisiensi transfer data dengan sedikit meningkatkan pendekatan sebelumnya. Untuk melakukan ini, kita akan menggunakan tipe integer (bilangan bulat panjang) sebagai nilai kolom kolom untuk melacak perubahan. Mari beri nama kolomnya row_ver. Nilai field kolom ini harus tetap disetel/diperbarui setiap kali record dibuat/dimodifikasi. Namun dalam kasus ini, kolom tersebut tidak akan diberi tanggal-waktu saat ini, melainkan nilai dari beberapa penghitung, ditambah satu. Akibatnya, kolom row_ver akan berisi nilai unik dan dapat digunakan tidak hanya untuk menampilkan data β€œdelta” (data ditambahkan/diubah sejak akhir sesi pertukaran sebelumnya), tetapi juga untuk memecahnya menjadi beberapa halaman secara sederhana dan efektif.

Metode terakhir yang diusulkan untuk meminimalkan jumlah data yang ditransfer dalam kerangka replikasi tingkat tinggi menurut saya paling optimal dan universal. Mari kita lihat lebih detail.

Melewati Data Menggunakan Penghitung Versi Baris

Implementasi bagian server/master

Di MS SQL Server, ada tipe kolom khusus untuk mengimplementasikan pendekatan ini - rowversion. Setiap database memiliki counter yang bertambah satu setiap kali record ditambahkan/diubah dalam tabel yang memiliki kolom seperti rowversion. Nilai penghitung ini secara otomatis ditetapkan ke bidang kolom ini dalam catatan yang ditambahkan/diubah. DBMS Tarantool tidak memiliki mekanisme bawaan yang serupa. Namun di Tarantool tidak sulit untuk mengimplementasikannya secara manual. Mari kita lihat bagaimana hal ini dilakukan.

Pertama, sedikit terminologi: tabel di Tarantool disebut spasi, dan record disebut tupel. Di Tarantool Anda dapat membuat urutan. Urutan tidak lebih dari generator bernama nilai integer yang diurutkan. Itu. inilah yang kita perlukan untuk tujuan kita. Di bawah ini kita akan membuat urutan seperti itu.

Sebelum melakukan operasi database apa pun di Tarantool, Anda perlu menjalankan perintah berikut:

box.cfg{}

Hasilnya, Tarantool akan mulai menulis snapshot database dan log transaksi ke direktori saat ini.

Mari kita buat urutannya row_version:

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

Pilihan if_not_exists memungkinkan skrip pembuatan dieksekusi beberapa kali: jika objek ada, Tarantool tidak akan mencoba membuatnya lagi. Opsi ini akan digunakan di semua perintah DDL berikutnya.

Mari kita 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 menetapkan nama ruang (goods), nama bidang dan tipenya.

Bidang penambahan otomatis di Tarantool juga dibuat menggunakan urutan. Mari kita buat kunci utama yang bertambah secara otomatis berdasarkan bidang 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 mendukung beberapa jenis indeks. Indeks yang paling umum digunakan adalah tipe TREE dan HASH, yang didasarkan pada struktur yang sesuai dengan namanya. TREE adalah tipe indeks yang paling serbaguna. Ini memungkinkan Anda mengambil data secara terorganisir. Namun untuk pemilihan kesetaraan, HASH lebih cocok. Oleh karena itu, disarankan untuk menggunakan HASH untuk kunci utama (seperti yang kami lakukan).

Untuk menggunakan kolom row_ver untuk mentransfer data yang diubah, Anda perlu mengikat nilai urutan ke bidang kolom ini row_ver. Namun berbeda dengan kunci utama, kolomnya adalah nilai row_ver harus bertambah satu tidak hanya ketika menambahkan catatan baru, tetapi juga ketika mengubah yang sudah ada. Anda dapat menggunakan pemicu untuk ini. Tarantool memiliki dua jenis pemicu ruang: before_replace ΠΈ on_replace. Pemicu diaktifkan setiap kali data dalam ruang berubah (untuk setiap tupel yang terpengaruh oleh perubahan tersebut, fungsi pemicu diluncurkan). Berbeda dengan on_replace, before_replace-triggers memungkinkan Anda mengubah data tupel yang pemicunya dijalankan. Oleh karena itu, jenis pemicu terakhir cocok untuk 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)

Pemicu berikut menggantikan nilai bidang row_ver menyimpan tupel ke nilai urutan berikutnya row_version.

Untuk dapat mengekstrak data dari luar angkasa goods menurut kolom 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 - pohon (TREE), Karena kita perlu mengekstrak data dalam urutan nilai di kolom row_ver.

Mari tambahkan beberapa data ke 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}

Karena Bidang pertama adalah penghitung kenaikan otomatis; sebagai gantinya kita meneruskan nil. Tarantool secara otomatis akan mengganti nilai berikutnya. Begitu pula dengan nilai kolom kolomnya row_ver Anda dapat memberikan nil - atau tidak menentukan nilainya sama sekali, karena kolom ini menempati posisi terakhir dalam ruang.

Mari kita periksa hasil penyisipan:

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, kolom pertama dan terakhir terisi secara otomatis. Sekarang akan mudah untuk menulis fungsi untuk mengunggah perubahan ruang halaman demi halaman 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 ini mengambil nilai sebagai parameter row_ver, mulai dari mana perlu membongkar perubahan, dan mengembalikan sebagian dari data yang diubah.

Pengambilan sampel data di Tarantool dilakukan melalui indeks. Fungsi get_goods menggunakan iterator berdasarkan indeks row_ver untuk menerima data yang diubah. Tipe Iteratornya adalah GT (Lebih Besar Dari, lebih besar dari). Artinya iterator akan menelusuri nilai indeks secara berurutan mulai dari kunci yang diteruskan (nilai bidang row_ver).

Iterator mengembalikan tupel. Agar selanjutnya dapat mentransfer data melalui HTTP, tupel perlu diubah ke struktur yang sesuai untuk serialisasi berikutnya. Contohnya menggunakan fungsi standar untuk ini tomap. Daripada menggunakan tomap Anda dapat menulis fungsi Anda sendiri. Misalnya, kita mungkin ingin mengganti nama suatu bidang name, jangan melewati lapangan code dan menambahkan bidang 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

Ukuran halaman data keluaran (jumlah record dalam satu porsi) ditentukan oleh variabel page_size. Dalam contoh nilainya page_size adalah 5. Dalam program sebenarnya, ukuran halaman biasanya lebih penting. Itu tergantung pada ukuran rata-rata tupel luar angkasa. Ukuran halaman optimal dapat ditentukan secara empiris dengan mengukur waktu transfer data. Semakin besar ukuran halaman, semakin kecil jumlah perjalanan bolak-balik antara sisi pengirim dan penerima. Dengan cara ini Anda dapat mengurangi waktu keseluruhan untuk mengunduh perubahan. Namun, jika ukuran halaman terlalu besar, kami akan menghabiskan waktu terlalu lama di server untuk membuat serial sampel. Akibatnya, mungkin terjadi keterlambatan dalam memproses permintaan lain yang masuk ke server. Parameter page_size dapat dimuat dari file konfigurasi. Untuk setiap ruang yang ditransmisikan, Anda dapat menetapkan nilainya sendiri. Namun, untuk sebagian besar ruang, nilai default (misalnya, 100) mungkin cocok.

Mari kita jalankan fungsinya 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 bidangnya row_ver dari baris terakhir dan panggil fungsinya lagi:

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, ketika digunakan dengan cara ini, fungsi mengembalikan semua catatan ruang halaman demi halaman goods. Halaman terakhir diikuti dengan pilihan kosong.

Mari kita membuat 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 mengubah nilai bidang name untuk satu entri dan menambahkan dua entri baru.

Mari ulangi pemanggilan 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 ini mengembalikan catatan yang diubah dan ditambahkan. Jadi fungsinya get_goods memungkinkan Anda menerima data yang telah berubah sejak panggilan terakhirnya, yang merupakan dasar dari metode replikasi yang sedang dipertimbangkan.

Kami akan membiarkan penerbitan hasil melalui HTTP dalam bentuk JSON di luar cakupan artikel ini. Anda dapat membaca tentang ini di sini: https://habr.com/ru/company/mailru/blog/272141/

Implementasi bagian klien/budak

Mari kita lihat seperti apa penerapannya di pihak penerima. Mari buat ruang di sisi penerima untuk menyimpan data yang diunduh:

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 pada sumbernya. Tapi karena kami tidak akan meneruskan data yang diterima ke tempat lain, kolom row_ver tidak ada di ruang penerima. Di lapangan id pengidentifikasi sumber akan dicatat. Oleh karena itu, di sisi penerima tidak perlu melakukan penambahan otomatis.

Selain itu, kita membutuhkan 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 dimuat (field space_name) kami akan menyimpan nilai terakhir yang dimuat di sini row_ver (bidang value). Kolom bertindak sebagai kunci utama space_name.

Mari buat fungsi untuk memuat data luar angkasa goods melalui HTTP. Untuk melakukan ini, kita memerlukan perpustakaan yang mengimplementasikan klien HTTP. Baris berikut memuat perpustakaan dan membuat instance klien HTTP:

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

Kami juga memerlukan perpustakaan untuk deserialisasi json:

local json = require('json')

Ini cukup untuk membuat 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 ini menjalankan permintaan HTTP ke alamat url dan mengirimkannya row_ver sebagai parameter dan mengembalikan hasil permintaan yang dideserialisasi.

Fungsi untuk menyimpan data yang diterima terlihat 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

Siklus menyimpan data ke luar angkasa goods ditempatkan dalam transaksi (fungsi digunakan untuk ini box.atomic) untuk mengurangi jumlah operasi disk.

Terakhir, fungsi sinkronisasi ruang lokal goods dengan sumber Anda dapat menerapkannya 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

Pertama kita membaca nilai yang disimpan sebelumnya row_ver untuk ruang goods. Kalau hilang (sesi pertukaran pertama), maka kita anggap sebagai row_ver nol. Berikutnya dalam siklus kami melakukan pengunduhan halaman demi halaman dari data yang diubah dari sumber di url yang ditentukan. Pada setiap iterasi, kami menyimpan data yang diterima ke ruang lokal yang sesuai dan memperbarui nilainya row_ver (di ruang hampa row_ver dan dalam variabel row_ver) - ambil nilainya row_ver dari baris terakhir data yang dimuat.

Untuk melindungi terhadap perulangan yang tidak disengaja (jika terjadi kesalahan dalam program), perulangan while bisa diganti dengan for:

for _ = 1, max_req do ...

Sebagai hasil dari menjalankan fungsi tersebut sync_goods ruang angkasa goods penerima akan berisi versi terbaru dari semua catatan luar angkasa goods di sumbernya.

Jelas, penghapusan data tidak dapat disiarkan dengan cara ini. Jika diperlukan, Anda dapat menggunakan tanda penghapusan. Tambahkan ke ruang goods bidang boolean is_deleted dan alih-alih menghapus catatan secara fisik, kami menggunakan penghapusan logis - kami menetapkan nilai bidang is_deleted ke dalam makna true. Terkadang, bukan bidang boolean is_deleted akan lebih nyaman menggunakan lapangan deleted, yang menyimpan tanggal-waktu penghapusan logis dari catatan. Setelah melakukan penghapusan logis, catatan yang ditandai untuk dihapus akan ditransfer dari sumber ke tujuan (sesuai dengan logika yang dibahas di atas).

Urutan row_ver dapat digunakan untuk mengirimkan data dari ruang lain: tidak perlu membuat urutan terpisah untuk setiap ruang yang ditransmisikan.

Kami melihat cara efektif replikasi data tingkat tinggi dalam aplikasi menggunakan Tarantool DBMS.

Temuan

  1. Tarantool DBMS adalah produk yang menarik dan menjanjikan untuk membuat aplikasi dengan beban tinggi.
  2. Replikasi data tingkat tinggi memiliki sejumlah keunggulan dibandingkan replikasi tingkat rendah.
  3. Metode replikasi tingkat tinggi yang dibahas dalam artikel ini memungkinkan Anda meminimalkan jumlah data yang ditransfer dengan hanya mentransfer catatan yang telah berubah sejak sesi pertukaran terakhir.

Sumber: www.habr.com

Tambah komentar