Dasturlash

PostgreSQL’da Raqobat Sharoitlarini Sinash: Sinxronizatsiya To‘siqlari Yordamida

25-mart, 2026, 16:0013 ko'rish3 daqiqa o'qish
PostgreSQL’da Raqobat Sharoitlarini Sinash: Sinxronizatsiya To‘siqlari Yordamida

Ma'lumotlar bazasida raqobat sharoiti (race condition) – bu bir nechta so'rovlar bir vaqtning o'zida bir xil ma'lumotni o'qib, keyin o'zgarishlarni yozganda yuzaga keladigan xatodir. Natijada, ma'lumot yo'qolishi yoki noto'g'ri qiymat saqlanishi mumkin. Bu xatolar ayniqsa moliyaviy tizimlarda jiddiy muammolar keltirib chiqaradi.

Raqobat sharoitini oddiy misol bilan tushunish

Masalan, hisob raqamiga $50 qo‘shish funksiyasi mavjud bo‘lsin. Funksiya avval balansni o‘qiydi, keyin qo‘shadi va yangilangan qiymatni yozadi. Ikki foydalanuvchi bir vaqtning o'zida $50 qo‘shsa, quyidagi ketma‑ketma sodir bo‘lishi mumkin:

  • P1: SELECT balance → 100
  • P2: SELECT balance → 100
  • P1: UPDATE balance = 150
  • P2: UPDATE balance = 150

Natijada balans $150 bo‘lib qoladi, $200 bo‘lishi kerak edi. Bu yerda har ikki so'rov ham eski qiymatni o‘qib, bir-birini ustiga yozgan.

Nega oddiy testlar yetarli emas?

Ko‘pgina test to'plamlari bir vaqtning o'zida bitta so'rovni bajaradi, shuning uchun yuqoridagi o'zaro ta'sir hech qachon sodir bo‘lmaydi. Test muvaffaqiyatli o'tadi, lekin kod haqiqiy paralel muhitda xato bo‘lishi mumkin.

Sinxronizatsiya to‘siqlari (barrier) nima?

Sinxronizatsiya to‘siqlari – bu bir nechta parallel vazifalar bir nuqtada to‘xtab, barcha vazifalar kelguncha kutib turadigan mexanizm. Vazifalar to‘siqni “kiritganda” ularning soni belgilangan miqdorga yetganda, hammasi bir vaqtning o'zida davom etadi.

JavaScript misolida to‘siqni quyidagicha yaratish mumkin:

function createBarrier(count) {
  let arrived = 0;
  let release;
  const barrier = new Promise(resolve => { release = resolve; });
  return async () => {
    arrived++;
    if (arrived === count) release();
    await barrier;
  };
}

Bu funksiya har bir vazifa to‘siqni chaqirganda hisoblagichni oshiradi, oxirgi vazifa kelganda esa hammasi bir vaqtning o'zida davom etadi.

To‘siqni kodga qo‘shish: amaliy misol

Yuqoridagi kredit funksiyasiga to‘siqni qo‘shsak, har ikki vazifa birinchi SELECTni bajaradi, so‘ng to‘siqda kutadi, keyin UPDATEni bajaradi. Natija aniq bo‘lib, raqobat sharoiti har doim yuzaga keladi:

const barrier = createBarrier(2);

async function credit(accountId, amount) {
  const [row] = await db.execute(`SELECT balance FROM accounts WHERE id = ${accountId}`);
  await barrier(); // ikkinchi vazifa ham o‘qiguncha kutadi
  const newBalance = row.balance + amount;
  await db.execute(`UPDATE accounts SET balance = ${newBalance} WHERE id = ${accountId}`);
}

await Promise.all([credit(1, 50), credit(1, 50)]);

Bu test deterministik bo‘lib, har safar $150 natija beradi – raqobat sharoiti aniq ko‘rinadi.

Transaktsiyalar va blokirovkalar bilan sinash

PostgreSQL’da SELECT ... FOR UPDATE iborasi qator darajasida blokirovka (write lock) yaratadi. To‘siqni BEGINdan keyin, lekin SELECTdan oldin qo‘ysak, blokirovka to‘g‘ri ishlaydi:

await db.transaction(async tx => {
  await barrier(); // hamma tranzaksiya boshlanadi
  const [row] = await tx.execute(`SELECT balance FROM accounts WHERE id = ${accountId} FOR UPDATE`);
  const newBalance = row.balance + amount;
  await tx.execute(`UPDATE accounts SET balance = ${newBalance} WHERE id = ${accountId}`);
});

Bu holatda birinchi tranzaksiya qatorni blokirovka qiladi, ikkinchisi esa blokirovka bo‘lishini kutadi, keyin yangilangan qiymatni o‘qiydi. Natija $200 bo‘lib, to‘siq muvaffaqiyatli sinovdan o‘tadi.

Testni ishlab chiqishda e’tibor beriladigan jihatlar

  • Real DB – mock ma'lumotlar bazasi blokirovka va transaktsiyalarni to‘g‘ri emulyatsiya qilmaydi.
  • Hook mexanizmi – to‘siqni test muhitida faqat qo‘shish, ishlab chiqarishda kodga hech qanday yuk qo‘shmaslik.
  • Vanity testlardan saqlanish – to‘siqni o‘chirib, blokirovkasiz sinab ko‘ring; test muvaffaqiyatsiz bo‘lishi kerak, aks holda test foydasiz.

Xulosa

Sinxronizatsiya to‘siqlari raqobat sharoitlarini aniqlash va ularni avtomatik test qilish uchun qudratli vosita hisoblanadi. To‘siqni to‘g‘ri joylashtirish, transaktsiyalar va FOR UPDATE blokirovkasini birgalikda qo‘llash orqali kodni real paralel muhitga tayyorlash mumkin. Natijada, refaktorlar yoki yangi funksiyalar kiritilganda ham, potentsial “yashirin” xatolar ishlab chiqarishga chiqib ketishining oldi olinadi.

Manba: Hacker News
#postgresql #race condition #testing #barrier #concurrency
Telegram da muhokama qilish