Технології та Інфраструктура → Кеш-рівні та зберігання даних
Кеш-рівні та зберігання даних
1) Навіщо потрібен багатошаровий кеш
Кеш - це короткий шлях до відповіді без походу в «дорогі» підсистеми (БД, зовнішні API, мережі). Багатошаровість розподіляє навантаження: браузер → CDN/edge → прикладний шар → розподілений кеш → БД/сховище. Цілі: знизити P95/P99, розвантажити origin, міцніше витримувати піки і здешевити байт.
2) Карта рівнів кеша
1. Браузер: `Cache-Control`, `ETag`, `Last-Modified`, `stale-while-revalidate`.
2. CDN/Edge: TTL/ключ, Vary, Signed URLs, image-resize; tiered/shield.
3. API Gateway/Service Mesh: короткоживучий кеш по безпечним GET.
4. Додаток (in-process): LRU/LFU, near-cache для «гарячих» ключів, мілісекунди.
5. Розподілений кеш (Redis/Memcached): основний шар для динаміки.
6. Кеші БД: Pg/Innodb буферы, PgBouncer multiplexing, materialized views.
7. Дискові/об'єктні стори: precomputed snapshots, blob-кеш (наприклад, S3 + CDN).
Принцип: "чим ближче до користувача - тим коротше TTL і менше персоналізації; чим ближче до даних - тим багатша політика консистентності".
3) Патерни кешування
Cache-Aside (Lazy): читаємо → при MISS вантажимо з джерела → кладемо в кеш. Простий, дає контроль TTL.
Read-Through: додаток читає через кеш, який сам тягне з джерела. Зручно централізувати політику.
Write-Through: запис йде в кеш і в джерело відразу. Консистентніше, але дорожче за записом.
Write-Back (Write-Behind): пишемо в кеш, джерело оновлюється асинхронно (черга). Висока швидкість, потрібні гарантії доставки та ідемпотентність.
Refresh-Ahead: у «топових» ключів оновлюємо значення до закінчення TTL.
Де що: картки ігор/каталоги - cache-aside/read-through; лічильники/лідерборди - write-back + CRDT/агрегації; довідники валют/лімітів - read-through з контрольованим TTL.
4) Ключі, сегментація та неймінг
Шаблон: `domain:entity:{id}:v{schema}|region={R}|currency={C}|lang={L}`.
Включайте в ключ тільки те, що реально змінює відповідь (регіон, валюта, мова, версія схеми).
Версіонування схем: при несумісних змінах - підвищуйте'vN'в ключі, уникаючи масових purge.
Namespacing по продуктам/тенантам: `tenant:{t}:...'- критично для multi-tenant.
Bloom-фільтр на «існування ключа» може знизити походи в джерело.
5) TTL, свіжість та інвалідація
TTL-матриця:- статика (хешовані файли): 30-365 днів +'immutable';
- каталоги/банери: 5-60 хвилин +'stale-while-revalidate';
- лідерборди/котирування: 2-15 секунд;
- довідники (валюти/ліміти): 1-10 хвилин.
- Інвалідація подіями: публікуємо'product. updated'→ інвалідація точкового ключа/префікса.
- Tag-based purge: групові очищення за тегами (реліз промо/каталогу).
- Soft-Expiry: після закінчення TTL віддаємо застаріле як «stale», паралельно оновлюємо (SWR/SIE).
- Versioned Keys> масовий purge: дешевше і безпечніше.
6) Stampede, «гарячі» ключі і конкуренція
Dogpile/Stampede захист:- Single-flight (request coalescing): один лідер оновлює ключ, інші чекають.
- TTL джиттер: розмиваємо витікання, уникаючи одномоментного обвалу.
- SWR локально: прострочене значення віддаємо користувачеві, в тлі оновлюємо.
- реплікація «гарячого» ключа в кілька слотів'key # 1.. N', розподілений читанням;
- near-cache в пам'яті процесу;
- prewarm/refresh-ahead перед піками (турніри/матчі).
- Ліміти на конкарренсі оновлення для важких ключів.
7) Консистентність і крос-шари
Write-invalidate: при записі в джерело - синхронно інвалідуйте відповідні ключі (pub/sub).
Read-repair: при розбіжностях оновлюйте кеш коректним значенням.
Eventual vs Strong: критичні грошові операції читаємо безпосередньо/з коротким TTL; UI-вітрини і статистика - eventual.
CRDT/агрегатори: для розподілених лічильників/рейтингів - структури «merge-safe» (G-Counter, Top-K на потоках).
Каскадна інвалідація: оновлення «гри» інвалідує картку + список + користувацький кеш рекомендацій.
8) Серіалізація, стиснення і формат
Формати: протобуф/MessagePack швидше JSON; для CDN/браузера - JSON з Brotli.
Компресія в Redis: вигідна для об'єктів> 1-2 КБ, але стежте за CPU.
Partial responses/поля на вимогу: менше байт → менше TTFB і RAM.
9) Політики витіснення і розмір
LRU (за замовчуванням) - безпечно; LFU - краще для «популярного» контенту.
Розмір ключів/значень: тримайте під контроль (метрики'avg value size','max').
Квоти по namespace/tenant, щоб один продукт не «з'їв» весь кеш.
10) Безпека та PII/PCI
Особисті/фінансові дані - не кешувати на CDN/edge і в загальних шарах; використовуйте токени/проекції.
Шифрування чутливих значень в Redis через client-side crypto (з обережністю до втрат TTL-контролю).
Строгі ACL і ізоляція мереж; фіксовані NAT/IP для egress до провайдерів.
11) Спостережуваність і SLO кеша
Метрики:- Hit Ratio (по шарах і префіксах), Origin Offload.
- TTFB/P95/P99 до/після кешу, Latency Redis.
- Evictions, OOM, keyspace hits/misses.
- Stampede rate (частка паралельних оновлень), refresh time.
- Stale served % и Freshness lag.
- Каталог ігор: Hit Ratio ≥ 85%, TTFB P95 ≤ 150 мс (edge).
- API-довідники: Revalidation-hit ≥ 60%, P95 ≤ 200 мс.
- Redis: P99 операція ≤ 5 мс, evictions не більше 1% на годину.
12) FinOps: Вартість кешу
$/GB-місяць RAM vs $/RPS origin: порахуйте точку окупності.
Offload и egress: CDN + Redis знижують вихідний трафік з регіоно-origin.
Image/WebP/AVIF і денормалізації дають найбільшу економію байт.
Лімітуйте «дорогі MISS»: аналітика «байти × MISS × регіон».
13) Приклади (фрагменти)
13. 1 Cache-Aside з single-flight (псевдокод)
python def get(key, ttl, loader):
val = redis. get(key)
if val: return val with single_flight (key): # only one updates val = redis. get (key) # double check if val: return val data = loader () # request to source redis. setex(key, ttl_with_jitter(ttl), serialize(data))
return data
13. 2 Публікація інвалідації за подією
json
{
"event": "game. updated",
"game_id": "g123",
"affected": ["catalog:list:region=TR", "game:card:g123:"]
}
Консьюмер підписаний на канал і робить'DEL '/' PUBLISH'відповідним ключам/тегам.
13. 3 Ключ з версією схеми і локаллю
game:card:v2:id=g123 region=BR currency=BRL lang=pt-BR
14) Чек-лист впровадження
1. Карта рівнів кешу і TTL-матриця (статик/напівстатик/API).
2. Неймінг ключів: домен, версія схеми, локаль/регіон/валюта, tenant.
3. Вибір патерна per-endpoint (aside/read-through/write-through/back).
4. SWR/SIE, single-flight і TTL-джиттер проти stampede.
5. Інвалідація подіями (pub/sub), tag-purge для груп.
6. Near-cache для «гарячих» ключів і prewarm перед піками.
7. Формати і компресія (protobuf/MsgPack, Brotli), контроль розміру.
8. Політики LRU/LFU, квоти на namespace/tenant.
9. SLO/метрики: hit ratio, latency, evictions, stale %, freshness lag.
10. Безпека: no-store для персонального, токенізація, мережа/ACL.
15) Анти-патерни
'no-cache'« про всяк випадок »і відмови від TTL - нульовий offload.
Ключ включає всі query/заголовки → вибух кардинальності.
Масові purge «всього CDN/Redis» при кожному релізі.
Відсутність захисту від stampede і одноразове закінчення «топ-ключів».
Єдиний загальний Redis без квот/ізоляції; «гарячий» tenant з'їдає весь кеш.
Кешування персональних відповідей на edge/CDN.
Немає телеметрії freshness/evictions → сліпе управління.
16) Контекст iGaming/фінтех: Практичні ноти
Лідерборди/рейтинги: TTL 2-10 с, aggregate-потоки + CRDT, SWR при збоях.
Каталог ігор/банери: CDN+Redis; ключ: регіон/валюта/мова; інвалідація за тегами "promo:update».
Платіжні статуси: без кешу на шляху запису; читання - короткий TTL (≤3 -5 с) або прямий запит.
KYC/AML відповіді: кешуйте non-PII деривативи (статуси), не зберігайте зображення/документи в Redis.
VIP-шлях: окремий namespace/пул Redis, пріоритетне обслуговування.
Підсумок
Сильна кеш-стратегія - це архітектура рівнів, правильні патерни оновлення, продумана TTL/інвалідація, стійкість до stampede, акуратні ключі і версії, а також спостережуваність і FinOps. Дотримуючись цих принципів, ви стабілізуєте хвости P95/P99, скоротите навантаження на джерела і отримаєте передбачувану вартість мілісекунди - саме там, де це найважливіше для продукту і бізнесу.