IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis57/65-dars15 daqiqa
Mundarija (24)

Redis atomikligi: MULTI/EXEC, WATCH, Lua skriptlar va pipelining

Qisqacha: Bitta Redis buyrug'i atomik, lekin bir nechta buyruq ketma-ketligi — yo'q. Kanonda 100 parallel "o'qi → +1 → yoz" natijasi 1 bo'ldi (kutilgan 100). Yechimlar: tayyor atomik buyruq (INCR — 100), MULTI/EXEC (buyruqlar orasiga hech kim kirmaydi, lekin rollback yo'q), WATCH (optimistik qulf — 50 xaridorga 399 urinish), Lua skript (shart va yozuv server ichida, bitta qadamda — qayta urinishsiz). Tezlik uchun — pipelining: 10 000 INCR ketma-ket await bilan 9.6 s, bitta paketda 29 ms.

Bu darsda

  • Redis'da poyga holati qayerdan kelishini ko'rsata olasiz.
  • MULTI/EXEC nimani kafolatlashini va nimani kafolatlamasligini tushuntirasiz.
  • WATCH bilan optimistik qulf va qayta urinish yozasiz.
  • Lua skript (EVAL, EVALSHA, defineScript) va Redis Functions'ni ishlatasiz.
  • Pipelining bilan tarmoq aylanishlarini qisqartirasiz.

Oldin bilishingiz kerak: Hash, List, Set va Sorted Set, Optimistic concurrency, Amaliyot: race condition'larni hal qilish.

Oldingi darslarda har bir Redis buyrug'i atomik ekanini aytdik. Endi savol: bir nechta buyruq birga bajarilishi kerak bo'lsa-chi? Hamma chiqishlar — kanon tajribasi (Redis 8.10.2, node-redis 6.3.0).

1. Nega bu kerak?

Ilovada aksiya: "Birinchi 10 ta foydalanuvchiga premium bepul". Qoldiq Redis'da: t57:qoldiq = 10. Har so'rov qoldiqni o'qiydi, 0 dan katta bo'lsa — bittaga kamaytiradi. Bir vaqtda 50 kishi bosdi. Nechta premium beriladi?

Bu savolni Postgres uchun Amaliyot: race condition'larni hal qilish darsida yechganmiz (qulflar, UPDATE … WHERE qoldiq > 0). Redis'da ham xuddi shu muammo — va o'z yechimlari bor.

2. Poyga holatini o'lchaymiz

Kanon 10 ta alohida ulanishdan 100 ta parallel so'rov yubordi. Har biri: GET → JavaScript'da +1 → SET.

js
await Promise.all(Array.from({ length: 100 }, async (_, i) => {
  const k = ulanishlar[i % 10];
  const v = Number(await k.get("t57:hisob"));
  await k.set("t57:hisob", String(v + 1));
}));

Keyin xuddi shuni INCR bilan:

text
GET+SET natija: 1 (kutilgan 100)
INCR natija: 100

100 ta oshirishdan 99 tasi yo'qoldi. Sabab: hamma 100 ta GET birinchi SET dan oldin bajarildi — hamma 0 ni o'qidi, hamma 1 ni yozdi.

sequenceDiagram
  participant A as Mijoz A
  participant R as Redis
  participant B as Mijoz B
  A->>R: GET hisob
  R-->>A: 0
  B->>R: GET hisob
  R-->>B: 0
  A->>R: SET hisob 1
  B->>R: SET hisob 1
  Note over R: natija 1, kutilgan 2

Diagrammaga qarang: har bir buyruq alohida atomik bajarildi — muammo ular orasida. "O'qish" va "yozish" o'rtasida boshqa mijozning buyrug'i kirdi. Bu — yo'qolgan yangilanish (lost update), Optimistic concurrency darsidagi tanish muammo.

Birinchi qoida: tayyor atomik buyruq bo'lsa — uni ishlating. INCR, HINCRBY, ZINCRBY, SET … NX, LPUSH — server ichida bitta qadam. Muammo murakkabroq mantiqda boshlanadi: "agar qoldiq > 0 bo'lsa, kamaytir".

3. MULTI/EXEC — tranzaksiya

3.1 Buyruqlar paketi

js
const javob = await redis.multi()
  .set("t57:a", "1")
  .incr("t57:a")
  .get("t57:a")
  .exec();
console.log(JSON.stringify(javob));
text
["OK",2,"2"]

MULTI dan keyin berilgan buyruqlar darhol bajarilmaydi — navbatga yig'iladi. EXEC kelganda Redis ularni ketma-ket, hech kimni orasiga qo'ymasdan bajaradi. Javob — har buyruq natijasi massivda.

3.2 Rollback yo'q

Postgres tranzaksiyasidan muhim farq. Kanon ikkinchi buyruq xato beradigan paketni yubordi (t57:matn = "salom"):

js
await redis.multi()
  .incr("t57:a")
  .incr("t57:matn") // satr — xato beradi
  .incr("t57:a")
  .exec();

Uzun qatorda uch qismga qarang: xato nomi, replies massivi va oxirida t57:a ning qiymati.

text
xatoli MULTI: MultiErrorReply 1 commands failed, see .replies and .errorIndexes for more information | replies: [3,{},4] | t57:a = 4
  • MultiErrorReply — "1 ta buyruq muvaffaqiyatsiz; .replies va .errorIndexes ga qarang".
  • replies: [3, {}, 4] — birinchi va uchinchi INCR bajarildi (3 va 4). O'rtadagi xato ({} — JSON.stringify da ko'rinmagan xato obyekti).
  • t57:a = 4 — o'zgarishlar qoldi.

Redis tranzaksiyasi — "hammasi yoki hech biri" emas. U faqat izolyatsiya beradi: orasiga boshqa buyruq kirmaydi. Ishlash paytidagi xato (noto'g'ri tur) qolganlarini to'xtatmaydi va bajarilganini qaytarmaydi. Redis hujjati buni ataylab tanlov deb tushuntiradi: bunday xatolar — dasturchi xatosi, ular testda ushlanishi kerak.

Faqat navbatga qo'yish paytidagi xato (masalan buyruq nomi yoki argumentlar soni noto'g'ri) boshqacha: Redis uni EXEC dan oldin ko'radi va butun paketni rad etadi (EXECABORT). Bu holat kanonda sinalmagan — Redis hujjatiga ko'ra.

Yana bir muhim narsa: MULTI ichida natijani o'qib, unga qarab qaror qilib bo'lmaydi. GET javobi faqat EXEC dan keyin keladi. "Qoldiq > 0 bo'lsa kamaytir" uchun MULTI o'zi yetmaydi.

Tekshirib ko'ring: MULTI; DECR qoldiq; LPUSH qoldiq x; EXEC — qoldiq 10 edi. Natijadan keyin qoldiq nimaga teng?

Javob
  1. DECR bajarildi. LPUSH satr ustida WRONGTYPE xato berdi, lekin DECR qaytarilmaydi — Redis'da rollback yo'q. EXEC javobi [9, xato] bo'ladi.

4. WATCH — optimistik qulf

4.1 Qanday ishlaydi

WATCH kalit — "shu kalitni kuzat". Keyin MULTI … EXEC. Agar WATCH dan EXEC gacha kimdir kalitni o'zgartirgan bo'lsa — EXEC bajarilmaydi. Bu Optimistic concurrency dagi versiya tekshiruvining Redis varianti.

Kanon ataylab aralashdi: A mijoz WATCH qilib, qoldiqni o'qidi; shu orada B (c.decr) qoldiqni kamaytirdi; keyin A EXEC qildi. Vaqt bo'yicha:

Qadam A ulanish B ulanish Natija
1 WATCH t57:qoldiq — A kalitni kuzatadi
2 GET → 10 — A "10 bor" deb o'yladi
3 — DECR → 9 kuzatilgan kalit o'zgardi
4 MULTI, SET 9, EXEC — EXEC bekor: WatchError
text
WATCH dan keyin EXEC: WatchError: One (or more) of the watched keys has been changed | qoldiq: 9

"Kuzatilgan kalitlardan biri (yoki bir nechtasi) o'zgardi". A ning yozuvi bekor qilindi — qoldiq B qo'ygan 9 da qoldi. A endi qayta urinishi kerak.

4.2 50 xaridor, 10 ta mahsulot

js
for (;;) {
  urinish++;
  await k.watch("t57:qoldiq");
  const qold = Number(await k.get("t57:qoldiq"));
  if (qold <= 0) { await k.unwatch(); return; }
  try {
    await k.multi()
      .set("t57:qoldiq", String(qold - 1))
      .exec();
    sotildi++;
    return;
  } catch (x) {
    if (x.constructor.name !== "WatchError") throw x;
  }
}
text
WATCH+retry: sotildi 10, qoldiq 0, urinishlar 399

To'g'ri natija — 10 ta sotildi, ortiqcha yo'q. Lekin narxi: 50 xaridor uchun 399 urinish. Raqobat qancha kuchli bo'lsa, shuncha ko'p behuda aylanish. Optimistik qulf kam to'qnashuvli joyda yaxshi; "flash sale" kabi qizg'in nuqtada — qimmat.

Diqqat: WATCH — ulanish holati. Bitta ulanishni bir nechta parallel oqim bo'lishsa, ularning WATCH lari aralashib ketadi. Kanon har xaridorga alohida ulanish berdi (redis.duplicate()). node-redis 5 dan beri eski executeIsolated yo'q — WATCH uchun alohida klient (yoki hovuz) kerak.

5. Lua skript — server ichidagi mantiq

5.1 EVAL

Redis ichida Lua dasturlash tili bor. Skript server ichida, bitta atomik qadam sifatida bajariladi: u ishlab turganda boshqa hech qanday buyruq bajarilmaydi. Shart, o'qish va yozish — hammasi bir joyda.

lua
local q = tonumber(redis.call('GET', KEYS[1]))
if q and q > 0 then
  redis.call('DECR', KEYS[1])
  return 1
end
return 0

Kanonda bu skript bitta qatorda (SOT o'zgaruvchisi). Lua sintaksisi JavaScript'ga yaqin: local — let, if … then … end, tonumber — Number. redis.call('GET', …) — skript ichidan Redis buyrug'i. KEYS[1] — birinchi kalit argumenti (Lua'da massivlar 1 dan sanaladi).

js
const r = await Promise.all(Array.from({ length: 50 }, (_, i) =>
  ulanishlar[i % 10].eval(SOT, { keys: ["t57:qoldiq"] })));
text
Lua EVAL: sotildi 10, qoldiq 0

10 ta sotildi, hech qanday qayta urinishsiz: har skript chaqiruvi boshqasi tugaguncha kutadi. 50 so'rov — 50 ta chaqiruv (WATCH'da 399 edi).

Kalitlarni doim KEYS orqali bering, skript ichida nomini yasamang. Redis Cluster (ma'lumot bir nechta Redis serverga bo'lingan tuzilma — Redis persistence va operatsiya darsida qisqacha) skriptni qaysi serverga yuborishni KEYS dan biladi. Kalit bo'lmagan qiymatlar — ARGV ({ keys: [...], arguments: [...] }).

5.2 EVALSHA va NOSCRIPT

Har safar skript matnini tarmoqdan yuborish o'rniga, uni bir marta yuklab, SHA1 hash'i bilan chaqirish mumkin:

text
SCRIPT LOAD sha: c9f20637bccb… | EVALSHA: 0 | noma'lum sha: NOSCRIPT No matching script. Please use EVAL.
  • SCRIPT LOAD — skript keshga yuklandi, hash qaytdi.
  • EVALSHA <sha> — hash bilan chaqiruv (qoldiq allaqachon 0 — natija 0).
  • Noma'lum hash — NOSCRIPT: "mos skript yo'q, EVAL ishlating". Skript keshi Redis qayta ishga tushganda (yoki SCRIPT FLUSH dan keyin) tozalanadi.

node-redis defineScript bilan buni o'zi boshqaradi — avval EVALSHA, NOSCRIPT bo'lsa EVAL:

js
import { createClient, defineScript } from "redis";

const redis = createClient({
  url,
  scripts: {
    sot: defineScript({
      NUMBER_OF_KEYS: 1,
      SCRIPT: SOT,
      parseCommand: (parser, kalit) => parser.pushKey(kalit),
      transformReply: (x) => x,
    }),
  },
});
await redis.connect();
await redis.set("t57:qoldiq", "1");
console.log(
  "node-redis defineScript (EVALSHA, NOSCRIPT bo'lsa EVAL):",
  await redis.sot("t57:qoldiq"),
  await redis.sot("t57:qoldiq"),
);
text
node-redis defineScript (EVALSHA, NOSCRIPT bo'lsa EVAL): 1 0

Qoldiq 1 edi: birinchi chaqiruv sotdi (1), ikkinchisi — yo'q (0). ioredis'da xuddi shu g'oya — redis.defineCommand("sot", { numberOfKeys: 1, lua: SOT }).

5.3 Lua'dagi xato

text
Lua xatosi: ERR value is not an integer or out of range script: 61636018f4e6b5817b89791bbed242f93fa089e3, on @user_script:1.

Skript satr ustida INCR qildi. Xabar skript hash'ini va qatorini ko'rsatadi (@user_script:1). MULTI dagidek: xatodan oldin bajarilgan redis.call lar qaytarilmaydi. Shuning uchun skriptda avval hamma tekshiruvni qiling, keyin yozing.

Lua skript bitta oqimni band qiladi. Uzoq sikl yoki minglab kalitni aylanadigan skript — KEYS * kabi butun serverni to'xtatadi. Skriptlar qisqa bo'lsin.

5.4 Redis Functions

Redis 7 dan skriptlarni nom bilan, kutubxona sifatida serverda saqlash mumkin — Redis Functions:

text
FCALL sot: 2 | FUNCTION LIST: [{"library_name":"vz","engine":"LUA","functions":[{"name":"sot","description":null,"flags"

Kanon vz kutubxonasini FUNCTION LOAD bilan yukladi, keyin SCRIPT FLUSH (skript keshini tozalash) qildi — va FCALL sot 1 t57:qoldiq baribir ishladi (qoldiq 3 → 2). Funksiyalar skript keshidan farqli ravishda ma'lumot bilan birga saqlanadi va replikalarga ko'chadi. Katta loyihada umumiy Lua mantiq uchun qulay. Kichik loyihada defineScript yetarli.

6. Pipelining — tarmoq aylanishini qisqartirish

Atomiklik bilan aralashtirib yuboriladigan, lekin boshqa narsa — quvurlash (pipelining): bir nechta buyruqni javobni kutmasdan bitta paketda yuborish. Kanon 10 000 INCR ni to'rt usulda yubordi (3 o'lchov, eng kichik–eng katta). Chiqishda har usul yonidagi millisekundlarga qarang:

text
{"ketma-ket await":"9580–9826 ms","execAsPipeline (1 so'rov)":"29–54 ms","MULTI/EXEC (tranzaksiya)":"30–40 ms","Promise.all":"48–89 ms"}
10 000 INCR: eng tez o'lchov
  • ketma-ket await9 580 ms
  • Promise.all48 ms
  • MULTI/EXEC30 ms
  • execAsPipelinebitta paket, tranzaksiyasiz29 ms

Manba: IlmHamroh kanon o'lchovi, 2026-10-25: Node 24.21.0, node-redis 6.3.0, Redis 8.10.2 (Docker, WSL2), 3 o'lchov

  • Ketma-ket await — 10 000 tarmoq aylanishi: ~1 ms dan, 9.6 s.
  • multi().execAsPipeline() — hamma buyruq bitta paketda, MULTI/EXEC siz: 29 ms. 330 baravar tez.
  • MULTI/EXEC — ham paket, ham izolyatsiya: 30 ms.
  • Promise.all — node-redis avtomatik quvurlaydi (Redis nima va ulanish): 48 ms.

Nima bo'ldi? Buyruqlarning o'zi bir xil, farq faqat tarmoqda. Ketma-ket await har buyruq javobini kutadi — 10 000 marta borib-keladi. Qolgan uchtasi buyruqlarni bitta yoki bir nechta paketda yuboradi.

Farqni tushuning: pipelining — tezlik vositasi, atomiklik emas. execAsPipeline dagi buyruqlar orasiga boshqa mijozlarning buyruqlari kirishi mumkin. Izolyatsiya kerak bo'lsa — exec() (MULTI/EXEC) yoki Lua.

Vosita Atomik Shartli mantiq Tarmoq aylanishi
Bitta buyruq (INCR) ha yo'q 1
MULTI/EXEC izolyatsiya, rollback yo'q yo'q 1
WATCH + MULTI ha (qayta urinish bilan) ha (Node'da) 3+
Lua / Functions ha ha (serverda) 1
Pipelining yo'q yo'q 1

7. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Hisoblagich "yo'qotadi" GET → JS'da +1 → SET INCR / Lua
MULTI dagi xatodan keyin ma'lumot yarim o'zgargan Redis'da rollback yo'q avval tekshiring; Lua'da ham yozuv oxirida
MULTI ichida GET natijasi undefined javoblar faqat EXEC dan keyin shartli mantiq — Lua yoki WATCH
WatchError cheksiz takrorlanadi qizg'in raqobat Lua skript
WATCH ishlamaydi yoki aralashadi bitta ulanish bir nechta oqimda duplicate() — alohida ulanish
NOSCRIPT No matching script Redis qayta ishga tushdi, kesh bo'sh defineScript yoki EVAL ga qaytish
Skript paytida hamma so'rovlar qotadi uzoq Lua sikli skriptni qisqa qiling

8. Mashqlar

Mashqlar kurs/mashqlar/27/57-atomik/ da.

1-mashq (oson): to'g'rimi?

  • MULTI/EXEC ichida xato bo'lsa, oldingi buyruqlar bekor qilinadi —
  • WATCH qilingan kalit EXEC dan oldin o'zgarsa, EXEC bajarilmaydi —
  • Lua skript ishlab turganda boshqa buyruqlar kutadi —
  • execAsPipeline buyruqlari orasiga boshqa mijoz kira olmaydi —
Yechim
  • noto'g'ri — rollback yo'q; kanonda [3, xato, 4].
  • to'g'ri — WatchError, qayta urinish kerak.
  • to'g'ri — shuning uchun skript qisqa bo'lishi kerak.
  • noto'g'ri — pipelining faqat tezlik; izolyatsiya — exec().

2-mashq (o'rta): poygani takrorlang

Redis'siz, toza JavaScript'da kanon tajribasini takrorlang. SoxtaRedis klassi: async get(k), async set(k, v) va atomik async incr(k) (o'qish va yozish orasida await yo'q). 100 ta parallel "o'qi → +1 → yoz" va 100 ta parallel incr natijasini chiqaring. get va set ichida await Promise.resolve() bilan tarmoq kechikishiga taqlid qiling.

Yechim
js
class SoxtaRedis {
  #m = new Map();
  async get(k) {
    await Promise.resolve(); // "tarmoq"
    return this.#m.get(k) ?? null;
  }
  async set(k, v) {
    await Promise.resolve();
    this.#m.set(k, String(v));
  }
  async incr(k) {
    await Promise.resolve();
    // o'qish va yozish orasida await yo'q — atomik
    const yangi = Number(this.#m.get(k) ?? 0) + 1;
    this.#m.set(k, String(yangi));
    return yangi;
  }
}

const r = new SoxtaRedis();
const yuz = (fn) => Promise.all(Array.from({ length: 100 }, fn));

await r.set("hisob", 0);
await yuz(async () => {
  const v = Number(await r.get("hisob"));
  await r.set("hisob", v + 1);
});
console.log("GET+SET:", await r.get("hisob"));

await r.set("hisob", 0);
await yuz(() => r.incr("hisob"));
console.log("INCR:", await r.get("hisob"));

Konsolda:

text
GET+SET: 1
INCR: 100

Natija kanon bilan bir xil. Haqiqiy Redis'siz ham poyga ko'rindi. 100 ta get hammasi birinchi set dan oldin tugadi. Sababi: har await boshqa vazifaga navbat beradi (Microtask va macrotask). incr ichida esa o'qish va yozish orasida await yo'q — JavaScript uni bo'lmay bajaradi, xuddi Redis bitta buyruqni bo'lmay bajargani kabi.

3-mashq (qiyin): optimistik qulf va urinishlar

SoxtaRedis ga versiya qo'shing: async olVersiya(k) → { qiymat, versiya }, async shartliYoz(k, qiymat, versiya) — versiya o'zgarmagan bo'lsa yozib true, aks holda false (WATCH + EXEC taqlidi). 50 xaridor, qoldiq 10: har biri qoldiq > 0 bo'lsa shartliYoz qiladi, false bo'lsa qaytadan urinadi. sotildi, qoldiq, urinishlar ni chiqaring. Keyin xuddi shuni "Lua" uslubida — atomik async sot(k) metodi bilan — qiling va urinishlarni solishtiring.

Yechim
js
class SoxtaRedis {
  #m = new Map();
  async olVersiya(k) {
    await Promise.resolve();
    return this.#m.get(k) ?? { qiymat: 0, versiya: 0 };
  }
  async shartliYoz(k, qiymat, versiya) {
    await Promise.resolve();
    const joriy = this.#m.get(k)?.versiya ?? 0;
    if (joriy !== versiya) return false; // WatchError
    this.#m.set(k, { qiymat, versiya: versiya + 1 });
    return true;
  }
  async sot(k) {
    await Promise.resolve();
    const y = this.#m.get(k); // atomik: "Lua" ichida
    if (!y || y.qiymat <= 0) return 0;
    this.#m.set(k, { qiymat: y.qiymat - 1, versiya: y.versiya + 1 });
    return 1;
  }
}

const xaridorlar = (fn) =>
  Promise.all(Array.from({ length: 50 }, fn));

let r = new SoxtaRedis();
await r.shartliYoz("qoldiq", 10, 0);
let sotildi = 0;
let urinish = 0;
await xaridorlar(async () => {
  for (;;) {
    urinish++;
    const { qiymat, versiya } = await r.olVersiya("qoldiq");
    if (qiymat <= 0) return;
    if (await r.shartliYoz("qoldiq", qiymat - 1, versiya)) {
      sotildi++;
      return;
    }
  }
});
const q1 = (await r.olVersiya("qoldiq")).qiymat;
console.log(`WATCH: sotildi ${sotildi}, qoldiq ${q1},`,
  `urinish ${urinish}`);

r = new SoxtaRedis();
await r.shartliYoz("qoldiq", 10, 0);
const natija = await xaridorlar(() => r.sot("qoldiq"));
const q2 = (await r.olVersiya("qoldiq")).qiymat;
const s2 = natija.filter((x) => x === 1).length;
console.log(`Lua: sotildi ${s2}, qoldiq ${q2},`,
  `chaqiruv ${natija.length}`);

Konsolda:

text
WATCH: sotildi 10, qoldiq 0, urinish 495
Lua: sotildi 10, qoldiq 0, chaqiruv 50

Ikkalasi ham to'g'ri: 10 ta sotildi, ortiqcha yo'q. Lekin optimistik qulf 495 urinish qildi (kanondagi haqiqiy Redis'da 399 — son tarmoq vaqtiga va navbat tartibiga bog'liq, g'oya bir xil). Har "yo'qotgan" xaridor qaytadan o'qiydi. "Lua" usulida shart va yozuv bitta atomik qadamda — 50 chaqiruv, qayta urinish yo'q. Qizg'in raqobatda Lua tanlanadi.

9. Loyiha qadami: kanon tajribasi, loyihaga hali kirmaydi

vazifalar-api ga bu darsda kod qo'shilmaydi: ilovada hozircha Redis'da bir nechta buyruqni birga bajarish kerak bo'lgan joy yo'q. Kesh (Caching naqshlari va invalidatsiya) yagona INCR (avlod raqami) bilan ishlaydi — eng oddiy atomik buyruq yetarli. Lua va SET NX qulflari keyingi darslarda kesh himoyasida va rate limit'da kerak bo'ladi. O'zingiz sinab ko'ring: redis-cli da MULTI, INCR a, LPUSH a x, INCR a, EXEC bering va natijada nechta buyruq bajarilganini ko'ring.

10. Real ishda

  • Aksiya va qoldiq — Lua skript yoki DECR + tekshiruv; flash sale'da WATCH qimmat.
  • Rate limiter'lar — rate-limiter-flexible kabi kutubxonalar ichida Lua skriptlar (Distributed lock va rate limit).
  • BullMQ — navbat holatlari Lua skriptlar bilan atomik o'zgaradi (29-qism).
  • Ommaviy yuklash — minglab buyruq pipelining bilan.
  • Intervyuda: "Redis tranzaksiyasi Postgres'nikidan nimasi bilan farq qiladi?", "WATCH qanday ishlaydi?", "Lua skript nega atomik?", "Pipelining va MULTI farqi?"

Xulosa

  • Bitta buyruq atomik; buyruqlar ketma-ketligi — yo'q: "o'qi-+1-yoz" 100 dan 1 berdi.
  • MULTI/EXEC — izolyatsiya, lekin rollback yo'q va natijaga qarab qaror qilib bo'lmaydi.
  • WATCH — optimistik qulf: to'g'ri, lekin raqobatda qimmat (50 xaridor — 399 urinish).
  • Lua (EVAL, EVALSHA, defineScript, Functions) — shart va yozuv server ichida, bitta qadamda; skript qisqa bo'lsin.
  • Pipelining — tezlik, atomiklik emas: 10 000 buyruq 9.6 s dan 29 ms gacha.

Keyingi dars: Caching naqshlari va invalidatsiya — cache-aside, TTL va jitter, eskirgan kesh, cache stampede va vazifalar-api ga Redis keshini qo'shamiz.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Redis atomikligi: MULTI/EXEC, WATCH, Lua skriptlar va pipelining — IlmHamroh