Bu darsda nima bor
1–4-qismlar keshni noldan quradi: nega kerak, hit/miss va qatlamlar, strategiyalar va Redis bilan NestJS implementatsiya. 5–6-qismlar — eng muhim production muammolari: invalidatsiya va klassik tuzoqlar. 7-qism nimani keshlash va qachon ishlatmaslik kerakligini hal qiladi.
Nega kerak — bazaning tor bo‘g‘izi
Oddiy o‘xshatish: tez-tez kerak bo‘ladigan hujjatni har safar arxivga (omborga) borib olib kelmaysiz — uni stol ustida, qo‘l ostida saqlaysiz. Bir necha soniya o‘rniga — bir zumda.
Bosh sahifangizdagi "eng ko‘p sotilganlar" ro‘yxatini olaylik. Unga sekundiga 5000 odam kiradi va har biri uchun baza bir xil og‘ir JOINli so‘rovni qayta-qayta bajaradi.
Har bir so‘rovda ma’lumotlar bazasiga murojaat qilish sekin va qimmat. Ma’lumot kam o‘zgarsa ham, baza bir xil natijani minglab marta hisoblaydi. Yuk ortganda baza tor bo‘g‘iz (bottleneck)ga aylanadi: javoblar sekinlashadi, ulanishlar tugaydi va butun tizim cho‘kadi. Bazani kuchaytirish — eng qimmat yechim.
Tez-tez so‘raladigan ma’lumotni tez xotirada (Redis, ilova xotirasi, CDN) saqlash. So‘rov kelganda avval keshdan qaraladi: bo‘lsa — darhol qaytariladi (cache hit, ~1ms); bo‘lmasa — bazadan olinadi, keshga yoziladi va keyingi safarga tayyor turadi (cache miss).
Real tizimlarda so‘rovlarning katta qismi kichik to‘plamdagi mashhur ma’lumotga tushadi (mashhur mahsulot, bosh sahifa, sessiya). Shu "qaynoq" 20%ni keshlasa, bazadagi yukning 80%i yo‘qoladi.
Asosiy g‘oya — hit/miss va kesh qatlamlari
Keshning ikki holati bor va butun mavzu shu ikkitasi atrofida aylanadi:
- Cache HIT — so‘ralgan ma’lumot keshda bor → darhol qaytariladi (bazaga bormaydi).
- Cache MISS — keshda yo‘q → bazadan olinadi, keshga yoziladi, qaytariladi.
Keshning samarasi hit rate (necha % so‘rov keshdan javob oldi) bilan o‘lchanadi. 90% hit rate = bazaga atigi 10% so‘rov tushadi.
Kesh qayerda yashaydi — bir necha qatlam
Kesh bitta joy emas — foydalanuvchidan bazagacha bir necha bosqichda bo‘lishi mumkin. Har biri bazaga yetib borishni kamaytiradi:
| Qatlam | Joyi | Misol |
|---|---|---|
| Brauzer | Mijoz qurilmasida | HTTP Cache-Control, rasm/CSS |
| CDN | Foydalanuvchiga yaqin chekka serverlar | Statik fayllar, rasm, video |
| Ilova ichi (in-memory) | Server jarayoni xotirasi | Eng tez, lekin har nusxada alohida |
| Taqsimlangan kesh | Alohida server (Redis) | Hamma nusxalar uchun umumiy |
Ilova xotirasidagi kesh eng tez, lekin har bir server nusxasida alohida bo‘ladi (5 ta nusxa = 5 ta turli kesh, izchillik yo‘q). Redis — barcha nusxalar uchun yagona, izchil kesh. Production’da odatda Redis tanlanadi.
Strategiyalar — Cache-Aside, write-through/behind
Kesh va baza qanday muvofiqlashadi — bir necha naqsh bor. Eng muhim 4 tasi:
1 · Cache-Aside (lazy loading) — eng keng tarqalgan
Ilova keshni o‘zi boshqaradi: avval keshdan so‘raydi, miss bo‘lsa bazadan olib, keshga yozadi. Kesh "yon"da turadi (aside).
Yozish strategiyalari — Write-through va Write-behind
| Strategiya | Qanday | Kelishuv |
|---|---|---|
| Write-through | Yozuvda ham keshga, ham bazaga birga yoziladi | Kesh doim yangi; lekin yozuv biroz sekinroq |
| Write-behind (write-back) | Avval keshga, bazaga keyinroq (asinxron) | Yozuv juda tez; lekin server qulasa ma’lumot yo‘qolishi mumkin |
| Read-through | Miss’da keshning o‘zi bazadan oladi (ilova emas) | Ilova kodi soddalashadi; kutubxona/kesh qatlami boshqaradi |
Aksariyat holatlarda Cache-Aside + TTL yetarli va eng oddiy — shundan boshlang. Write-through izchillik muhim bo‘lganda, write-behind esa yozuv juda ko‘p va tezlik kritik bo‘lganda ishlatiladi.
NestJS implementatsiya (Redis)
@nestjs/cache-managerNestJS keshni @nestjs/cache-manager orqali beradi. Ikki usul bor: avtomatik (interceptor) va qo‘lda (to‘liq nazorat). Production’da odatda qo‘lda Cache-Aside ko‘proq ishlatiladi.
1 · Kesh modulini ulash (Redis)
// app.module.ts — Redis bilan kesh modulini ulaymiz
import { CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-yet';
@Module({
imports: [
CacheModule.registerAsync({
isGlobal: true,
useFactory: async () => ({
store: await redisStore({ url: 'redis://localhost:6379' }),
ttl: 60_000, // DIQQAT: cache-manager v5 da TTL = millisekund
}),
}),
],
})
export class AppModule {}
2 · Qo‘lda Cache-Aside — to‘liq nazorat
// product.service.ts — qo'lda Cache-Aside (eng ko'p ishlatiladigan naqsh)
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
@Injectable()
export class ProductService {
constructor(
@Inject(CACHE_MANAGER) private cache: Cache,
private repo: ProductRepository,
) {}
async getById(id: string): Promise<Product> {
const key = `product:${id}`;
const cached = await this.cache.get<Product>(key);
if (cached) return cached; // HIT -> darhol
const product = await this.repo.findById(id); // MISS -> bazadan
await this.cache.set(key, product, 60_000); // keshga yoz (60s)
return product;
}
async update(id: string, dto: UpdateProductDto) {
const product = await this.repo.update(id, dto);
await this.cache.del(`product:${id}`); // INVALIDATE (eskisini o'chir)
return product;
}
}
3 · Avtomatik keshlash — interceptor
Oddiy, kam o‘zgaradigan GET endpointlar uchun qulay — kod yozmasdan keshlaydi:
// Avtomatik HTTP keshlash — interceptor (oddiy GET endpointlar uchun)
import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager';
@Controller('products')
@UseInterceptors(CacheInterceptor)
export class ProductController {
@Get()
@CacheKey('products_all')
@CacheTTL(30_000) // 30s
findAll() { return this.service.findAll(); }
}
Redis store paketi (cache-manager-redis-yet / @keyv/redis) va TTL birligi (ms yoki sek) cache-manager versiyasiga qarab farq qiladi. v5+ da TTL — millisekund. Loyihangiz versiyasini tekshiring.
Invalidatsiya — eng qiyin muammo
TTL · write · eventKompyuter fanida mashhur hazil bor: "Faqat ikkita qiyin narsa bor — kesh invalidatsiyasi va narsalarga nom berish." Invalidatsiya — keshning eng og‘riqli muammosi.
Mahsulot narxi bazada o‘zgardi, lekin keshda eski narx turibdi. Foydalanuvchi noto‘g‘ri narx ko‘radi. Savol: ma’lumot o‘zgarganda keshdagi eski nusxani qachon va qanday yangilash kerak?
3 ta yondashuv
1 · TTL (Time To Live) — eng oddiy. Har keshga yashash muddati beriladi (masalan 60s). Muddat tugagach o‘zi o‘chadi va keyingi so‘rovda yangilanadi. Kelishuv: TTL davomida ma’lumot biroz eskirgan bo‘lishi mumkin. Ko‘p hollarda — joiz.
2 · Yozuvda invalidatsiya (write invalidation). Ma’lumot o‘zgarganda keshdagi kalitni darhol del qilasan (yuqoridagi update misolidagidek). Eng aniq, lekin har o‘zgarish joyida keshni o‘chirishni eslab turish kerak.
3 · Hodisaga asoslangan invalidatsiya. O‘zgarishda event chiqadi, keshga bog‘liq joylar o‘zini tozalaydi — bo‘shroq bog‘langan:
// Hodisaga asoslangan invalidatsiya (3-mavzu bilan bog'lanadi)
// Mahsulot o'zgarganda event chiqadi -> keshlar o'zini tozalaydi
@OnEvent('product.updated')
async onProductUpdated(e: ProductUpdated) {
await this.cache.del(`product:${e.id}`);
await this.cache.del('products_all'); // bog'liq ro'yxat keshini ham
}
Mukammal izchillik kerak bo‘lsa — TTL’ni qisqa qil yoki yozuvda invalidatsiya qil. Biroz eskirish joiz bo‘lsa — uzunroq TTL ishlat. Aniq izchillik va tezlik o‘rtasidagi kelishuvni biznes ehtiyoji hal qiladi.
Klassik muammolar va eviction
stampede · avalanche · penetrationKeshda 3 ta klassik muammo bor — ularni bilmaslik tizimni yiqitishi mumkin:
1 · Cache Stampede (thundering herd)
Mashhur kalit keshdan o‘chdi (TTL tugadi). Ayni o‘sha lahzada minglab so‘rov birato‘la miss bo‘lib, hammasi bazaga yuguradi — baza to‘fondan cho‘kadi.
Yechim (qisqacha): faqat bitta so‘rov bazaga borib keshni to‘ldirsin (lock / "single-flight"), qolganlar kutsin; yoki muddat tugashidan oldin fonda yangilash. (Chuqur mexanika — Deep qatlamda.)
2 · Cache Avalanche (qor ko‘chkisi)
Ko‘p kalitga bir xil TTL berilgan → hammasi bir vaqtda tugaydi → bir zumda ulkan miss to‘lqini. Yechim: TTL’ga tasodifiy qo‘shimcha (jitter) ber: 60s + random(0..10s) — muddatlar tarqaladi.
3 · Cache Penetration (teshib o‘tish)
So‘rovlar umuman mavjud bo‘lmagan kalitga tushadi (masalan, product:-1). Kesh doim miss, har safar baza benihoya so‘raladi (hatto buzg‘unchi shu orqali bazani yuklashi mumkin). Yechim: "yo‘q" natijani ham qisqa TTL bilan keshla (negative caching).
Eviction — kesh to‘lganda nima o‘chadi
Kesh xotirasi cheksiz emas. To‘lganda eskilarini chiqarib tashlaydi (eviction). Asosiy siyosatlar: LRU (eng kam yaqinda ishlatilgani), LFU (eng kam tez-tez ishlatilgani), TTL (muddati bo‘yicha). Redis’da bu maxmemory-policy bilan sozlanadi.
Nimani keshlash va qachon ishlatmaslik
Kesh kuchli, lekin har joyda emas. Noto‘g‘ri ishlatilsa — eskirgan ma’lumot va topish qiyin xatolar keltiradi.
Keshlash YAXSHI bo‘lganda
- Ma’lumot ko‘p o‘qiladi, kam o‘zgaradi
- Biroz eskirish joiz (lenta, katalog, profil)
- Hisoblash yoki so‘rov qimmat (og‘ir JOIN, agregatsiya)
- Bir xil natija qayta-qayta so‘raladi (mashhur kalitlar)
EHTIYOT bo‘ling / keshlamang
- Ma’lumot har soniyada o‘zgaradi (real-time narx)
- Mutlaq aniqlik shart (hisob qoldig‘i, to‘lov)
- Har foydalanuvchi uchun noyob, qayta so‘ralmaydigan
- Yozuv o‘qishdan ko‘p (kesh foyda bermaydi)
1. Avval o‘lchang — qaysi so‘rov sekin/ko‘p? Faqat o‘shani keshlang, hammasini emas.
2. Hit rateni kuzating. Past hit rate = kesh foyda bermayapti, balki noto‘g‘ri kalit yoki juda qisqa TTL.
3. Kalit nomlanishini izchil qiling: product:42, user:7:orders — versiyalash oson bo‘lsin.
4. Kesh ishonchlilik manbai emas — u o‘chsa, tizim (sekinroq bo‘lsa-da) ishlashda davom etishi kerak. Keshga "majburiy" tayanmang.
Eslab qolish kerak bo‘lgan 5 jumla
- Kesh = tez-tez o‘qiladigan ma’lumotni tez xotirada saqlash. HIT (~1ms) bazaga bormaydi; MISS bazadan olib keshga yozadi.
- Eng ko‘p ishlatiladigan naqsh — Cache-Aside + TTL. Shundan boshla; write-through/behind keyin kerak bo‘lsa.
- Invalidatsiya — eng qiyin qism. TTL (oddiy), yozuvda
del(aniq), yoki hodisaga asoslangan. Tezlik va izchillik orasidagi kelishuv. - 3 ta tuzoq: stampede (lock/single-flight), avalanche (TTL jitter), penetration (negative caching). Kesh to‘lsa — LRU/LFU eviction.
- Faqat ko‘p o‘qiladigan, kam o‘zgaradigan, eskirishi joiz ma’lumotni keshla. O‘lchab keshla, hit rate kuzat, keshga majburiy tayanma.
Bu mavzuning Deep/Senior qatlami kerak bo‘lsa (Redis ichki tuzilishi, stampede’ga lock/probabilistic early expiration, multi-level cache, consistent hashing, cache warming) — ayting, qo‘shaman.
Yoki keyingi mavzu: “5-mavzu: Load Balancing” — masshtablashning ikkinchi quroli.