Сайн байна уу, би DBMS-д зориулсан программ үүсгэж байна
Хүч чадлыг мэдэр! (... гүйцэтгэлийг сайхан өнгөрүүлээрэй)
Дээр дурдсан бүхэн Tarantool-ийг мэдээллийн сантай ажилладаг өндөр ачаалалтай програмуудыг бий болгох сонирхолтой платформ болгодог. Ийм програмуудад ихэвчлэн өгөгдлийг хуулбарлах шаардлагатай байдаг.
Дээр дурдсанчлан Tarantool-д өгөгдөл хуулбарлах боломжтой. Түүний үйл ажиллагааны зарчим нь мастер бүртгэлд (WAL) агуулагдсан бүх гүйлгээг хуулбар дээр дараалан гүйцэтгэх явдал юм. Ихэнхдээ ийм хуулбар (бид үүнийг цаашид дуудах болно доод түвшин) нь програмын алдааны хүлцлийг хангах ба/эсвэл кластерийн зангилааны хооронд унших ачааллыг хуваарилахад ашиглагддаг.
Цагаан будаа. 1. Кластер доторх хуулбарлах
Альтернатив хувилбарын жишээ нь нэг мэдээллийн санд үүсгэсэн өгөгдлийг боловсруулах/хяналт хийх зорилгоор өөр мэдээллийн сан руу шилжүүлэх явдал юм. Сүүлчийн тохиолдолд ашиглах нь илүү тохиромжтой шийдэл байж болно өндөр түвшин хуулбарлах - програмын бизнесийн логик түвшинд өгөгдлийг хуулбарлах. Тэдгээр. Бид DBMS-д суурилуулсан бэлэн шийдлийг ашигладаггүй, харин өөрсдийн боловсруулж буй програмын хүрээнд хуулбарлах ажлыг бие даан хэрэгжүүлдэг. Энэ арга нь давуу болон сул талуудтай. Давуу талуудыг жагсаацгаая.
1. Замын хөдөлгөөний хэмнэлт:
- Та бүх өгөгдлийг дамжуулах боломжгүй, гэхдээ зөвхөн нэг хэсгийг нь (жишээлбэл, та зөвхөн зарим хүснэгт, тэдгээрийн зарим багана эсвэл тодорхой шалгуурыг хангасан бүртгэлийг шилжүүлж болно);
- Асинхрон (Tarantool-ийн одоогийн хувилбар - 1.10-д хэрэгжсэн) эсвэл синхрон (Tarantool-ийн дараагийн хувилбаруудад хэрэгжих) горимд тасралтгүй хийгддэг доод түвшний хуулбараас ялгаатай нь өндөр түвшний хуулбарыг сесс (өөрөөр хэлбэл, програм эхлээд өгөгдлийг синхрончилдог - солилцооны сессийн өгөгдөл, дараа нь хуулбарлах завсарлага, дараа нь дараагийн солилцооны сесс үүснэ гэх мэт);
- хэрэв бичлэг хэд хэдэн удаа өөрчлөгдсөн бол та зөвхөн түүний хамгийн сүүлийн хувилбарыг шилжүүлж болно (бага түвшний хуулбараас ялгаатай нь мастер дээр хийсэн бүх өөрчлөлтийг хуулбарууд дээр дараалан тоглуулах болно).
2. Алсын мэдээллийн санг синхрончлох боломжийг олгодог HTTP солилцоог хэрэгжүүлэхэд ямар ч хүндрэл байхгүй.
Цагаан будаа. 2. HTTP дээр хуулбарлах
3. Өгөгдөл дамжуулах өгөгдлийн сангийн бүтэц нь ижил байх албагүй (түүнээс гадна ерөнхий тохиолдолд өөр өөр 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 дахь хүснэгтүүдийг хоосон зай, бичлэгийг tuple гэж нэрлэдэг. 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
дарааллын дараагийн утга хүртэл хадгалагдсан tuple 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. Бодит программд хуудасны хэмжээ ихэвчлэн илүү чухал байдаг. Энэ нь сансрын tuple-ийн дундаж хэмжээнээс хамаарна. Хуудасны оновчтой хэмжээг өгөгдөл дамжуулах хугацааг хэмжих замаар эмпирик байдлаар тодорхойлж болно. Хуудасны хэмжээ том байх тусам илгээх болон хүлээн авагч талуудын хоорондох эргэлтийн тоо бага байх болно. Ингэснээр та өөрчлөлтийг татаж авах нийт хугацааг багасгаж чадна. Гэсэн хэдий ч, хэрэв хуудасны хэмжээ хэтэрхий том бол бид дээжийг цуваа болгоход сервер дээр хэтэрхий удаан зарцуулах болно. Үүний үр дүнд серверт ирж буй бусад хүсэлтийг боловсруулахад саатал гарч болзошгүй. Параметр 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 хэлбэрээр үр дүнг гаргахыг энэ нийтлэлийн хүрээнээс гадуур үлдээх болно. Та энэ тухай эндээс уншиж болно:
Үйлчлүүлэгч/боол хэсгийн хэрэгжилт
Хүлээн авагч талын хэрэгжилт ямар байгааг харцгаая. Татаж авсан өгөгдлийг хадгалахын тулд хүлээн авагч талд зай үүсгэцгээе:
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 ашиглан програмуудад өндөр түвшний өгөгдлийг хуулбарлах үр дүнтэй аргыг авч үзсэн.
үр дүн нь
- Tarantool DBMS нь өндөр ачаалалтай програмуудыг бий болгоход зориулсан сэтгэл татам, ирээдүйтэй бүтээгдэхүүн юм.
- Өндөр түвшний өгөгдлийн хуулбар нь доод түвшний хуулбараас хэд хэдэн давуу талтай байдаг.
- Өгүүлэлд дурдсан өндөр түвшний хуулбарлах арга нь зөвхөн сүүлийн солилцооны сессээс хойш өөрчлөгдсөн бүртгэлийг шилжүүлэх замаар шилжүүлсэн өгөгдлийн хэмжээг багасгах боломжийг олгодог.
Эх сурвалж: www.habr.com