Tarantool DBMSda yuqori darajadagi replikatsiya

Salom, men DBMS uchun ilovalar yaratyapman Tarantool Mail.ru Group tomonidan ishlab chiqilgan platforma boΚ»lib, u yuqori unumli DBMS va Lua tilidagi dastur serverini birlashtiradi. Tarantool asosidagi yechimlarning yuqori tezligiga, xususan, DBMSning xotira rejimini qo'llab-quvvatlash va ma'lumotlar bilan bitta manzil maydonida amaliy biznes mantiqini bajarish qobiliyati tufayli erishiladi. Shu bilan birga, ACID tranzaktsiyalari yordamida ma'lumotlarning barqarorligi ta'minlanadi (diskda WAL jurnali saqlanadi). Tarantool replikatsiya va parchalanish uchun o'rnatilgan yordamga ega. 2.1 versiyasidan boshlab SQL tilidagi so'rovlar qo'llab-quvvatlanadi. Tarantool ochiq manba va Simplified BSD litsenziyasi ostida litsenziyalangan. Tijoriy Enterprise versiyasi ham mavjud.

Tarantool DBMSda yuqori darajadagi replikatsiya
Quvvatni his eting! (...aka spektakldan zavqlaning)

Yuqorida aytilganlarning barchasi Tarantool-ni ma'lumotlar bazalari bilan ishlaydigan yuqori yuklangan ilovalarni yaratish uchun jozibali platformaga aylantiradi. Bunday ilovalarda ko'pincha ma'lumotlarni ko'paytirishga ehtiyoj bor.

Yuqorida aytib o'tilganidek, Tarantool o'rnatilgan ma'lumotlar replikatsiyasiga ega. Uning ishlash printsipi asosiy jurnalda (WAL) mavjud bo'lgan barcha operatsiyalarni takrorlashda ketma-ket bajarishdir. Odatda bunday replikatsiya (biz uni keyinroq chaqiramiz past darajadagi) dasturning nosozlikka chidamliligini ta'minlash va/yoki o'qish yukini klaster tugunlari o'rtasida taqsimlash uchun ishlatiladi.

Tarantool DBMSda yuqori darajadagi replikatsiya
Guruch. 1. Klaster ichida replikatsiya

Muqobil stsenariyga misol sifatida bitta ma'lumotlar bazasida yaratilgan ma'lumotlarni qayta ishlash/monitoring uchun boshqa ma'lumotlar bazasiga o'tkazish mumkin. Ikkinchi holda, foydalanish uchun qulayroq echim bo'lishi mumkin yuqori daraja replikatsiya - ilovaning biznes mantiqiy darajasida ma'lumotlarni takrorlash. Bular. Biz DBMSga o'rnatilgan tayyor yechimdan foydalanmaymiz, lekin biz ishlab chiqayotgan dastur doirasida replikatsiyani o'zimiz amalga oshiramiz. Ushbu yondashuv ham afzalliklarga, ham kamchiliklarga ega. Keling, afzalliklarini sanab o'tamiz.

1. Trafikni tejash:

  • Siz barcha ma'lumotlarni o'tkaza olmaysiz, lekin uning faqat bir qismini (masalan, siz faqat ba'zi jadvallarni, ularning ba'zi ustunlarini yoki ma'lum bir mezonga javob beradigan yozuvlarni o'tkazishingiz mumkin);
  • Asinxron (Tarantool ning joriy versiyasida joriy etilgan - 1.10) yoki sinxron (Tarantoolning keyingi versiyalarida amalga oshiriladi) doimiy ravishda amalga oshiriladigan past darajadagi replikatsiyadan farqli o'laroq, yuqori darajadagi replikatsiya sessiyalarda (ya'ni, ilova birinchi navbatda ma'lumotlarni sinxronlashtiradi - almashish seansi ma'lumotlari, keyin replikatsiyada pauza bo'ladi, shundan so'ng keyingi almashinuv seansi sodir bo'ladi va hokazo);
  • agar yozuv bir necha marta o'zgargan bo'lsa, siz uning faqat so'nggi versiyasini o'tkazishingiz mumkin (past darajadagi replikatsiyadan farqli o'laroq, masterda kiritilgan barcha o'zgarishlar replikalarda ketma-ket ijro etiladi).

2. Masofaviy ma'lumotlar bazalarini sinxronlashtirish imkonini beruvchi HTTP almashinuvini amalga oshirishda hech qanday qiyinchiliklar yo'q.

Tarantool DBMSda yuqori darajadagi replikatsiya
Guruch. 2. HTTP orqali replikatsiya

3. Ma'lumotlar uzatiladigan ma'lumotlar bazasi tuzilmalari bir xil bo'lishi shart emas (bundan tashqari, umumiy holatda, hatto turli xil DBMS, dasturlash tillari, platformalar va boshqalarni ishlatish mumkin).

Tarantool DBMSda yuqori darajadagi replikatsiya
Guruch. 3. Geterogen sistemalarda replikatsiya

Salbiy tomoni shundaki, o'rtacha hisobda dasturlash konfiguratsiyadan ko'ra qiyinroq/xarajatdir va o'rnatilgan funksiyani sozlash o'rniga o'zingiznikini amalga oshirishingiz kerak bo'ladi.

Agar sizning vaziyatingizda yuqoridagi afzalliklar hal qiluvchi ahamiyatga ega bo'lsa (yoki zaruriy shart bo'lsa), unda yuqori darajadagi replikatsiyadan foydalanish mantiqan to'g'ri keladi. Keling, Tarantool DBMSda yuqori darajadagi ma'lumotlar replikatsiyasini amalga oshirishning bir necha usullarini ko'rib chiqaylik.

Trafikni minimallashtirish

Shunday qilib, yuqori darajadagi replikatsiyaning afzalliklaridan biri bu trafikni tejashdir. Ushbu afzallik to'liq amalga oshirilishi uchun har bir almashuv sessiyasida uzatiladigan ma'lumotlar hajmini minimallashtirish kerak. Albatta, sessiya oxirida ma'lumotlarni qabul qiluvchi manba bilan sinxronlashtirilishi kerakligini unutmasligimiz kerak (hech bo'lmaganda replikatsiyada ishtirok etadigan ma'lumotlarning bir qismi uchun).

Yuqori darajadagi replikatsiya vaqtida uzatiladigan ma'lumotlar miqdorini qanday kamaytirish mumkin? To'g'ridan-to'g'ri yechim sana va vaqt bo'yicha ma'lumotlarni tanlash bo'lishi mumkin. Buni amalga oshirish uchun siz jadvalda mavjud bo'lgan sana-vaqt maydonidan foydalanishingiz mumkin (agar mavjud bo'lsa). Masalan, "buyurtma" hujjatida "buyurtmani bajarish vaqti" maydoni bo'lishi mumkin - delivery_time. Ushbu yechim bilan bog'liq muammo shundaki, bu sohadagi qiymatlar buyurtmalarni yaratishga mos keladigan ketma-ketlikda bo'lishi shart emas. Shunday qilib, biz maksimal maydon qiymatini eslay olmaymiz delivery_time, oldingi almashuv seansida uzatiladi va keyingi almashinuv seansida yuqoriroq maydon qiymatiga ega barcha yozuvlarni tanlang delivery_time. Birja seanslari orasida kichikroq maydon qiymatiga ega yozuvlar qo'shilgan bo'lishi mumkin delivery_time. Bundan tashqari, buyurtma o'zgarishlarga duch kelishi mumkin edi, ammo bu maydonga ta'sir qilmadi delivery_time. Ikkala holatda ham o'zgarishlar manbadan belgilangan joyga o'tkazilmaydi. Ushbu muammolarni hal qilish uchun biz ma'lumotlarni "bir-biriga mos keladigan" uzatishimiz kerak bo'ladi. Bular. har bir almashinuv seansida biz barcha ma'lumotlarni maydon qiymati bilan uzatamiz delivery_time, o'tmishdagi bir nuqtadan oshib ketgan (masalan, hozirgi paytdan boshlab N soat). Biroq, katta tizimlar uchun bu yondashuv juda keraksiz va biz harakat qilayotgan trafikni tejashni hech narsaga kamaytirishi aniq. Bundan tashqari, uzatilayotgan jadvalda sana-vaqt bilan bog'langan maydon bo'lmasligi mumkin.

Amalga oshirish nuqtai nazaridan murakkabroq bo'lgan yana bir yechim - ma'lumotlarning qabul qilinishini tan olishdir. Bunday holda, har bir almashuv sessiyasida barcha ma'lumotlar uzatiladi, ularning olinganligi qabul qiluvchi tomonidan tasdiqlanmagan. Buni amalga oshirish uchun siz manba jadvaliga mantiqiy ustun qo'shishingiz kerak bo'ladi (masalan, is_transferred). Agar qabul qiluvchi yozuvni olganligini tan olsa, tegishli maydon qiymatni oladi true, shundan so'ng kirish endi almashinuvlarda ishtirok etmaydi. Ushbu amalga oshirish opsiyasi quyidagi kamchiliklarga ega. Birinchidan, o'tkazilgan har bir yozuv uchun tasdiq yaratilishi va yuborilishi kerak. Taxminan aytganda, bu uzatilgan ma'lumotlar miqdorini ikki baravar oshirish va aylanma sayohatlar sonini ikki baravar oshirish bilan solishtirish mumkin. Ikkinchidan, bir xil yozuvni bir nechta qabul qiluvchilarga yuborish imkoniyati yo'q (birinchi qabul qiluvchi o'zi uchun ham, qolganlari uchun ham kvitansiyani tasdiqlaydi).

Yuqorida keltirilgan kamchiliklarga ega bo'lmagan usul - uzatilgan jadvalga uning satrlaridagi o'zgarishlarni kuzatish uchun ustun qo'shishdir. Bunday ustun sana-vaqt turiga ega bo'lishi mumkin va har safar yozuvlar qo'shilgan/o'zgartirilganda (qo'shish/o'zgartirish bilan atomik tarzda) joriy vaqtga ilova tomonidan o'rnatilishi/yangilanishi kerak. Misol tariqasida, ustunni chaqiramiz update_time. O'tkazilgan yozuvlar uchun ushbu ustunning maksimal maydoni qiymatini saqlash orqali biz ushbu qiymat bilan keyingi almashinuv seansini boshlashimiz mumkin (maydon qiymatiga ega yozuvlarni tanlang. update_time, oldindan saqlangan qiymatdan oshib ketgan). Oxirgi yondashuv bilan bog'liq muammo shundaki, ma'lumotlar o'zgarishi partiyalarda sodir bo'lishi mumkin. Ustundagi maydon qiymatlari natijasida update_time noyob bo'lmasligi mumkin. Shunday qilib, bu ustundan qismlarga bo'lingan (sahifa-sahifa) ma'lumotlarni chiqarish uchun foydalanilmaydi. Ma'lumotlarni sahifama-sahifa ko'rsatish uchun siz juda past samaradorlikka ega bo'lgan qo'shimcha mexanizmlarni ixtiro qilishingiz kerak bo'ladi (masalan, ma'lumotlar bazasidan qiymati bo'lgan barcha yozuvlarni olish). update_time ma'lum biridan yuqori va namunaning boshidan ma'lum bir ofsetdan boshlab ma'lum miqdordagi yozuvlarni ishlab chiqaradi).

Oldingi yondashuvni biroz yaxshilash orqali ma'lumotlarni uzatish samaradorligini oshirishingiz mumkin. Buning uchun biz o'zgarishlarni kuzatish uchun ustun maydoni qiymatlari sifatida butun son turini (uzun butun son) ishlatamiz. Keling, ustunga nom beraylik row_ver. Ushbu ustunning maydon qiymati har safar yozuv yaratilganda/o'zgartirilganda o'rnatilishi/yangilanishi kerak. Ammo bu holda, maydonga joriy sana-vaqt tayinlanmaydi, lekin ba'zi hisoblagichning qiymati bittaga oshiriladi. Natijada, ustun row_ver noyob qiymatlarni o'z ichiga oladi va nafaqat "delta" ma'lumotlarini ko'rsatish uchun (oldingi almashinuv seansining oxiridan beri qo'shilgan/o'zgartirilgan ma'lumotlar), balki ularni oddiy va samarali ravishda sahifalarga ajratish uchun ham ishlatilishi mumkin.

Yuqori darajadagi replikatsiya doirasida uzatiladigan ma'lumotlar miqdorini minimallashtirishning oxirgi taklif qilingan usuli menga eng maqbul va universal ko'rinadi. Keling, buni batafsil ko'rib chiqaylik.

Qator versiyasi hisoblagichi yordamida ma'lumotlarni uzatish

Server/master qismini amalga oshirish

MS SQL Serverda ushbu yondashuvni amalga oshirish uchun maxsus ustun turi mavjud - rowversion. Har bir ma'lumotlar bazasida ustunga ega bo'lgan jadvalga yozuv qo'shilganda/o'zgartirilganda bittaga ko'payadigan hisoblagich mavjud rowversion. Ushbu hisoblagichning qiymati qo'shilgan/o'zgartirilgan yozuvdagi ushbu ustunning maydoniga avtomatik ravishda tayinlanadi. Tarantool DBMSda shunga o'xshash o'rnatilgan mexanizm yo'q. Biroq, Tarantoolda uni qo'lda amalga oshirish qiyin emas. Keling, bu qanday amalga oshirilganini ko'rib chiqaylik.

Birinchidan, bir oz terminologiya: Tarantool-dagi jadvallar bo'shliqlar deb ataladi va yozuvlar kortejlar deb ataladi. Tarantool-da siz ketma-ketliklar yaratishingiz mumkin. Ketma-ketliklar tartiblangan tamsayΔ± qiymatlarining nomlangan generatorlaridan boshqa narsa emas. Bular. bu bizning maqsadlarimiz uchun kerak bo'lgan narsadir. Quyida biz shunday ketma-ketlikni yaratamiz.

Tarantool-da har qanday ma'lumotlar bazasi operatsiyasini bajarishdan oldin, siz quyidagi buyruqni bajarishingiz kerak:

box.cfg{}

Natijada, Tarantool joriy katalogga ma'lumotlar bazasi suratlari va tranzaksiya jurnallarini yozishni boshlaydi.

Keling, ketma-ketlikni yarataylik row_version:

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

Variant if_not_exists yaratish skriptini bir necha marta bajarishga imkon beradi: agar ob'ekt mavjud bo'lsa, Tarantool uni qayta yaratishga urinmaydi. Ushbu parametr barcha keyingi DDL buyruqlarida qo'llaniladi.

Keling, misol sifatida bo'sh joy yarataylik.

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

Bu erda biz bo'sh joy nomini o'rnatamiz (goods), maydon nomlari va ularning turlari.

Tarantool'da avtomatik o'sish maydonlari ham ketma-ketliklar yordamida yaratiladi. Maydonlar bo'yicha avtomatik o'sadigan asosiy kalitni yarataylik 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 bir necha turdagi indekslarni qo'llab-quvvatlaydi. Eng ko'p ishlatiladigan indekslar TREE va HASH turlari bo'lib, ular nomga mos keladigan tuzilmalarga asoslangan. TREE - eng ko'p qirrali indeks turi. Bu sizga ma'lumotlarni tartibli tarzda olish imkonini beradi. Ammo tenglikni tanlash uchun HASH ko'proq mos keladi. Shunga ko'ra, asosiy kalit uchun HASH dan foydalanish tavsiya etiladi (biz shunday qildik).

Ustunni ishlatish uchun row_ver o'zgartirilgan ma'lumotlarni uzatish uchun siz ushbu ustunning maydonlariga ketma-ketlik qiymatlarini bog'lashingiz kerak row_ver. Lekin asosiy kalitdan farqli o'laroq, ustun maydoni qiymati row_ver nafaqat yangi yozuvlarni qo'shganda, balki mavjudlarini o'zgartirganda ham bittaga ko'payishi kerak. Buning uchun triggerlardan foydalanishingiz mumkin. Tarantool ikki turdagi kosmik tetiklarga ega: before_replace ΠΈ on_replace. Triggerlar bo'shliqdagi ma'lumotlar har safar o'zgarganda ishga tushiriladi (o'zgarishlardan ta'sirlangan har bir kortej uchun trigger funktsiyasi ishga tushiriladi). Undan farqli o'laroq on_replace, before_replace-triggerlar trigger bajariladigan kortej ma'lumotlarini o'zgartirish imkonini beradi. Shunga ko'ra, oxirgi turdagi triggerlar bizga mos keladi.

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

Quyidagi trigger maydon qiymatini almashtiradi row_ver ketma-ketlikning keyingi qiymatiga saqlanadi row_version.

Kosmosdan ma'lumotlarni chiqarib olish uchun goods ustun bo'yicha row_ver, indeks yaratamiz:

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

Indeks turi - daraxt (TREE), chunki ustundagi qiymatlarning o'sish tartibida ma'lumotlarni chiqarib olishimiz kerak bo'ladi row_ver.

Keling, bo'sh joyga ba'zi ma'lumotlarni qo'shamiz:

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}

Chunki Birinchi maydon avtomatik o'sish hisoblagichi; biz uning o'rniga nolga o'tamiz. Tarantool avtomatik ravishda keyingi qiymatni almashtiradi. Xuddi shunday, ustun maydonlarining qiymati sifatida row_ver nolga o'tishingiz mumkin - yoki umuman qiymatni belgilamaysiz, chunki bu ustun bo'shliqda oxirgi o'rinni egallaydi.

Keling, kiritish natijasini tekshiramiz:

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

Ko'rib turganingizdek, birinchi va oxirgi maydonlar avtomatik ravishda to'ldiriladi. Endi bo'sh joy o'zgarishlarini sahifama-sahifa yuklash funksiyasini yozish oson bo'ladi 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

Funktsiya parametr sifatida qiymatni oladi row_ver, undan boshlab o'zgarishlarni tushirish kerak va o'zgartirilgan ma'lumotlarning bir qismini qaytaradi.

Tarantool-da ma'lumotlarni tanlash indekslar orqali amalga oshiriladi. Funktsiya get_goods indeks bo'yicha iteratordan foydalanadi row_ver o'zgartirilgan ma'lumotlarni olish uchun. Iterator turi GT (kattaroq, kattaroq). Bu shuni anglatadiki, iterator o'tkazilgan kalitdan (maydon qiymati) boshlab indeks qiymatlarini ketma-ket bosib o'tadi. row_ver).

Iterator kortejlarni qaytaradi. Keyinchalik HTTP orqali ma'lumotlarni uzatish imkoniyatiga ega bo'lish uchun kortejlarni keyingi ketma-ketlashtirish uchun qulay tuzilishga aylantirish kerak. Misol uchun standart funksiyadan foydalaniladi tomap. Foydalanish o'rniga tomap o'z funktsiyangizni yozishingiz mumkin. Misol uchun, biz maydon nomini o'zgartirishni xohlashimiz mumkin name, maydondan o'tmang code va maydon qo'shing 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

Chiqish ma'lumotlarining sahifa hajmi (bir qismdagi yozuvlar soni) o'zgaruvchi tomonidan belgilanadi page_size. Misolda qiymat page_size 5. Haqiqiy dasturda sahifa hajmi odatda ko'proq ahamiyatga ega. Bu kosmik tuplening o'rtacha hajmiga bog'liq. Optimal sahifa hajmi ma'lumotlarni uzatish vaqtini o'lchash orqali empirik tarzda aniqlanishi mumkin. Sahifaning o'lchami qanchalik katta bo'lsa, jo'natuvchi va qabul qiluvchi tomonlar o'rtasidagi aylanishlar soni shunchalik kichik bo'ladi. Shunday qilib, siz o'zgarishlarni yuklab olish uchun umumiy vaqtni qisqartirishingiz mumkin. Biroq, agar sahifa o'lchami juda katta bo'lsa, biz namunani serializatsiya qilish uchun serverda juda uzoq vaqt sarflaymiz. Natijada, serverga keladigan boshqa so'rovlarni qayta ishlashda kechikishlar bo'lishi mumkin. Parametr page_size konfiguratsiya faylidan yuklanishi mumkin. Har bir uzatilgan makon uchun siz o'z qiymatini belgilashingiz mumkin. Biroq, ko'pchilik bo'shliqlar uchun standart qiymat (masalan, 100) mos kelishi mumkin.

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

Maydon qiymatini olaylik row_ver oxirgi qatordan boshlab funktsiyani qayta chaqiring:

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

Yana bir bor:

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

Ko'rib turganingizdek, shu tarzda foydalanilganda, funksiya barcha bo'sh joy yozuvlarini sahifama-sahifa qaytaradi goods. Oxirgi sahifadan keyin bo'sh tanlov mavjud.

Keling, bo'shliqqa o'zgartirish kiritamiz:

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

Biz maydon qiymatini o'zgartirdik name bitta kirish uchun va ikkita yangi yozuv qo'shildi.

Keling, oxirgi funktsiya chaqiruvini takrorlaymiz:

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

Funktsiya o'zgartirilgan va qo'shilgan yozuvlarni qaytardi. Shunday qilib, funktsiya get_goods ko'rib chiqilayotgan replikatsiya usulining asosi bo'lgan oxirgi qo'ng'iroqdan keyin o'zgargan ma'lumotlarni olish imkonini beradi.

HTTP orqali natijalarni JSON ko'rinishida chiqarishni ushbu maqola doirasidan tashqarida qoldiramiz. Bu haqda bu yerda oβ€˜qishingiz mumkin: https://habr.com/ru/company/mailru/blog/272141/

Mijoz/qul qismini amalga oshirish

Keling, qabul qiluvchi tomonning amalga oshirishi qanday ko'rinishini ko'rib chiqaylik. Yuklab olingan ma'lumotlarni saqlash uchun qabul qiluvchi tomonda bo'sh joy yarataylik:

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

Kosmosning tuzilishi manbadagi makonning tuzilishiga o'xshaydi. Ammo biz qabul qilingan ma'lumotlarni boshqa joyga o'tkazmasligimiz sababli, ustun row_ver oluvchining maydonida emas. Dalada id manba identifikatorlari yozib olinadi. Shuning uchun, qabul qiluvchi tomonda uni avtomatik ravishda oshirishga hojat yo'q.

Bundan tashqari, qadriyatlarni saqlash uchun bizga bo'sh joy kerak 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
})

Har bir yuklangan joy uchun (maydon space_name) oxirgi yuklangan qiymatni shu yerda saqlaymiz row_ver (maydon value). Ustun asosiy kalit vazifasini bajaradi space_name.

Keling, kosmik ma'lumotlarni yuklash funksiyasini yarataylik goods HTTP orqali. Buning uchun bizga HTTP mijozini amalga oshiradigan kutubxona kerak. Quyidagi qator kutubxonani yuklaydi va HTTP mijozini ishga tushiradi:

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

Bizga json deserialization uchun kutubxona ham kerak:

local json = require('json')

Bu ma'lumotlarni yuklash funksiyasini yaratish uchun etarli:

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

Funktsiya url manziliga HTTP so'rovini bajaradi va uni yuboradi row_ver parametr sifatida va so'rovning seriyasizlashtirilgan natijasini qaytaradi.

Qabul qilingan ma'lumotlarni saqlash funktsiyasi quyidagicha ko'rinadi:

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

Kosmosga ma'lumotlarni saqlash davri goods tranzaktsiyaga joylashtirilgan (funktsiya buning uchun ishlatiladi box.atomic) diskdagi operatsiyalar sonini kamaytirish uchun.

Nihoyat, mahalliy kosmik sinxronizatsiya funktsiyasi goods manba bilan siz buni shunday amalga oshirishingiz mumkin:

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

Avval biz avval saqlangan qiymatni o'qiymiz row_ver bo'sh joy uchun goods. Agar u etishmayotgan bo'lsa (birinchi almashinuv seansi), biz uni shunday qabul qilamiz row_ver nol. Keyingi tsiklda biz belgilangan urldagi manbadan o'zgartirilgan ma'lumotlarni sahifama-sahifa yuklab olishni amalga oshiramiz. Har bir iteratsiyada biz olingan ma'lumotlarni tegishli mahalliy maydonga saqlaymiz va qiymatni yangilaymiz row_ver (kosmosda row_ver va o'zgaruvchida row_ver) - qiymatni qabul qiling row_ver yuklangan ma'lumotlarning oxirgi qatoridan.

Tasodifiy tsikldan himoya qilish uchun (dasturda xatolik bo'lsa), pastadir while bilan almashtirilishi mumkin for:

for _ = 1, max_req do ...

Funktsiyani bajarish natijasida sync_goods bo'sh joy goods qabul qiluvchi barcha kosmik yozuvlarning so'nggi versiyalarini o'z ichiga oladi goods manbada.

Shubhasiz, ma'lumotlarni o'chirishni bu tarzda translyatsiya qilish mumkin emas. Agar bunday ehtiyoj mavjud bo'lsa, siz o'chirish belgisidan foydalanishingiz mumkin. Bo'sh joyga qo'shing goods mantiqiy maydon is_deleted va yozuvni jismonan o'chirish o'rniga biz mantiqiy o'chirishdan foydalanamiz - biz maydon qiymatini o'rnatamiz is_deleted ma'noga kiradi true. Ba'zan mantiqiy maydon o'rniga is_deleted daladan foydalanish qulayroqdir deleted, bu yozuvni mantiqiy o'chirish sana-vaqtini saqlaydi. Mantiqiy o'chirishni amalga oshirgandan so'ng, o'chirish uchun belgilangan yozuv manbadan belgilangan joyga o'tkaziladi (yuqorida muhokama qilingan mantiq bo'yicha).

Tartib row_ver boshqa bo'shliqlardan ma'lumotlarni uzatish uchun ishlatilishi mumkin: har bir uzatiladigan maydon uchun alohida ketma-ketlikni yaratishga hojat yo'q.

Biz Tarantool DBMS yordamida ilovalarda yuqori darajadagi ma'lumotlarni ko'paytirishning samarali usulini ko'rib chiqdik.

topilmalar

  1. Tarantool DBMS - bu yuqori yuklangan ilovalarni yaratish uchun jozibali, istiqbolli mahsulot.
  2. Yuqori darajadagi ma'lumotlarni takrorlash past darajadagi replikatsiyaga nisbatan bir qator afzalliklarga ega.
  3. Maqolada muhokama qilingan yuqori darajadagi replikatsiya usuli faqat oxirgi almashinuv seansidan keyin o'zgargan yozuvlarni o'tkazish orqali uzatilgan ma'lumotlar miqdorini minimallashtirishga imkon beradi.

Manba: www.habr.com

a Izoh qo'shish