Tarantool DBMSде жогорку деңгээлдеги репликация

Саламатсызбы, мен DBMS үчүн тиркемелерди түзүп жатам Tarantool — бул Mail.ru Group тарабынан иштелип чыккан платформа, ал жогорку натыйжалуу ДББЖ менен Lua тилиндеги тиркеме серверин бириктирет. Tarantool негизиндеги чечимдердин жогорку ылдамдыгына, атап айтканда, МББнын эс тутум режимин колдоо жана маалыматтар менен бир дарек мейкиндигинде тиркеме бизнес логикасын аткаруу мүмкүнчүлүгүнөн улам жетишилет. Ошол эле учурда ACID транзакцияларынын жардамы менен берилиштердин туруктуулугу камсыздалат (дискте WAL журналы сакталат). Tarantool репликациялоо жана бөлүү үчүн орнотулган колдоого ээ. 2.1 версиясынан баштап, SQL тилиндеги сурамдар колдоого алынат. Tarantool ачык булак жана жөнөкөйлөштүрүлгөн BSD лицензиясы боюнча лицензияланган. Коммерциялык Enterprise версиясы да бар.

Tarantool DBMSде жогорку деңгээлдеги репликация
Күчтү сезиңиз! (...ака аткаруудан ырахат алыңыз)

Жогоруда айтылгандардын баары Tarantoolду маалымат базалары менен иштеген жогорку жүктөмдүү тиркемелерди түзүү үчүн жагымдуу платформа кылат. Мындай тиркемелерде көбүнчө маалыматтарды репликациялоо зарылчылыгы бар.

Жогоруда айтылгандай, Tarantool камтылган маалыматтарды репликациясына ээ. Анын иштөө принциби репликалар боюнча башкы журналда (WAL) камтылган бардык транзакцияларды ырааттуу аткаруу болуп саналат. Көбүнчө мындай репликация (мындан ары аны атайбыз төмөн деңгээл) колдонмонун каталарына чыдамдуулугун камсыз кылуу жана/же окуу жүгүн кластердик түйүндөр ортосунда бөлүштүрүү үчүн колдонулат.

Tarantool DBMSде жогорку деңгээлдеги репликация
Райс. 1. Кластердин ичиндеги репликация

Альтернативдик сценарийдин мисалы бир маалымат базасында түзүлгөн маалыматтарды кайра иштетүү/мониторинг үчүн башка маалымат базасына өткөрүп берүү. Акыркы учурда, бир кыйла ыңгайлуу чечим колдонуу болушу мүмкүн жогорку деңгээл репликация - тиркеменин бизнес логикалык деңгээлинде маалыматтарды репликациялоо. Ошол. Биз ДББга орнотулган даяр чечимди колдонбойбуз, бирок биз иштеп жаткан тиркеменин ичинде репликацияны өз алдынча ишке ашырабыз. Бул ыкманын артыкчылыктары да, кемчиликтери да бар. Келгиле, артыкчылыктарды санап көрөлү.

1. Трафикти үнөмдөө:

  • Сиз бардык маалыматтарды өткөрүп бере албайсыз, бирок анын бир бөлүгүн гана (мисалы, кээ бир таблицаларды, алардын айрым мамычаларын же белгилүү бир критерийге жооп берген жазууларды гана өткөрүп бере аласыз);
  • Үзгүлтүксүз асинхрондуу (Tarantoolдун учурдагы версиясында ишке ашырылган - 1.10) же синхрондуу (Tarantoolдун кийинки версияларында ишке ашырыла турган) төмөнкү деңгээлдеги репликациядан айырмаланып, жогорку деңгээлдеги репликация сессияларда (б.а.) аткарылышы мүмкүн. тиркеме адегенде маалыматтарды синхронизациялайт - алмашуу сессиясынын маалыматтары, андан кийин репликацияда тыныгуу болот, андан кийин кийинки алмашуу сессиясы ж.б.у.с.);
  • эгерде жазуу бир нече жолу өзгөргөн болсо, анын акыркы версиясын гана өткөрүп бере аласыз (көпүрөөчүгө киргизилген бардык өзгөртүүлөр репликаларда ырааттуу түрдө ойнотула турган төмөнкү деңгээлдеги репликациядан айырмаланып).

2. Алыскы маалымат базаларын синхрондоштурууга мүмкүндүк берген HTTP алмашууну ишке ашырууда эч кандай кыйынчылыктар жок.

Tarantool DBMSде жогорку деңгээлдеги репликация
Райс. 2. HTTP аркылуу репликациялоо

3. Маалыматтар өткөрүлүүчү маалыматтар базасынын түзүмдөрү бирдей болууга тийиш эмес (андан тышкары, жалпы учурда, ал тургай, ар кандай СББ, программалоо тилдерин, платформаларды ж.б. колдонууга болот).

Tarantool DBMSде жогорку деңгээлдеги репликация
Райс. 3. Гетерогендик системалардагы репликация

Кемчилиги, орто эсеп менен программалоо конфигурацияга караганда татаал/кымбатыраак жана орнотулган функцияны ыңгайлаштыруунун ордуна, сиз өзүңүздүн ишиңизди ишке ашырышыңыз керек болот.

Эгерде сиздин жагдайыңызда жогорудагы артыкчылыктар чечүүчү мааниге ээ болсо (же зарыл шарт болсо), анда жогорку деңгээлдеги репликацияны колдонуунун мааниси бар. Келгиле, Tarantool DBMSде жогорку деңгээлдеги маалыматтардын репликациясын ишке ашыруунун бир нече жолдорун карап көрөлү.

Трафикти минималдаштыруу

Ошентип, жогорку деңгээлдеги репликациянын артыкчылыктарынын бири трафикти үнөмдөө болуп саналат. Бул артыкчылык толугу менен ишке ашырылышы үчүн, ар бир алмашуу сессиясында берилүүчү маалыматтардын көлөмүн минималдаштыруу зарыл. Албетте, сессиянын аягында маалыматтарды кабыл алуучу булак менен синхрондоштуруу керек экенин унутпашыбыз керек (жок дегенде репликацияга катышкан маалыматтардын ошол бөлүгү үчүн).

Жогорку деңгээлдеги репликациялоо учурунда берилүүчү маалыматтардын көлөмүн кантип азайтуу керек? Түз чечим датасы жана убактысы боюнча маалыматтарды тандоо болушу мүмкүн. Бул үчүн, сиз таблицада мурунтан эле бар дата-убак тилкесин колдоно аласыз (эгерде ал бар болсо). Мисалы, "буйрутма" документинде "заказды аткаруунун талап кылынган убактысы" деген талаа болушу мүмкүн - delivery_time. Бул чечимдин көйгөйү - бул тармактагы баалуулуктар буйруктарды түзүүгө туура келген ырааттуулукта болбошу керек. Ошентип, биз максималдуу талаа маанисин эстей албайбыз delivery_time, мурунку алмашуу сессиясында берилүүчү жана кийинки алмашуу сессиясында талаа мааниси жогору болгон бардык жазууларды тандаңыз delivery_time. Талаа мааниси төмөн болгон жазуулар алмашуу сессияларынын ортосунда кошулган болушу мүмкүн delivery_time. Ошондой эле, тартип, ошентсе да, талаага таасирин тийгизген эмес, өзгөрүүлөргө дуушар болушу мүмкүн delivery_time. Эки учурда тең өзгөртүүлөр булактан көздөгөн жерге өткөрүлбөйт. Бул көйгөйлөрдү чечүү үчүн, биз маалыматтарды "кабат-кабат" өткөрүп берүү керек болот. Ошол. ар бир алмашуу сессиясында биз талаа мааниси менен бардык маалыматтарды өткөрүп берет delivery_time, өткөн бир чекиттен ашкан (мисалы, азыркы учурдан N саат). Бирок, чоң системалар үчүн бул ыкма өтө ашыкча жана биз аракет кылып жаткан трафикти үнөмдөөнү эч нерсеге азайта алаары айдан ачык. Мындан тышкары, өткөрүлүп жаткан таблицада дата-убакыт менен байланышкан талаа жок болушу мүмкүн.

Дагы бир чечим, ишке ашыруу жагынан кыйла татаал, маалыматтардын кабыл алынганын ырастоо болуп саналат. Бул учурда, ар бир алмашуу сессиясынын жүрүшүндө, кабыл алуучу тарабынан тастыкталбаган бардык маалыматтар берилет. Муну ишке ашыруу үчүн булак таблицасына логикалык тилке кошуу керек болот (мисалы, is_transferred). Эгерде кабыл алуучу жазууну алгандыгын ырастаса, тиешелүү талаа маанини алат true, андан кийин кирүү мындан ары алмашуу катышат. Бул ишке ашыруу опциясы төмөнкү кемчиликтерге ээ. Биринчиден, өткөрүлүп берилген ар бир жазуу үчүн тастыктоо түзүлүп, жөнөтүлүшү керек. Болжол менен айтканда, бул берилүүчү маалыматтардын көлөмүн эки эсеге көбөйтүү менен салыштырууга болот жана айланма каттамдардын санын эки эсеге көбөйтүүгө алып келет. Экинчиден, бир эле жазууну бир нече кабыл алуучуга жөнөтүү мүмкүнчүлүгү жок (биринчи кабыл алган кабыл алуучу өзү үчүн да, калгандары үчүн да квитанцияны ырастайт).

Жогоруда келтирилген кемчиликтери жок ыкма, анын саптарындагы өзгөрүүлөргө көз салуу үчүн берилүүчү таблицага мамычаны кошуу. Мындай тилке дата-убакыт тибинде болушу мүмкүн жана жазуулар ар бир кошулган/өзгөрүлгөн (атомикалык түрдө кошуу/өзгөртүү менен) учурдагы убакытка тиркеме тарабынан коюлушу/жаңыртылууга тийиш. Мисал катары колонканы чакыралы update_time. Өткөрүлгөн жазуулар үчүн бул тилкенин максималдуу талаа маанисин сактоо менен, биз кийинки алмашуу сессиясын ушул маани менен баштасак болот (талаа мааниси бар жазууларды тандаңыз) update_time, мурда сакталган мааниден ашкан). Акыркы ыкманын көйгөйү - маалыматтардын өзгөрүшү партияларда болушу мүмкүн. Мамычадагы талаа маанилеринин натыйжасында update_time уникалдуу болбошу мүмкүн. Ошентип, бул тилкени бөлүштүрүлгөн (барак-барак) маалымат чыгаруу үчүн колдонуу мүмкүн эмес. Берилиштерди барактан бетке көрсөтүү үчүн сиз өтө төмөн эффективдүүлүккө ээ болгон кошумча механизмдерди ойлоп табышыңыз керек болот (мисалы, маалыматтар базасынан бардык жазууларды мааниси менен алуу update_time берилгенден жогору жана үлгүнүн башынан белгилүү бир офсеттен баштап белгилүү бир сандагы жазууларды чыгарат).

Сиз мурунку ыкманы бир аз жакшыртуу менен маалыматтарды берүүнүн натыйжалуулугун жогорулата аласыз. Бул үчүн, биз өзгөрүүлөргө көз салуу үчүн тилке талаасынын маанилери катары бүтүн сан түрүн (узун бүтүн сан) колдонобуз. Колоннага ат коёлу row_ver. Бул тилкенин талаасынын мааниси жазуу түзүлгөн/өзгөрүлгөн сайын коюлушу/жаңыртылуусу керек. Бирок бул учурда, талаага учурдагы дата-убакыт дайындалбайт, бирок кээ бир эсептегичтин мааниси бирге көбөйөт. Натыйжада колонна row_ver уникалдуу баалуулуктарды камтыйт жана "дельта" маалыматтарды көрсөтүү үчүн гана эмес (маалыматтар мурунку алмашуу сессиясынын аяктагандан бери кошулган/өзгөрүлгөн), ошондой эле аны жөнөкөй жана натыйжалуу барактарга бөлүү үчүн колдонулушу мүмкүн.

Жогорку деңгээлдеги репликациянын алкагында берилүүчү маалыматтардын көлөмүн минималдаштыруунун акыркы сунушталган ыкмасы мага эң оптималдуу жана универсалдуу көрүнөт. Келгиле, кененирээк карап көрөлү.

Саптын версиясын эсептегичти колдонуу менен берилиштерди өткөрүү

Сервер/мастер бөлүгүн ишке ашыруу

MS SQL Server, бул ыкманы ишке ашыруу үчүн атайын мамыча түрү бар - rowversion. Ар бир маалымат базасында эсептегич бар, ал ар бир жазуу кошулган/өзгөрүлгөн таблицага бир көбөйөт rowversion. Бул эсептегичтин мааниси автоматтык түрдө кошулган/өзгөрүлгөн жазуудагы бул тилкенин талаасына дайындалат. Tarantool DBMS окшош камтылган механизми жок. Бирок, Тарантоодо аны кол менен ишке ашыруу кыйын эмес. Келгиле, бул кандайча жасалганын карап көрөлү.

Биринчиден, бир аз терминология: Tarantoolдагы таблицалар боштуктар деп аталат, ал эми жазуулар кортеждер деп аталат. Tarantoolда сиз ырааттуулукту түзө аласыз. Ырааттуулук - бул иреттелген бүтүн сандардын аталган генераторлордон башка эч нерсе эмес. Ошол. биздин максаттарыбыз үчүн дал ушул нерсе керек. Төмөндө биз ушундай ырааттуулукту түзөбүз.

Tarantool'да кандайдыр бир маалымат базасы операциясын аткаруудан мурун, сиз төмөнкү буйрукту аткарышыңыз керек:

box.cfg{}

Натыйжада, Tarantool учурдагы каталогго маалымат базасынын сүрөттөрүн жана транзакция журналдарын жаза баштайт.

Келгиле, ырааттуулукту түзөлү row_version:

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

тандоо if_not_exists түзүү сценарийин бир нече жолу аткарууга мүмкүндүк берет: объект бар болсо, Tarantool аны кайра түзүүгө аракет кылбайт. Бул параметр бардык кийинки DDL буйруктарында колдонулат.

Мисал катары мейкиндикти түзөлү.

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

Бул жерде биз мейкиндиктин атын койдук (goods), талаа аттары жана алардын түрлөрү.

Tarantoolдагы автоматтык түрдө өсүүчү талаалар да ырааттуулукту колдонуу менен түзүлөт. Келгиле, талаалар боюнча автоматтык түрдө өсүүчү негизги ачкыч түзөлү 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 индекстердин бир нече түрлөрүн колдойт. Көбүнчө колдонулган индекстер TREE жана HASH түрлөрү болуп саналат, алар атына ылайыктуу структураларга негизделген. TREE – эң көп тараптуу индекс түрү. Ал уюшкан түрдө маалыматтарды алууга мүмкүндүк берет. Бирок теңчиликти тандоо үчүн HASH көбүрөөк ылайыктуу. Демек, негизги ачкыч үчүн HASHти колдонуу сунушталат (бул биз жасаган).

Колонканы колдонуу үчүн row_ver өзгөртүлгөн маалыматтарды өткөрүп берүү үчүн, сиз бул тилкенин талааларына ырааттуулук маанилерин байлашыңыз керек row_ver. Бирок негизги ачкычтан айырмаланып, тилке талаасынын мааниси row_ver жаңы жазууларды кошууда гана эмес, ошондой эле учурдагыларды өзгөртүүдө да бир көбөйүшү керек. Бул үчүн триггерлерди колдонсоңуз болот. Tarantool космостук триггерлер эки түрү бар: before_replace и on_replace. Триггерлер мейкиндиктеги маалыматтар өзгөргөн сайын иштетилет (өзгөрүүлөр таасир эткен ар бир кортеж үчүн триггер функциясы ишке киргизилет). Окшобой on_replace, before_replace-триггерлер триггер аткарылган кортеждин маалыматтарын өзгөртүүгө мүмкүндүк берет. Демек, триггерлердин акыркы түрү бизге ылайыктуу.

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

Төмөнкү триггер талаанын маанисин алмаштырат row_ver ырааттуулуктун кийинки маанисине сакталган кортеж row_version.

Космостон маалыматтарды алуу үчүн goods тилке боюнча row_ver, индексти түзөлү:

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

Индекс түрү - дарак (TREE), анткени биз тилкедеги маанилердин өсүү тартибинде маалыматтарды чыгарып алышыбыз керек row_ver.

Келгиле, мейкиндикке кээ бир маалыматтарды кошолу:

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}

Анткени Биринчи талаа автоматтык түрдө өсүүчү эсептегич; анын ордуна биз нөлгө өтөбүз. Tarantool кийинки маанини автоматтык түрдө алмаштырат. Ошо сыяктуу эле, мамыча талааларынын мааниси катары row_ver нөлгө өтсөңүз болот - же бааны такыр көрсөтпөйсүз, анткени бул тилке мейкиндикте акыркы позицияны ээлейт.

Киргизүүнүн жыйынтыгын текшерип көрөлү:

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

Көрүнүп тургандай, биринчи жана акыркы талаалар автоматтык түрдө толтурулат. Эми мейкиндикти өзгөртүүнү барактан барак жүктөө функциясын жазуу оңой болот 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

Функция параметр катары маанини алат row_ver, андан баштап өзгөртүүлөрдү түшүрүү керек жана өзгөртүлгөн маалыматтардын бир бөлүгүн кайтарат.

Tarantoolдагы маалыматтарды тандоо индекстер аркылуу жүргүзүлөт. Функция get_goods индекси боюнча итераторду колдонот row_ver өзгөртүлгөн маалыматтарды алуу үчүн. Итератордун түрү GT (Улуураак, чоңураак). Бул итератор берилген ачкычтан баштап индекстин маанилерин ырааттуу басып өтөт дегенди билдирет (талаанын мааниси row_ver).

Итератор кортеждерди кайтарат. Кийинчерээк HTTP аркылуу берилиштерди өткөрө алуу үчүн, кортеждерди кийинки сериялаштыруу үчүн ыңгайлуу структурага айландыруу керек. Мисал бул үчүн стандарттык функцияны колдонот tomap. Колдонуунун ордуна tomap сиз өзүңүздүн функцияңызды жаза аласыз. Мисалы, биз талаанын атын өзгөрткүбүз келиши мүмкүн name, талаадан өтпө code жана талаа кошуу 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

Чыгарылган маалыматтардын барак өлчөмү (бир бөлүктөгү жазуулардын саны) өзгөрмө тарабынан аныкталат page_size. Мисалда мааниси page_size 5. Чыныгы программада барактын көлөмү адатта көбүрөөк мааниге ээ. Бул мейкиндик тутумунун орточо өлчөмүнө жараша болот. Оптималдуу барактын өлчөмүн маалымат берүү убактысын өлчөө жолу менен эмпирикалык түрдө аныктоого болот. Барактын көлөмү канчалык чоң болсо, жөнөтүүчү жана кабыл алуучу тараптардын ортосундагы айланма каттамдардын саны ошончолук аз болот. Ушундай жол менен сиз өзгөртүүлөрдү жүктөө үчүн жалпы убакытты кыскарта аласыз. Бирок, эгерде барактын көлөмү өтө чоң болсо, биз серверде үлгүнү сериалдаштырууга өтө көп убакыт сарптайбыз. Натыйжада, серверге келген башка суроо-талаптарды кароодо кечигүүлөр болушу мүмкүн. Параметр page_size конфигурация файлынан жүктөөгө болот. Ар бир өткөрүлүүчү мейкиндик үчүн сиз өз баасын орното аласыз. Бирок, көпчүлүк боштуктар үчүн демейки маани (мисалы, 100) ылайыктуу болушу мүмкүн.

Функцияны аткаралы 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
...

Келгиле, талаанын маанисин алалы row_ver акыркы саптан баштап, функцияны кайра чакырыңыз:

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

Дагы бир жолу:

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

Көрүнүп тургандай, ушундай жол менен колдонулганда, функция бардык мейкиндик жазууларын барактан барактан кайтарат goods. Акыркы барактан кийин бош тандоо турат.

Келгиле, мейкиндикке өзгөртүүлөрдү киргизели:

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

Биз талаанын маанисин өзгөрттүк name бир кириш үчүн жана эки жаңы жазууларды кошту.

Акыркы функция чакырыгын кайталайлы:

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

Функция өзгөртүлгөн жана кошулган жазууларды кайтарды. Ошентип, функция get_goods каралып жаткан репликация ыкмасынын негизи болуп саналган акыркы чалуудан бери өзгөргөн маалыматтарды алууга мүмкүндүк берет.

Жыйынтыктарды HTTP аркылуу JSON түрүндө чыгарууну ушул макаланын чегинен тышкары калтырабыз. Бул тууралуу бул жерден окуй аласыз: https://habr.com/ru/company/mailru/blog/272141/

Кардар/кул бөлүгүн ишке ашыруу

Келгиле, кабыл алуучу тараптын ишке ашыруу кандай экенин карап көрөлү. Жүктөлгөн маалыматтарды сактоо үчүн кабыл алуучу тарапта бош орун түзөлү:

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

Мейкиндиктин түзүлүшү булактагы мейкиндиктин түзүлүшүнө окшош. Бирок биз алынган маалыматтарды башка жакка өткөрбөй жаткандыктан, колонка row_ver алуучунун мейкиндигинде эмес. Талаада id булактардын идентификаторлору жазылат. Ошондуктан, кабыл алуучу тарапта аны автоматтык түрдө көбөйтүүнүн кереги жок.

Мындан тышкары, баалуулуктарды сактоо үчүн мейкиндик керек 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
})

Ар бир жүктөлгөн мейкиндик үчүн (талаа space_name) биз бул жерде акыркы жүктөлгөн маанини сактайбыз row_ver (талаа value). Мамыча негизги ачкыч катары иштейт space_name.

Келгиле, космостук маалыматтарды жүктөө функциясын түзөлү goods HTTP аркылуу. Бул үчүн бизге HTTP кардарын ишке ашырган китепкана керек. Төмөнкү сап китепкананы жүктөйт жана HTTP кардарын инстанциялайт:

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

Бизге json десерализациясы үчүн китепкана да керек:

local json = require('json')

Бул маалыматтарды жүктөө функциясын түзүү үчүн жетиштүү:

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

Функция url дарегине HTTP сурамын аткарат жана аны жөнөтөт row_ver параметр катары жана сурамдын сериядан ажыратылган натыйжасын кайтарат.

Кабыл алынган маалыматтарды сактоо функциясы төмөнкүдөй көрүнөт:

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

Маалыматтарды мейкиндикке сактоо цикли goods транзакцияга жайгаштырылган (бул үчүн функция колдонулат box.atomic) диск операцияларынын санын кыскартуу.

Акыр-аягы, жергиликтүү мейкиндик синхрондоштуруу милдети goods булак менен сиз аны төмөнкүдөй ишке ашыра аласыз:

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

Алгач биз мурда сакталган маанини окуйбуз row_ver космос үчүн goods. Эгерде ал жок болсо (биринчи алмашуу сессиясы), анда биз аны катары кабыл алабыз row_ver нөл. Кийинки циклде биз көрсөтүлгөн url дареги боюнча булактан өзгөртүлгөн маалыматтарды барак-бет жүктөйбүз. Ар бир итерацияда биз алынган маалыматтарды тиешелүү жергиликтүү мейкиндикке сактап, маанини жаңыртабыз row_ver (космосто row_ver жана өзгөрмөдө row_ver) - маанини алыңыз row_ver жүктөлгөн маалыматтардын акыркы сабынан.

Кокус циклден коргоо үчүн (программада ката болгондо), цикл while менен алмаштырылышы мүмкүн for:

for _ = 1, max_req do ...

Функцияны аткаруунун натыйжасында sync_goods космос goods кабыл алуучу бардык космостук жазуулардын акыркы нускаларын камтыйт goods булакта.

Көрүнүп тургандай, маалыматтарды өчүрүүнү мындай жол менен берүү мүмкүн эмес. Мындай муктаждык бар болсо, сиз өчүрүү белгисин колдоно аласыз. Космоско кошуу goods логикалык талаа is_deleted жана жазууну физикалык түрдө жок кылуунун ордуна, биз логикалык өчүрүүнү колдонобуз - биз талаанын маанисин койдук is_deleted мааниге true. Кээде буль талаасынын ордуна is_deleted талааны пайдалануу ынгайлуураак deleted, ал жазууну логикалык жок кылуунун дата-убагын сактайт. Логикалык өчүрүүнү аткаргандан кийин, өчүрүү үчүн белгиленген жазуу булактан көздөгөн жерге (жогоруда талкууланган логикага ылайык) өткөрүлүп берилет.

ирээт row_ver башка мейкиндиктерден маалыматтарды берүү үчүн колдонулушу мүмкүн: ар бир берилген мейкиндик үчүн өзүнчө ырааттуулукту түзүүнүн кереги жок.

Биз Tarantool DBMS колдонуп тиркемелерде жогорку деңгээлдеги маалыматтарды репликациялоонун натыйжалуу жолун карадык.

табылгалары

  1. Tarantool DBMS - бул жогорку жүктөмдүү тиркемелерди түзүү үчүн жагымдуу, келечектүү продукт.
  2. Жогорку деңгээлдеги маалыматтарды репликациялоо төмөнкү деңгээлдеги репликацияга караганда бир катар артыкчылыктарга ээ.
  3. Макалада талкууланган жогорку деңгээлдеги репликация ыкмасы акыркы алмашуу сессиясынан бери өзгөргөн жазууларды гана өткөрүп берүү менен берилүүчү маалыматтардын көлөмүн азайтуу үчүн мүмкүнчүлүк берет.

Source: www.habr.com

Комментарий кошуу