Files
han-app/architectory/arch-09-redis.md
T

206 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# arch-09. Контракт Redis
> Канонический контракт Redis для всех application VM.
> Реализация на конкретной VM — [`module-04-redis-vm1.md`](../VM1_app/documentation/module-04-redis-vm1.md) и [`module-04-redis-vm2.md`](../VM2_services/documentation/module-04-redis-vm2.md).
> Compose/сети — [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md). Env — [`arch-04-settings-and-content.md`](arch-04-settings-and-content.md). Метрики exporter — [`arch-07-observability.md`](arch-07-observability.md).
## Назначение
Документ фиксирует то, что **должно совпасть между ВМ1 и ВМ2**: Redis не source of truth, формат ключей, TTL, Lua governance, AOF/RDB, ACL/network, eviction и restore. Карты ключей DB0/DB1 и Redis Safety здесь не детализируются и не копируются в чужой репозиторий.
Этот контракт **нельзя** независимо кастомизировать так, чтобы Redis стал очередью, OTP store или единственной защитой от дублей.
## 1. Инварианты
Redis разделён по deployment/security boundary:
- Redis ВМ1: DB0 (`api-backend` idempotency/rate) и DB1 (realtime/coordination);
- Redis Safety ВМ2: отдельный instance для hot cache, rate limiting и optional worker wake-up;
- legacy DB2 ВМ1 существует только для test stub v1 до cutover и после него удаляется.
Redis не является бизнес-очередью, source of truth сообщений, sync tasks, audit, профилей или delivery checkpoint. Надёжные состояния остаются в managed PostgreSQL/S3. Потеря Redis может ухудшить сервис, но не должна создавать потерю подтверждённых сообщений либо дубль side effect.
OTP counters `api-backend` в Redis не хранит; они принадлежат Keycloak/SPI. `bitrix-sync` Redis не использует: `sync_queue`, leases и durable wake-up — PostgreSQL.
Logical DB — изоляция имён, не security boundary. ACL prefix и разные credentials обязательны.
## 2. Версия и topology
Redis 7.x, image закреплён по digest. На каждой VM одна нужная primary instance без replica/Sentinel в MVP. Клиенты используют connection pool, bounded timeouts и не выполняют опасные команды.
ВМ2 никогда не использует hostname Redis ВМ1 и наоборот.
## 3. Общие правила ключей
Формат: `han:{domain}:{purpose}:{hashed-or-public-id}:{version}`. Только ASCII lowercase separators. Public UUID допустим; IP, phone, email, token, text и filename — только HMAC/SHA-256 с server-side pepper там, где нужна защита dictionary attack.
- key length желательно ≤ 200 bytes;
- значения versioned (`v=1`);
- timestamps — Unix ms/seconds или RFC3339, формат фиксирован для каждого key;
- wildcard `KEYS` production запрещён; только `SCAN` для ops;
- каждый non-channel key имеет TTL, кроме явно обоснованных bounded structures;
- large payload/presigned URL/token/message text запрещены.
Новый key без TTL запрещён contract test, кроме Pub/Sub channel (не key) и ops metadata с явным обоснованием.
## 4. Serialization и limits
- простые counters — integer;
- locks — opaque random 128-bit token;
- metadata — Redis HASH либо компактный JSON с `schema_version`;
- max value target 32 KiB, hard application guard 128 KiB;
- response cache хранит только allow-listed sanitized JSON;
- decode error считается cache miss, key удаляется/карантинируется и поднимается metric.
## 5. TTL policy — реестр
| Категория | TTL | Владелец |
|---|---|---|
| idempotency completed | 24h по arch-02 | ВМ1 |
| idempotency in-progress lock | 30s, heartbeat bounded | ВМ1 |
| rate limit | window + 1030% deterministic jitter | ВМ1 / ВМ2 по своим зонам |
| realtime connection | 90s; set membership 120s | ВМ1 |
| coordination lock | 30s | ВМ1 |
| safety file hot cache | ≤30d; authoritative row/version в PostgreSQL | ВМ2 |
| safety text-rules cache | 48h; invalidation by rules version | ВМ2 |
| safety stable link policy cache | 48h | ВМ2 |
| safety DNS cache | actual DNS TTL, hard max 900s | ВМ2 |
## 6. Atomicity и Lua governance
Scripts/functions хранятся в репозитории рядом с клиентом, versioned и тестируются на real Redis. Запрещены unbounded loops/SCAN внутри Lua. Входные массивы ограничены. Script timeout отслеживается; `SCRIPT KILL` runbook применяется только если нет writes либо после оценки.
Clock в rate/limit scripts — Redis `TIME`, не client wall clock. Script загружается при startup, SHA кэшируется; после `NOSCRIPT` выполняется контролируемый reload.
Redis transaction не координирует PostgreSQL/S3/HTTP. Cross-system consistency обеспечивается DB checkpoint/outbox и idempotent finalize.
Карта обязательных scripts — в спецификации VM.
## 7. Persistence
Решение MVP: AOF `appendonly yes`, `appendfsync everysec` плюс RDB snapshots (`save 900 1`, `300 100`, `60 10000` либо tuned). Это ускоряет восстановление ephemeral state, но не превращает Redis в authoritative store.
`aof-use-rdb-preamble yes`, automatic rewrite с порогами; volume `redis-data`. При corruption используется `redis-check-aof`/restore clean instance, а сервисы восстанавливают authoritative state из PostgreSQL.
RPO Redis до ~1 секунды приемлем, потому что бизнес-RPO задаётся PostgreSQL/S3. Backup Redis не обязателен для бизнес-восстановления, но периодическая копия RDB/AOF полезна для ops forensic без secrets.
## 8. Memory и eviction
`maxmemory` задаётся относительно container limit (ориентир 7075%, оставляя overhead/fork). Начальная оценка для одной VM — 512 MiB, уточняется load test.
Eviction MVP: `volatile-lru`/`volatile-ttl`, так как все application keys имеют TTL. `allkeys-lru` опасен для idempotency при memory pressure; `noeviction` может полностью закрыть writes. Окончательный выбор после нагрузки: предпочтительно `volatile-lru` + alerts, а при разделении instances DB0 idempotency получает отдельную noeviction policy.
Контролируются `used_memory`, RSS, fragmentation, evicted_keys, expired_keys, key count/avg TTL по DB. OOM/eviction не должен создавать дубль бизнес-эффекта: это гарантирует PostgreSQL fallback, не Redis.
## 9. Sizing
Общая формула:
```text
instance working set × 1.5 allocator/fragmentation × 1.3 growth reserve
```
Состав working set считает спецификация VM. Pub/Sub output buffers и slow consumers имеют hard/soft limits. Load test фиксирует peak RPS, connections, record size и AOF rewrite headroom.
## 10. Auth, ACL и network boundary
Оба Redis не публикуют `6379` на host и подключены только к local Docker `backend` своей VM. `protected-mode yes`, default user отключён.
ACL users (имена общие, credentials разные на каждой VM):
- application user — только свои key prefixes и command categories;
- `ops_health`: `PING`, ограниченный `INFO`;
- `redis_exporter` — только `INFO`/`PING` и безопасные latency/keyspace metrics (arch-07 §8.3).
Redis ACL не ограничивает logical DB напрямую надёжно; key-prefix patterns и разные credentials обязательны. `SELECT` запрещается, клиент URL сразу задаёт DB, но ACL prefix остаётся основной защитой.
Dangerous/admin commands (`FLUSHALL`, `FLUSHDB`, `CONFIG`, `MODULE`, broad `KEYS`, replication changes) запрещены application users; rename-command не считается основной защитой.
Пароли сильные, только env/secret mount, rotation current/new через rolling deploy. Внутри одной VM TLS Redis опционален при закрытой Docker network; при выносе за host/VPC TLS обязателен (`rediss://`) и plaintext отключается.
## 11. Docker/runtime
```text
redis/
docker-compose.yml
redis.conf
users.acl.template
scripts/
tests/
```
Compose: pinned Redis image, `expose: 6379`, без `ports`, `backend` network, `redis-data:/data`, config/ACL read-only, non-root UID, no-new-privileges, dropped capabilities, resource/memory/ulimit settings.
Startup валидирует config и ACL, permissions volume, затем Redis. Healthcheck использует ACL health user и `redis-cli --no-auth-warning PING`, secret не печатается. Graceful stop timeout позволяет AOF flush.
Credential URL не входит в общий публичный `.env` как секрет: secret file / arch-06.
## 12. Health — общие правила
`PING` проверяет liveness Redis; readiness приложений проверяет auth, correct DB и выполнение малого read/write/expire script без оставления key.
При latency выше threshold clients используют short timeout/circuit, не создают бесконечные retry storms. Reconnect — exponential backoff+jitter.
Degraded policy конкретного сервиса — спецификация VM.
## 13. Backup и restore
Redis backup не используется для бизнес restore. Runbook:
1. остановить/изолировать corrupted instance;
2. при целостном AOF/RDB восстановить на отдельном instance и проверить;
3. иначе поднять пустой Redis;
4. приложения прогревают ephemeral state из PostgreSQL / reconnect;
5. не копировать Redis dump в небезопасное место: keys содержат UUID и hashed identifiers.
Детали прогрева — спецификация VM.
## 14. Metrics и alerts — общие
- availability, commands/sec, latency percentiles;
- connected/blocked clients, rejected connections;
- memory/RSS/fragmentation, maxmemory ratio;
- evictions/expirations/keyspace hits/misses;
- AOF fsync latency/rewrite status/last save;
- replication metrics зарезервированы;
- key count/avg TTL по DB без key values;
- script errors/NOSCRIPT/slowlog;
- Pub/Sub subscribers/output buffer/slow disconnect.
Alerts: unavailable, p99 latency, >80/90% memory, any sustained evictions, AOF error, no recent persistence, client buffer pressure, unexpected keys without TTL.
Бизнес-метрики rate/idempotency/Safety cache — спецификация VM и arch-07. Keys/values не экспортируются.
## 15. Общий Definition of Done
- Lua scripts atomic, bounded, versioned и покрыты real Redis tests;
- AOF/RDB, volume, restart и clean-instance recovery проверены;
- maxmemory/eviction/resource limits основаны на load test либо явно TBD;
- ACL users и network isolation работают, порт не published;
- все application keys имеют TTL;
- logs/metrics не содержат secret/value/PII;
- Redis не используется как `sync_queue`, delivery queue, message/audit source of truth или OTP store.
Профильный DoD VM дополняет свои prefixes, URL и degraded policy.
## 16. Решения, допущения и TBD
**Решения:** по одной primary instance на каждую VM без replica/Sentinel в MVP; AOF everysec + RDB; Pub/Sub best effort; PostgreSQL durable fallback; prefix ACL; все application keys с TTL. Историческая схема «один instance / три DB» заменена разделением ВМ1 DB0/DB1 и Redis Safety ВМ2.
**Допущения:** Redis loss допустим без потери business truth; `bitrix-sync` Redis не использует.
**TBD:**
- R1: точный maxmemory после load profile — по VM.
- R2: eviction policy после измерений.
- R3: credential env names в arch-04.
- R5: TLS при изменении network topology.
- R6: момент разделения DB на instances — спецификация ВМ1.
- R7: RPO/RTO ops target.
- R4: Safety task TTL/recovery margin — спецификация ВМ2 (PostgreSQL, не Redis).
## 17. Ссылки
- ВМ1: [`module-04-redis-vm1.md`](../VM1_app/documentation/module-04-redis-vm1.md).
- ВМ2: [`module-04-redis-vm2.md`](../VM2_services/documentation/module-04-redis-vm2.md).