GH GambleHub

Архітектура кешування: Redis, Memcached

Архітектура кешування: Redis, Memcached

1) Коли і навіщо кеш

Цілі: знизити латентність, розвантажити БД/PSP/зовнішні API і пом'якшити піки.
Шари кешів часто багаторівневі: in-process (L1) → service-level (Redis/Memcached L2) → edge/CDN. Внутрішній кеш прискорює «гарячі» читання, L2 - загальний для сервісів, edge - для публічного контенту.

2) Redis vs Memcached - коротко

КритерійRedisMemcached
Типи данихРядки, хеші, списки, множини, zset, бітмапи, HyperLogLog, Streams, Bloom/CF (через модулі)Ключ-значення (рядки)
ПерсистентністьAOF/RDB, no-fsync-loss при налаштуванніНі, ні
КластерRedis Cluster (шардинг, failover )/SentinelКлієнтський шард, без нативного failover
Транзакції/скриптиMULTI/EXEC, EVAL (Lua), атомарні операціїНі, ні
TTL/evictionТонке налаштування політикБазові
Латентність/пам'ятьТрохи більше overheadДуже легкий, передбачуваний

Правило: якщо потрібні складні структури даних, персистентність, pub/sub/стріми/скрипти - беріть Redis. Якщо супер-проста, швидка, дешева KV-кеш-прошарок без durability - Memcached.

3) Шаблони кешування

3. 1 Cache-aside (lazy)

Додаток читає з кешу → промах → читає з БД → кладе в кеш з TTL.

Простий контроль TTL, незалежність від кешу. − Можливий «шторм» при промахах.

3. 2 Read-through

Клієнт/проксі сам підтягує з origin при промаху і кладе в кеш.

Централізована логіка. − Складніше інфраструктурно.

3. 3 Write-through / Write-behind

Write-through: запис спочатку в кеш, потім в БД.
Write-behind: запис в чергу, асинхронний флаш в БД (потенційна втрата при краше - потрібен журнал).

3. 4 Two-tier (L1+L2)

L1 (in-process) c коротким TTL і soft TTL, L2 (Redis/Memcached) - «істина кеша». Інвалідація через pub/sub.

4) TTL, шторми і консистентність

TTL: задавайте близько до частоти зміни даних. Для гарячих ключів використовуйте рандомізацію TTL (jitter): `ttl = base ± rand(0..base0. 1)'- знімає синхронні закінчення.

Dogpile (thundering herd): захистіть промахи:
  • Singleflight: тільки один процес перегенерує значення (див. приклад Lua).
  • Soft-TTL + background refresh: після'soft _ ttl'віддавайте застаріле (stale) і оновлюйте тлом.
  • Semaphore/lock: `SET key:lock value NX PX=2000`.
  • Near-stale: 'stale-while-revalidate'для API відповідей (див. розділ 8).

5) Ключі, неймспейси, серіалізація

5. 1 Іменування ключів

Шаблон: `{domain}:{entity}:{id}:{field}`

Приклади:
  • `user:profile:42` `catalog:product:1001:v2` `psp:rates:2025-11-03`

Додавайте версію схеми (':v2') - це полегшує масову інвалідацію.

5. 2 Неймспейси через «версію простору»

Тримайте ключ'ns:catalog = 17`. Реальні ключі: `catalog:17:product:1001`. Для глобальної інвалідації каталогу просто інкрементуйте'ns:catalog`.

5. 3 Серіалізація/компресія

JSON - зручний, але важкий. Використовуйте MessagePack/CBOR.
Включайте компресію (LZ4/ZSTD) для великих payload (> 1-2 KB). У Redis - на стороні клієнта.

6) Гарячі ключі та шардування

Hot-keys: моніторьте top-N по hit/miss/byte. Для екстремально гарячих ключів:
  • Replicated read pattern: дублюйте значення в кілька shard-ключів'hot:k:1. N', вибирайте випадковий при читанні.
  • Local L1: тримайте в пам'яті процесу з підпискою на інвалідацію.
Шардування:
  • Redis Cluster - нативно (16384 hash-слотів).
  • Memcached - клієнтський консистентний хеш.
  • Hash-tag в Redis'{...}'фіксує слот для набору ключів: `user:{42}:profile` и `user:{42}:limits'опиняться на одному шарді.

7) Політики витіснення і розміри

Redis `maxmemory-policy`: `allkeys-lru`, `volatile-lru`, `allkeys-lfu`, `noeviction` и т. д. Для кешу зазвичай'allkeys-lru '/' allkeys-lfu'.
Memcached — LRU на item-slab.
Розмір ключа і value: слідкуйте за max item size (Memcached за замовчуванням 1 МБ, тюнінг slab).
Перевищення пам'яті повинно деградувати передбачувано: не'noeviction'на активному шляху.

Redis конфіг (фрагмент):

maxmemory 32gb maxmemory-policy allkeys-lfu hz 50 tcp-keepalive 60

8) Патерни захисту від штормів - код

8. 1 Redis Lua singleflight (псевдо)

lua
-- KEYS[1] = data_key, KEYS[2] = lock_key
-- ARGV[1] = now_ms, ARGV[2] = soft_ttl_ms, ARGV[3] = hard_ttl_ms, ARGV[4] = lock_ttl_ms local payload = redis. call("GET", KEYS[1])
if payload then local meta = redis. call("HGETALL", KEYS[1].. ":meta")
local last = tonumber(meta[2] or "0")
if tonumber(ARGV[1]) - last < tonumber(ARGV[2]) then return { "HIT", payload }
end if redis. call ("SET," KEYS [2], "1," "NX," "PX," ARGV [4]) then return {"REFRESH," payload} - one worker updates, the rest give stale end return {"STALE," payload}
end if redis. call("SET", KEYS[2], "1", "NX", "PX", ARGV[4]) then return { "MISS", nil }
end return { "BUSY", nil }

8. 2 Node. js cache-aside (спрощено)

js const v = await redis. get(key);
if (v) return decode(v);
const lock = await redis. setNX(key+":lock", "1", { PX: 1500 });
if (lock) {
const fresh = await loadFromDB(id);
await redis. set(key, encode(fresh), { EX: ttl, NX: false });
await redis. del(key+":lock");
return fresh;
} else {
await sleep(60);           // short backoff const retry = await redis. get (key) ;//give someone's already filled return decode (retry);
}

9) Інвалідація та узгодженість

За подією: при зміні в БД публікуйте'pub/sub'подія'invalidate:{ns}:{id}'→ передплатники видаляють ключі.
За таймером: короткий TTL для часто мінливих даних.
Версіонування: див. "ns:'ключі.
Outbox: гарантія доставки інвалідації (подія в лог/топік, ретраї).
Ідемпотентність операцій з кешем: використовуйте'SETXX/SETNX', версії ('etag') і хеш-поля для інкременту.

10) Реплікація, кластер, failover

10. 1 Redis

Sentinel: автоматичний failover master-replica (стейтFUL IP/ім'я).
Cluster: шардування + автоматичний failover; клієнти повинні підтримувати редиректи'MOVED/ASK'.
AOF/RDB: для кешу зазвичай'appendfsync everysec', можна без персистентності (як чистий кеш).

10. 2 Memcached

Немає реплікації з коробки. Надійність - через багатосерверний шард + повтор'n'( client-side).
При падінні ноди - зростання промахів і «переучування» кешу.

10. 3 K8s та мережеві аспекти

Redis/Memcached не люблять часту пересоздачу pod'ів; використовуйте StatefulSet + антиподи по AZ, фіксовані PVC/POD IP.
Ставте PodDisruptionBudget і TopologySpreadConstraints.

11) Транзакції, скрипти та атомарність (Redis)

INCR/DECR, HINCRBY - лічильники, квоти, rate-limits (тільки враховуйте persist).
MULTI/EXEC - пачка атомарних команд.
Lua (EVAL) - read-modify-write без гонок.
Pipeline - зменшує RTT (особливо при мережевому хопі).

Приклад rate-limit (token bucket, спрощено):
lua
-- KEYS[1]=bucket, ARGV[1]=capacity, ARGV[2]=refill_rate_per_sec, ARGV[3]=now_ms
-- Returns 1 if the token is issued, otherwise 0

12) Черги, pub/sub і Streams (Redis)

Pub/Sub: Інвалідація, сигнали. Без збереження, тільки онлайн-слухачі.
Streams: черги подій з підтвердженням (ACK), групи споживачів, ретраї - зручно для write-behind/фан-аутів.
Lists (`BRPOP`): Прості черги.
Не використовуйте Redis як «єдину шину всього» без бекапа - це кеш/швидка шина, не Kafka.

13) Безпека та доступ

Ізоляція мереж/VPC, mTLS на ingress-рівні, ACL/паролі ('requirepass '/ACL в Redis 6 +).
Disable dangerous команд в Redis ('CONFIG','FLUSHALL','KEYS') через ACL.
Для Memcached - не слухати публічні інтерфейси,'-U 0'( без UDP), тільки приватні мережі.
PII не зберігати; якщо потрібно - короткий TTL + шифрування на рівні програми.

14) Спостережуваність і обслуговування

Ключові метрики:
  • Hit ratio/Miss ratio (за namespace/маршрутом).
  • Latency p95/p99 команд'GET/SET/MGET', timeouts.
  • Evictions и OOM errors.
  • Replication lag (Redis), cluster state, migrate/rehash events.
  • Top-N keys за трафіком/байтами (семплінгом).
  • Логи: повільні команди («slowlog»), помилки мережі.
  • Дашборди: загальне (CPU/RAM/connections), команди, слоти кластера, sentinels, пропускаючи через Prometheus-експортери.

15) Конфіги і розгортання - приклади

15. 1 Redis Sentinel (фрагмент)


port 6379 protected-mode yes appendonly yes appendfsync everysec maxmemory-policy allkeys-lfu
`sentinel. conf`:

sentinel monitor m1 10. 0. 0. 11 6379 2 sentinel auth-pass m1 sentinel down-after-milliseconds m1 5000 sentinel failover-timeout m1 60000

15. 2 Redis Cluster (helm values, спрощено)

yaml cluster:
enabled: true nodes: 6  # 3 masters + 3 replicas persistence:
size: 100Gi resources:
requests: { cpu: "500m", memory: "2Gi" }

15. 3 Memcached (deployment)

yaml containers:
- image: memcached:1. 6 args: ["-m", "32768", "-I", "2m", "-v", "-t", "8", "-o", "modern"]
ports: [{ containerPort: 11211 }]

15. 4 NGINX як read-through проксі (контур API)

nginx proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api:100m max_size=10g inactive=10m;
map $request_uri $cache_key { default "api:$request_uri"; }
location /api/ {
proxy_cache api;
proxy_cache_valid 200 1m;
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
proxy_cache_lock on;      # singleflight на уровне NGINX proxy_cache_key $cache_key;
proxy_pass http://backend;
}

16) Тестування та гейти

Навантажувальні профілі «холодний/теплий/гарячий кеш».
Ін'єкція промахів (purge масово) - origin повинен витримати «переучування».
Алерти: різке падіння hit-ratio, зростання miss latency, лавина evictions, зростання timeouts.

17) Анти-патерни

Зберігати «істину» в Redis без AOF/RDB і без резервування.
TTL = 0 (безстроково) для волатильних даних → вічна неконсистентність.
Масовий «KEYS» в проді.
Відсутність jitter/soft-TTL → синхронні витікання і шторму.
Один інстанс на всі команди без шардування/реплік.
Використовувати Memcached для завдань, що вимагають атомарності/скриптів.

18) Чек-лист впровадження (0-45 днів)

0-10 днів

Вибрати шаблон (cache-aside + L1/L2), описати ключі, TTL, неймспейси.
Увімкнути jitter/soft-TTL, singleflight; базові алерти/дашборди.
Для Redis - налаштувати ACL, protected-mode, slowlog, maxmemory-policy.

11-25 днів

Перейти на шардування (Redis Cluster або клієнтський хеш), репліки.
Інвалідація через pub/sub або версію неймспейсу; outbox в БД.
Навантажувальні тести «переучування» кешу; limiting origin.

26-45 днів

Автопромо/канарські TTL, прогрівши перед релізом.
Streams для write-behind/фонових перегородок.
Щотижневі звіти по hit-ratio, топ-ключам, вартості пам'яті.

19) Метрики зрілості

Hit-ratio L2 ≥ 80% (статистика по маршрутах/неймспейсам).
P95 GET <2-3 ms (in-DC), промахи <SLO origin.
0 шторму при масовій інвалідації (доведено тестами).
Автоматична інвалідація та версіонування неймспейсів.
Шардування/реплікація покривають відмову 1 вузла без помітної деградації.

20) Висновок

Сильна архітектура кеша - це дисципліна ключів і TTL, захист від шторму, правильне шардування і передбачуване витіснення. Redis дає багату семантику, персистентність і атомарність; Memcached - максимум простоти і швидкості. Додайте спостережуваність, інвалідацію по подіям, L1 + L2, і кеш стане прискорювачем платформи, а не джерелом випадкових падінь і «містичних» багів.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.