Asosiy kontentga o‘tish
Innovialabs

Kesh invalidatsiyasi strategiyalari: TTL, write-through, stampede

Chuqur4 daq

Qisqacha

Ko‘pchilik tizimlar uchun TTL’li cache-aside va har bir yozuvda kalitni o‘chirish mos keladi; issiq kalitlarni lock yoki single-flight bilan himoyalang, TTL’ga jitter qo‘shing va fonda yangilanayotganda eskirgan ma’lumotni bering.

Qisqacha javob

Mukammal invalidatsiya strategiyasi yo‘q — ma’lumotlar yangiligi, bazaga yuklama va murakkablik o‘rtasida murosa bor. Ko‘pchilik mahsulotlar uchun ishonchli standart variant:

  • cache-aside sxemasida o‘qish: keshni tekshiramiz, topilmasa bazadan olib, natijani saqlaymiz;
  • har bir kalitda sug‘urta sifatida TTL;
  • haqiqat manbasiga har bir yozuvdan keyin kalitni o‘chirish;
  • issiq kalitlarni stampede’dan himoya qilish.

Har bir ma’lumot turi uchun qanchalik eskirishi mumkinligini hal qilishdan boshlang. Mahsulot tavsifi bir daqiqa kechikishi mumkin, buyurtma rasmiylashtirishdagi balans yoki ombordagi qoldiq esa — yo‘q.

Yozish sxemalarini taqqoslash

SxemaQanday ishlaydiQayerda yaxshiRisklar
Cache-asideIlova keshni o‘qiydi, topilmasa to‘ldiradi, yozishda invalidatsiya qiladiO‘qish ustun bo‘lgan ko‘pchilik APIYozish va qayta to‘ldirish o‘rtasida poyga
Write-throughHar bir yozuv kesh va bazaga birga boradiYozilgandan so‘ng darhol o‘qiladigan ma’lumotlarSekinroq yozish, kesh kam o‘qiladigan narsalar bilan to‘ladi
Write-behindKeshga yozish, bazaga — asinxronJuda tez-tez yozuvlar, hisoblagichlarKesh bazaga yozishdan oldin tushib qolsa, ma’lumot yo‘qoladi

Write-behind eng xavflisi: kesh vaqtincha haqiqat manbasiga aylanadi. Undan oxirgi yozuvlarni yo‘qotish maqbul bo‘lgan yoki navbat ishonchli bo‘lgan joyda foydalaning.

TTL va hodisaga asoslangan invalidatsiya

TTL oddiy va o‘zini o‘zi tiklaydi: invalidatsiya qilishni unutsangiz ham, muddat tugagach ma’lumot to‘g‘ri bo‘ladi. Narxi — kafolatlangan eskirish oynasi va davriy keshga tushmaslik (miss).

Hodisaga asoslangan invalidatsiya ma’lumot o‘zgarganda kalitlarni o‘chiradi yoki yangilaydi: yozuvdan keyin darhol, xabarlar shinasi orqali yoki bazaning change data capture (CDC) orqali. Ma’lumot yangiroq, lekin yozuvga bog‘liq barcha kalitlarni bilish kerak, yo‘qolgan hodisa esa biror narsa tuzatmaguncha eskirgan ma’lumotni anglatadi.

Amalda ularni birlashtiradi: hodisalar yangilikni beradi, TTL o‘tkazib yuborilgan hodisalardan sug‘urtalaydi.

Amaliy qoidalar:

  • Yozishda kalitni qayta yozmang, o‘chiring. Keshni yangilayotgan ikki parallel yozuvchi unda eskiroq qiymatni qoldirishi mumkin.
  • Avval bazaga yozing, so‘ng kalitni o‘chiring.
  • O‘quvchi o‘chirilgandan keyin darhol eski qiymatni qaytarib qo‘yishi mumkin. Qisqa TTL, kechiktirilgan ikkinchi o‘chirish yoki versiyalangan kalitlar (product:42:v17) bu bo‘shliqni yopadi.
  • «Topilmadi» natijasini qisqa muddatga keshlang, shunda mavjud bo‘lmagan ID’lar uchun so‘rovlar bazaga urilmaydi.

Cache stampede va uni qanday to‘xtatish

Stampede mashhur kalit muddati tugaganda va yuzlab so‘rovlar bir vaqtda keshga tushmay, bir xil og‘ir so‘rovni bajarganda yuz beradi. Baza sekinlashadi, ko‘proq so‘rovlar taymautga tushadi va muammo o‘zini o‘zi kuchaytiradi.

Ishlaydigan usullar:

  • Lock yoki single-flight: qiymatni faqat bitta so‘rov qayta yig‘adi, qolganlari qisqa kutadi yoki eski qiymatni oladi.
  • TTL uchun jitter: muddatga tasodifiy tarqoqlik qo‘shing, shunda birga yaratilgan kalitlar birga tugamaydi.
  • Stale-while-revalidate: bitta fon vazifasi yangilayotgan paytda muddati o‘tgan qiymatni berishda davom eting.
  • Erta yangilash: issiq kalitlarni muddati tugashidan sal oldin yangilang — jadval bo‘yicha yoki o‘qishda ehtimollik asosida.
  • Deploy yoki kesh qayta ishga tushgandan keyin ma’lum issiq kalitlarni qizdirish.

Redis’da minimal lock:

def get_product(pid):
    key = f"product:{pid}"
    cached = redis.get(key)
    if cached:
        return json.loads(cached)

    if redis.set(f"lock:{key}", "1", nx=True, ex=10):
        try:
            product = db.load_product(pid)
            ttl = 300 + random.randint(0, 60)  # jitter
            redis.set(key, json.dumps(product), ex=ttl)
            return product
        finally:
            redis.delete(f"lock:{key}")

    time.sleep(0.05)
    cached = redis.get(key)
    return json.loads(cached) if cached else db.load_product(pid)

HTTP javoblari uchun xuddi shu g‘oya Cache-Control sarlavhasiga o‘rnatilgan: max-age=60, stale-while-revalidate=300 CDN va brauzerlarga yangi nusxa yuklanayotganda biroz eskirgan nusxani berishga imkon beradi.

Qanday tanlash kerak

  1. Ma’lumotlarni ruxsat etilgan eskirish bo‘yicha ajrating: soniyalar, daqiqalar, soatlar, hech qachon.
  2. Eskirishi mumkin bo‘lmagan ma’lumotlar (pul, rasmiylashtirishdagi qoldiq) bazadan o‘qiladi yoki u bilan solishtiriladi; kesh — faqat ishora.
  3. Qolganlari uchun — TTL va yozishda o‘chirish bilan cache-aside.
  4. Hodisalarni faqat TTL bo‘yicha eskirish foydalanuvchilarga sezilarli xalaqit beradigan joyda qo‘shing.
  5. Hit rate, miss paytidagi kechikish va bazaga yuklamani kuzating. Relizdan keyin hit rate’ning tushishi ko‘pincha kalit formati o‘zgarganini bildiradi.

Ko‘p beriladigan savollar

Odatda o‘chirish. Yangilash hamma joyda bir xil serializatsiya va amallar tartibini talab qiladi va parallel yozuvlardan keyin eski qiymatni qoldirishi mumkin. O‘chirish keyingi o‘qishga qiymatni haqiqat manbasidan yig‘ish imkonini beradi.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.