Cache Stampede — bu, bir çox klient və ya axın eyni anda keş boşluğu aşkar etdikdə məlumat mənbəyinə sorğuların selvari artımıdır. Mobil tətbiqlərdə Cache Stampede populyar keş yazısı müddəti bitdikdə və yüzlərlə cihaz eyni anda məlumatı yenidən yükləməyə çalışaraq serverin həddindən artıq yüklənməsinə səbəb olduqda baş verir. Medium Engineering (2024) tədqiqatına görə, Cache Stampede-dən düzgün konfiqurasiya edilmiş qorunma serverin pik yükünü 95% azaldır.
Əsas Məqamlar
Cache Stampede (həmçinin cache thundering herd kimi tanınır) — bu, çox sayda sorğunun eyni anda keş boşluğu aşkar edərək məlumat mənbəyinə yönəlməsi vəziyyətidir. Bu, sistemin deqradasiyasına və ya tam sıradan çıxmasına səbəb ola biləcək pik yük yaradır.
Tipik ssenari: mobil tətbiq ümumi məhsul siyahısını TTL = 5 dəqiqə ilə keşləyir. Saat 14:00-da keş müddəti bitir. 500 aktiv istifadəçi eyni anda kataloqu açır, hər biri boş keş aşkar edir və bütün 500 sorğu serverə göndərilir. Məlumat bazası və ya xarici API qəfil axının öhdəsindən gələ bilmir, səhifə 10-15 saniyə yüklənir, sorğuların bir hissəsi timeouta düşür.
Vattani et al. (SOCC, 2015) məlumatlarına görə, Cache Stampede müddəti bitən yazıları olan istənilən keşləmə qatında baş verir, o cümlədən CDN, Redis, Memcached, brauzerin HTTP-keşi və tətbiqin yaddaşdaxili keşi. Yazı nə qədər populyardırsa, stampede-dən potensial zərər bir o qədər yüksəkdir.
def mutex_get(key, lock_timeout=5):
cached = cache.get(key)
if cached is not None:
return cached
if lock.acquire(key, lock_timeout):
data = source.load(key)
cache.set(key, data)
lock.release(key)
return data
sleep(0.01)
return mutex_get(key, lock_timeout)
Bu nümunə mutex vasitəsilə qorunmanı göstərir: yalnız birinci axın keşi yeniləyir, qalanları hazır nəticəni gözləyir. Bloklama mexanizmi — orta yüklər üçün stampede-nin qarşısını almağın ən sadə, lakin effektiv üsuludur.
Kütləvi TTL müddətinin bitməsi — Cache Stampede-nin əsas səbəbi. Populyar keş yazısı bütün klientlər üçün eyni TTL-ə malik olduqda, hamısı eyni anda onun olmadığını aşkar edir. Bu, ümumi məlumatlar üçün xarakterikdir: valyuta məzənnələri, ölkə siyahısı, tətbiqin əsas konfiqurasiyası.
Serverin yenidən başladılması zamanı kolaps — Redis və ya Memcached sıfırlanarsa, bütün keş boş olur. İlk trafik pikində bütün sorğular məlumat bazasına gedir. Amazon AWS Architecture Blog (2024) məlumatlarına görə, yenidən başlatmadan sonra keşin qızdırılması tövsiyə olunur: populyar yazıları tədricən yükləyərək kəskin yük artımının qarşısını almaq.
İnvalidasiya məntiqində səhv — tərtibatçı bir element dəyişdikdə bütün istifadəçilər üçün keşi təmizlədikdə baş verir. Məsələn, xəbər tətbiqində bir məqalə dərc edildikdə bütün xəbər siyahısı invalid edilir. Yüzlərlə istifadəçi eyni anda boş keş aşkar edir — və server çökür. Nöqtəvi invalidasiya (yalnız dəyişdirilmiş yazının) bu problemi aradan qaldırır.
Tətbiqin soyuq başlanğıcı — mobil cihazlarda keş yalnız prosesin yaddaşında mövcuddur. Tətbiq yenidən başladıqdan sonra keş boşdur və bütün sorğular serverə gedir. Həll yolu: seanslar arasında keşi diskdə saxlamaq (Room, SQLite) və başlanğıcda əsas məlumatların ilkin yüklənməsindən istifadə etmək.
Metodun ideyası — keş boşluğu aşkar edildikdə birinci axın bloklamanı (lock) ələ keçirir və mənbədən məlumat yükləməyə başlayır. Qalan axınlar bloklamanın bitməsini gözləyir və yenilənmiş keşi oxuyur. Bloklama Redis SETNX, ZooKeeper və ya hətta yaddaşdaxili mutex vasitəsilə həyata keçirilə bilər.
Əsas parametr — lock_timeout. Çox qısa olduqda, birinci axın keşi yeniləməyə vaxt tapmaya bilər və ikinci axın da məlumat yükləməyə cəhd edərək mini-stampede yaradar. Çox uzun olduqda, klientlər lazım olduğundan daha çox gözləyir. Tövsiyə olunan dəyər: tipik məlumat bazası sorğuları üçün 2-5 saniyə.
Tək axın problemi — birinci axının xətası (istisna, timeout) zamanı bloklama ələ keçirilmiş qalır və bütün digər axınlar lock_timeout-un bitməsini gözləyir. Həll yolu: bloklamanı finally blokunda silmək. Redis Best Practices (2025) məlumatlarına görə, bloklamaların atomik qurulması və buraxılması üçün Lua skriptlərindən istifadə tövsiyə olunur.
-- Atomic lock acquisition script for Redis
if redis.call("SET", KEYS[1], "locked", "NX", "EX", ARGV[1]) then
return true
else
return false
end
Bu Lua skripti atomik olaraq bloklamanı TTL ilə yoxlayır və qurur. Atomiklik iki eyni vaxtda sorğunun bloklama ala bilməməsini təmin edir — yalnız biri, bu da Cache Stampede-ni tamamilə qarşısını alır.
Probabilistic Early Expiration (PEE) — bloklamasız zərif metod. İdeya ondan ibarətdir ki, hər bir klient müəyyən ehtimalla keşi faktiki müddəti bitməzdən əvvəl yenidən hesablayır. Yazı müddətin bitməsinə nə qədər yaxındırsa, ehtimal bir o qədər yüksəkdir. Bu, yenidən yükləmələri təbii olaraq zamanda paylayır və pik yük hamarlanır.
XFetch alqoritmi — Vattani, Chierichetti və Panconesi (2015) tərəfindən təklif edilmişdir. Ehtimal düsturu: p = max(0, 1 - (beta * age / ttl)), burada beta — qeyri-bərabərlik parametridir (adətən 1.0). age = 0 olduqda → p = 1 (sıfır yaşda zəmanətli yeniləmə, bu düzgün deyil). Buna görə modifikasiyadan istifadə olunur: p = max(0, (ttl - age) / (ttl * beta)).
Etsy Engineering (2024) məlumatlarına görə, Memcached-də XFetch-in tətbiqi stampede hadisələrinin sayını gündə 12-dən 0-a endirdi, məlumat bazasına pik yük isə 78% azaldı. Randomizə edilmiş yeniləmə bloklama və sinxronizasiya tələb etmir, bu da XFetch-i mikroservis arxitekturası üçün ideal edir.
Mobil klientlər üçün PEE tətbiq tərəfində tətbiq oluna bilər: klientlər təsadüfi olaraq keş rəsmi olaraq müddəti bitməzdən əvvəl yeniləməyə başlayır. Məsələn, age > 80% TTL olduqda hər sorğu 20% ehtimalla məlumatları yeniləyir. Paylanmış mobil cihazlar sinxron zərbə ehtimalını əlavə olaraq azaldan təbii səs-küy yaradır.
Yanaşmanın ideyası — keş müddəti bitməzdən əvvəl yeniləmək, boşluğu tamamilə aradan qaldırmaq. Fon prosesi (cron, Kubernetes-də scheduler) vaxtaşırı populyar açarları yoxlayır və onları yeni TTL ilə yenidən yazır. Klientlər həmişə keşi etibarlı tapır — stampede tərifinə görə qeyri-mümkündür.
Time-To-Refresh (TTR) — müddət bitməsinə nə qədər qalmış yeniləməyə başlamağı müəyyən edən parametr. Məsələn, TTL = 300 saniyə, TTR = 60 saniyə: 240 saniyə işarəsində fon prosesi məlumatları yenidən yazır. Bu, klientlərin heç vaxt boş keş görməməsinə zəmanət verir.
Öncədən yeniləmənin mənfi cəhəti — daimi yük məlumat mənbəyinə, heç kim yazını tələb etməsə belə. Az istifadə olunan məlumatlar üçün bu səmərəsizdir. Həll yolu: açarın sorğu tezliyini (access frequency) izləmək və yalnız populyar yazıları yeniləmək. Adaptiv TTR — yeniləmə intervalının sorğu tarixçəsi əsasında dinamik hesablandığı qabaqcıl texnikadır.
Mutex bloklaması — orta yükü olan sistemlər üçün uyğundur (açar başına 10 000 rps-ə qədər). Tətbiqi sadədir və mənbəyin yalnız bir yeniləmə sorğusu almasını təmin edir. Minus — bloklamalar gözləyən axınlar üçün gecikmə yaradır.
Probabilistic Early Expiration / XFetch — yüksək yüklər və paylanmış sistemlər üçün optimaldır. Bloklama tələb etmir, üfüqi miqyaslanır, pik yük təbii şəkildə hamarlanır. Minlərlə klienti olan Redis-klasterləri və Memcached üçün tövsiyə olunur.
Öncədən yeniləmə — proqnozlaşdırıla bilən giriş nümunəsi olan kritik məlumatlar üçün idealdır (konfiqurasiyalar, arayış kitabçaları, əsas metadata). Fon prosesi üçün əlavə infrastruktur tələb edir.
Disk keşi klientdə — mobil tətbiqlər üçün ən vacib qorunma səviyyəsidir. Server keşi invalid edilsə belə, mobil klient yeni sorğu icra olunarkən diskdən məlumat göstərə bilər. Room + Stale-While-Revalidate — Google (2025) tərəfindən tövsiyə olunan nümunədir və klient tərəfdə Cache Stampede-ni tamamilə aradan qaldırır.
Tez-tez verilən suallar
Cache Stampede — eyni anda boş keş aşkar edən qanuni klientlərin normal davranışının nəticəsidir. DDoS — qəsdən hücumdur. Stampede üçün qoruyucu alqoritmlər kifayətdir; DDoS üçün əlavə trafik filtrasiya infrastrukturu tələb olunur.
Məlumat mənbəyində RPS qrafiklərini (məlumat bazası, API) izləyin. Keş müddətinin bitmə anı ilə sinxronlaşan müntəzəm yük pikləri görürsünüzsə — bu Cache Stampede-dir. Hər populyar açar üçün cache miss rate metrikasını əlavə edin.
Bəli, tətbiqdə bir neçə axın ümumi yaddaşdaxili keşdən istifadə edərsə. Məsələn, 10 korutin eyni anda istifadəçi profilini tələb edir — birincisi bloklayır, qalan 9-u sorğunu təkrarlaya bilər. Kotlin kitabxanası kotlinx.coroutines bunu CoroutineCache və ya Flow.distinctUntilChanged vasitəsilə həll edir.
beta = 1.0 — bərabər paylanma verən standart dəyər. Daha aqressiv qorunma üçün (az qaçırma ehtimalı) beta-nı 1.5-2.0-ə qədər artırın. Mənbə resurslarına qənaət etmək üçün — 0.5-ə qədər azaldın. Tövsiyə olunan diapazon: 0.8-1.2.
Bəli, Cache-Control: stale-while-revalidate və Cache-Control: stale-if-error mexanizmi vasitəsilə. CDN köhnəlmiş versiyanı qaytarır və fonda keşi yeniləyir, bu da PEE-nin CDN analoqudur. Cloudflare və Fastly bu direktivləri 2023-cü ildən dəstəkləyir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun