18-bo‘lim

O'zgarishlar oqimi va gorizontal kengayish

watch bilan o'zgarishlarni kuzatish, hodisa turlari, resume token, fullDocument va bo'laklash (sharding) tushunchasi.

🕑 12 daqiqa o‘qish 📄 838 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. watch - oqimni ochish
  2. Hodisa turlari
  3. Oqimni filtrlash
  4. Resume token - uzilishdan keyin davom etish
  5. Butun baza va klaster bo'yicha kuzatish
  6. Gorizontal kengayish - bo'laklash
  7. Xulosa

Ma'lumot o'zgarganda dasturga xabar berish kerak bo'ladi: keshni yangilash, xabar yuborish, qidiruv indeksini sinxronlash. Buni so'rab turish (polling) bilan emas, o'zgarishlar oqimi bilan qilish to'g'ri.

JavaScript
db.buyurtma.insertMany([
  { _id: 1, mijoz: "Husanboy", holat: "yangi", summa: 250000 },
  { _id: 2, mijoz: "Malika",   holat: "yangi", summa: 180000 }
])

watch - oqimni ochish #

JavaScript
const oqim = db.buyurtma.watch()
oqim.disableBlockWarnings()
db.buyurtma.insertOne({ _id: 3, mijoz: "Nodira", summa: 95000 })
const h = oqim.next()
h.operationType
h.documentKey
h.fullDocument
oqim.close()
Natija
ChangeStreamCursor on buyurtma
{ acknowledged: true, insertedId: 3 }

insert
{ _id: 3 }
{ _id: 3, mijoz: 'Nodira', summa: 95000 }

Oqim ochilgandan keyin sodir bo'lgan har bir o'zgarishni beradi.

Hodisa turlari #

JavaScript
const oqim = db.buyurtma.watch()
oqim.disableBlockWarnings()
db.buyurtma.updateOne({ _id: 1 }, { $set: { holat: "yolda" } })
db.buyurtma.deleteOne({ _id: 2 })
const y = oqim.next()
y.operationType
y.updateDescription.updatedFields
const o = oqim.next()
o.operationType
o.documentKey
oqim.close()
Natija
ChangeStreamCursor on buyurtma
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
{ acknowledged: true, deletedCount: 1 }

update
{ holat: 'yolda' }

delete
{ _id: 2 }
operationTypeQachon
insertYangi hujjat
update$set, $inc va shunga o'xshash
replacereplaceOne
deleteO'chirildi
dropTo'plam tashlandi
invalidateOqim yaroqsiz bo'lib qoldi
update hodisasi to'liq hujjatni bermaydi

Odatiy holda update hodisasida faqat o'zgargan maydonlar keladi - updateDescription.updatedFields.

Bu ataylab: butun hujjatni har o'zgarishda yuborish katta hujjatlarda qimmat bo'lardi.

To'liq hujjat kerak bo'lsa, uni ochiq so'rang:

Natija
db.buyurtma.watch([], { fullDocument: "updateLookup" })

Lekin bitta muhim tafsilot bor: updateLookup hujjatni hozirgi holatida o'qiydi, o'zgarish paytidagi holatida emas. Agar o'sha oraliqda yana bir yangilash bo'lsa, siz eng oxirgi holatni olasiz.

MongoDB 6.0 dan boshlab fullDocumentBeforeChange ham bor - u o'zgarishdan oldingi holatni beradi. Buning uchun to'plamda changeStreamPreAndPostImages yoqilgan bo'lishi kerak.

JavaScript
const oqim = db.buyurtma.watch([], { fullDocument: "updateLookup" })
oqim.disableBlockWarnings()
db.buyurtma.updateOne({ _id: 1 }, { $set: { holat: "yakunlandi" } })
const h = oqim.next()
h.operationType
h.fullDocument
oqim.close()
Natija
ChangeStreamCursor on buyurtma
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

update
{ _id: 1, mijoz: 'Husanboy', holat: 'yakunlandi', summa: 250000 }

Oqimni filtrlash #

watch agregatsiya quvurini qabul qiladi:

JavaScript
const oqim = db.buyurtma.watch([
  { $match: {
      operationType: "insert",
      "fullDocument.summa": { $gte: 200000 }
  } }
])
oqim.disableBlockWarnings()
db.buyurtma.insertOne({ _id: 4, mijoz: "Aziza", summa: 50000 })
db.buyurtma.insertOne({ _id: 5, mijoz: "Kamola", summa: 400000 })
const h = oqim.next()
h.fullDocument.mijoz
h.fullDocument.summa
oqim.close()
Natija
ChangeStreamCursor on buyurtma
{ acknowledged: true, insertedId: 4 }
{ acknowledged: true, insertedId: 5 }

Kamola
400000

Birinchi hujjat filtrga tushmadi - oqim uni umuman bermadi. Filtrlash serverda bajariladi, shuning uchun keraksiz ma'lumot tarmoqqa chiqmaydi.

So'rab turish va o'zgarishlar oqimi So'rab turish (polling) Har 5 soniyada: find({ yangi: true }) O'zgarish bo'lmasa ham so'rov ketadi Kechikish: 0 dan 5 soniyagacha Ko'p mijozda yuk chidab bo'lmas bo'ladi O'zgarishlar oqimi watch() - ulanish ochiq turadi Server o'zi xabar beradi Kechikish: millisekundlar Filtr serverda bajariladi Oqim oplog ustida ishlaydi Shuning uchun u replika to'plamini talab qiladi Va oplog hajmi uzilishdan keyin qancha orqaga qaytish mumkinligini belgilaydi
Oqim - bu tranzaksiya jurnalining (oplog) tozalangan va filtrlangan ko'rinishi

Resume token - uzilishdan keyin davom etish #

Har bir hodisada _id bor - bu davom etish belgisi:

JavaScript
const oqim = db.buyurtma.watch()
oqim.disableBlockWarnings()
db.buyurtma.insertOne({ _id: 6, mijoz: "Dilnoza", summa: 77000 })
const h = oqim.next()
typeof h._id._data
h._id._data.length > 0
oqim.close()
Natija
ChangeStreamCursor on buyurtma
{ acknowledged: true, insertedId: 6 }

string
true

Uni saqlab qo'yib, keyinroq shu joydan davom etish mumkin:

Natija
db.buyurtma.watch([], { resumeAfter: saqlangan_token })
Resume token ni saqlashni unutmang

Dastur qayta ishga tushganda oqim noldan boshlanadi - ya'ni uzilish paytidagi o'zgarishlar butunlay o'tkazib yuboriladi.

Bu, ayniqsa, quyidagi holatlarda zarar keltiradi:

VazifaYo'qotish
Qidiruv indeksini sinxronlashIndeks bazadan orqada qoladi
Kesh yangilashEski ma'lumot ko'rsatiladi
Xabar yuborishMijoz xabarni olmaydi

To'g'ri naqsh:

  1. Har hodisani qayta ishlagandan keyin h._id ni saqlang.
  2. Dastur ishga tushganda oxirgi tokendan davom eting.
  3. Token resumeAfter uchun juda eski bo'lsa - MongoDB xato beradi va siz to'liq qayta sinxronlashni boshlaysiz.

Uchinchi holat oplog to'lib ketganda yuz beradi. Oplog hajmi - vaqt oynasi: u 24 soatlik o'zgarishni saqlasa, dastur 24 soatdan ko'p o'chib turmasligi kerak.

Butun baza va klaster bo'yicha kuzatish #

YozuvNimani kuzatadi
db.buyurtma.watch()Bitta to'plam
db.watch()Butun baza
db.getMongo().watch()Butun klaster
JavaScript
const oqim = db.watch()
oqim.disableBlockWarnings()
db.buyurtma.insertOne({ _id: 7, mijoz: "Husanboy", summa: 30000 })
db.mijoz.insertOne({ _id: 1, ism: "Malika" })
const a = oqim.next()
a.ns.coll
const b = oqim.next()
b.ns.coll
oqim.close()
Natija
ChangeStreamCursor on dokon
{ acknowledged: true, insertedId: 7 }
{ acknowledged: true, insertedId: 1 }

buyurtma

mijoz

ns.coll - hodisa qaysi to'plamda sodir bo'lganini ko'rsatadi.

Gorizontal kengayish - bo'laklash #

Bitta server yetmay qolganda ikki yo'l bor:

Yo'lNima qilinadiChegarasi
VertikalKuchliroq serverBir kun kelib tugaydi
GorizontalMa'lumotni serverlarga bo'lishDeyarli cheksiz

MongoDB da gorizontal kengayish sharding deb ataladi. To'plam bo'lak kaliti (shard key) bo'yicha bir nechta serverga taqsimlanadi:

Natija
sh.enableSharding("dokon")
sh.shardCollection("dokon.buyurtma", { mijoz_id: "hashed" })
QismVazifasi
ShardMa'lumotning bir bo'lagini saqlaydigan replika to'plami
mongosSo'rovni to'g'ri shard ga yo'naltiruvchi vositachi
Config serverQaysi bo'lak qayerda ekanini biladi

Dastur mongos ga ulanadi va bo'laklar haqida hech narsa bilmaydi - so'rovlar o'zgarishsiz qolaveradi.

Bo'lak kalitini keyin o'zgartirish juda qiyin

Bo'lak kaliti - shardingdagi eng muhim qaror. Uni noto'g'ri tanlash butun klasterni foydasiz qiladi.

Yomon kalitning uchta belgisi:

MuammoMisolOqibat
Monoton o'suvchisana, ObjectIdHamma yangi yozuv bitta shard ga tushadi
Kam xilma-xillikholat (3 ta qiymat)Ko'pi bilan 3 ta bo'lak
So'rovlarga mos emasKalit mijoz_id, so'rov sana bo'yichaHar so'rov hamma shard ga boradi

Birinchisi eng ko'p uchraydi va u "issiq shard" muammosini keltirib chiqaradi: o'nta serverdan bittasi 100% yuk ostida, qolgan to'qqiztasi bo'sh turadi.

Yaxshi kalit uchta shartni bajaradi: yuqori xilma-xillik, teng taqsimlanish va so'rovlarga moslik.

MongoDB 5.0 dan boshlab kalitni qayta belgilash (reshardCollection) mumkin, lekin bu butun ma'lumotni ko'chirishni anglatadi - terabaytlik to'plamda bu kunlar davom etadi.

Amaliy maslahat: shardingni kerak bo'lgunicha qilmang. Ko'p loyihada bitta yaxshi indekslangan replika to'plami yetadi.

Amaliy topshiriq
  1. watch() bilan oqim oching va hujjat qo'shing.
  2. operationType va documentKey ni chiqaring.
  3. update hodisasida nima kelishini tekshiring.
  4. fullDocument: "updateLookup" qo'shib, farqni ko'ring.
  5. updateLookup ning cheklovini o'z so'zingiz bilan yozing.
  6. Oqimga $match filtri qo'shing.
  7. Filtrga tushmagan hujjat kelmasligini tasdiqlang.
  8. Resume token nima uchun kerakligini tushuntiring.
  9. db.watch() bilan butun bazani kuzating.
  10. Yomon bo'lak kalitining uchta belgisini sanang.

Xulosa #

  • O'zgarishlar oqimi so'rab turishning o'rnini bosadi: server o'zi xabar beradi.
  • watch() oqim ochilgandan keyingi o'zgarishlarni beradi.
  • operationType hodisa turini bildiradi: insert, update, delete va boshqalar.
  • update hodisasi faqat o'zgargan maydonlarni beradi.
  • To'liq hujjat uchun fullDocument: "updateLookup" kerak - lekin u hozirgi holatni o'qiydi.
  • watch agregatsiya quvurini qabul qiladi - filtrlash serverda bajariladi.
  • Har hodisadagi _id - resume token; uni saqlamasangiz uzilish paytidagi o'zgarishlar yo'qoladi.
  • Oqim oplog ustida ishlaydi, shuning uchun replika to'plami talab qilinadi.
  • Gorizontal kengayish - sharding; dastur mongos ga ulanadi va bo'laklarni ko'rmaydi.
  • Bo'lak kaliti eng muhim qaror: monoton o'suvchi kalit butun yukni bitta shard ga to'playdi.

Keyingi bo'limda xavfsizlik va zaxira nusxani ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.