Mundarija (24)
- Bu darsda
- 1. Nega bu kerak?
- 2. Poyga holatini o'lchaymiz
- 3. MULTI/EXEC — tranzaksiya
- 3.1 Buyruqlar paketi
- 3.2 Rollback yo'q
- 4. WATCH — optimistik qulf
- 4.1 Qanday ishlaydi
- 4.2 50 xaridor, 10 ta mahsulot
- 5. Lua skript — server ichidagi mantiq
- 5.1 EVAL
- 5.2 EVALSHA va NOSCRIPT
- 5.3 Lua'dagi xato
- 5.4 Redis Functions
- 6. Pipelining — tarmoq aylanishini qisqartirish
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): to'g'rimi?
- 2-mashq (o'rta): poygani takrorlang
- 3-mashq (qiyin): optimistik qulf va urinishlar
- 9. Loyiha qadami: kanon tajribasi, loyihaga hali kirmaydi
- 10. Real ishda
- Xulosa
- Manbalar
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 000INCRketma-ketawaitbilan 9.6 s, bitta paketda 29 ms.
Bu darsda
- Redis'da poyga holati qayerdan kelishini ko'rsata olasiz.
MULTI/EXECnimani kafolatlashini va nimani kafolatlamasligini tushuntirasiz.WATCHbilan 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.
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:
GET+SET natija: 1 (kutilgan 100)
INCR natija: 100100 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 2Diagrammaga 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
const javob = await redis.multi()
.set("t57:a", "1")
.incr("t57:a")
.get("t57:a")
.exec();
console.log(JSON.stringify(javob));["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"):
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.
xatoli MULTI: MultiErrorReply 1 commands failed, see .replies and .errorIndexes for more information | replies: [3,{},4] | t57:a = 4MultiErrorReply— "1 ta buyruq muvaffaqiyatsiz;.repliesva.errorIndexesga qarang".replies: [3, {}, 4]— birinchi va uchinchiINCRbajarildi (3 va 4). O'rtadagi xato ({}—JSON.stringifyda 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—qoldiq10 edi. Natijadan keyinqoldiqnimaga teng?
Javob
DECRbajarildi.LPUSHsatr ustidaWRONGTYPExato berdi, lekinDECRqaytarilmaydi — Redis'da rollback yo'q.EXECjavobi[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 |
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
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;
}
}WATCH+retry: sotildi 10, qoldiq 0, urinishlar 399To'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, ularningWATCHlari aralashib ketadi. Kanon har xaridorga alohida ulanish berdi (redis.duplicate()). node-redis 5 dan beri eskiexecuteIsolatedyo'q —WATCHuchun 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.
local q = tonumber(redis.call('GET', KEYS[1]))
if q and q > 0 then
redis.call('DECR', KEYS[1])
return 1
end
return 0Kanonda 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).
const r = await Promise.all(Array.from({ length: 50 }, (_, i) =>
ulanishlar[i % 10].eval(SOT, { keys: ["t57:qoldiq"] })));Lua EVAL: sotildi 10, qoldiq 010 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:
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 — natija0).- Noma'lum hash —
NOSCRIPT: "mos skript yo'q, EVAL ishlating". Skript keshi Redis qayta ishga tushganda (yokiSCRIPT FLUSHdan keyin) tozalanadi.
node-redis defineScript bilan buni o'zi boshqaradi — avval EVALSHA, NOSCRIPT bo'lsa EVAL:
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"),
);node-redis defineScript (EVALSHA, NOSCRIPT bo'lsa EVAL): 1 0Qoldiq 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
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:
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:
{"ketma-ket await":"9580–9826 ms","execAsPipeline (1 so'rov)":"29–54 ms","MULTI/EXEC (tranzaksiya)":"30–40 ms","Promise.all":"48–89 ms"}- 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/EXECsiz: 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/EXECichida xato bo'lsa, oldingi buyruqlar bekor qilinadi —WATCHqilingan kalitEXECdan oldin o'zgarsa,EXECbajarilmaydi —- Lua skript ishlab turganda boshqa buyruqlar kutadi —
execAsPipelinebuyruqlari 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
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:
GET+SET: 1
INCR: 100Natija 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
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:
WATCH: sotildi 10, qoldiq 0, urinish 495
Lua: sotildi 10, qoldiq 0, chaqiruv 50Ikkalasi 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'daWATCHqimmat. - Rate limiter'lar —
rate-limiter-flexiblekabi 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
- Redis hujjati — tranzaksiyalar (MULTI, EXEC, WATCH; nega rollback yo'q): https://redis.io/docs/latest/develop/interact/transactions/
- Lua skriptlar (EVAL, EVALSHA, KEYS/ARGV): https://redis.io/docs/latest/develop/interact/programmability/eval-intro/
- Redis Functions: https://redis.io/docs/latest/develop/interact/programmability/functions-intro/
- Pipelining: https://redis.io/docs/latest/develop/use/pipelining/
- node-redis —
multi,execAsPipeline,defineScript: https://github.com/redis/node-redis/blob/master/docs/transactions.md - Chiqishlar — kanon o'lchovi (IlmHamroh, 2026-10): Redis 8.10.2, Node 24.21.0, node-redis 6.3.0.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!