230 lines
16 KiB
Markdown
230 lines
16 KiB
Markdown
---
|
|
title: Runbook — Redis capability incident
|
|
category: TRANSIENT_DEPENDENCY
|
|
error_codes: []
|
|
severity: P1
|
|
owner: oncall
|
|
last_updated: 2026-07-29
|
|
status: active
|
|
---
|
|
|
|
# Runbook: Redis capability incident (`runbook://redis/capability-incident`)
|
|
|
|
이 runbook은 Redis 전체를 하나의 상태로 취급하지 않는다. 먼저 영향받은 capability와 role을
|
|
식별한다.
|
|
|
|
| Role | Capability | 기본 안전 결정 |
|
|
| --- | --- | --- |
|
|
| `CACHE` | cache, cache refresh soft lease | source fallback 예산 안에서 degraded serving 허용 |
|
|
| `COORDINATION` | edge rate limit, request-replay idempotency, efficiency lease | 새 mutation/claim을 fail closed하고 결과 불확실성을 보존 |
|
|
| `SESSION` | Redis session | 인증을 fail open하지 않고 재인증 또는 503으로 전환 |
|
|
|
|
Redis liveness 실패만으로 pod를 재시작하지 않는다. 재시작 폭주는 reconnect와 source fallback
|
|
부하를 키울 수 있다.
|
|
|
|
## Detection
|
|
|
|
- readiness detail에서 affected role과 `required` 여부를 확인한다. endpoint, key, token, secret
|
|
reference는 detail에 포함되면 안 된다.
|
|
- semantic reason을 구분한다: read/write failure, program ACL denial, unsupported server
|
|
version, program failure, command saturation, recent command failure, probe-in-progress,
|
|
stale observation, closed route, command unavailable. `semanticObservedAt`,
|
|
`semanticAgeMillis`, `semanticStale`를 함께 확인한다. PING 성공만으로 role이 ready라는 뜻은
|
|
아니다.
|
|
- `evictionValidation=CONFIGURED_EXPECTATION_ONLY`와
|
|
`externalEvictionAttestation=INCOMPLETE`는 effective server policy가 증명되지 않았다는
|
|
뜻이다. 이를 정상 attestation으로 해석하지 않는다.
|
|
- `redis.capability.operations.total`과 `redis.capability.duration.seconds`에서 affected
|
|
capability/role/operation의 실제 반환 outcome을 확인한다. mutation의
|
|
`certainty=indeterminate`는 timeout이나 연결 끊김을 미실행 증거로 바꾸지 않는다.
|
|
- `redis.capability.admission.rejected.total`에서 `rejected_saturated`와
|
|
`rejected_closed`를 구분하고, `redis.capability.inflight.total`의 같은 role에 대해 현재 0이
|
|
아닌 state를 확인한다. in-flight gauge는 bounded command count이며 byte 수나 queue depth가
|
|
아니다.
|
|
- `redis.capability.readiness.total`은 현재 상태 gauge가 아니라 exact sanitized
|
|
`RoleHealth` 관측 횟수다. 최신 health detail의 state/reason/requirement와 함께 해석한다.
|
|
optional cache의 degraded serving과 required coordination/session의 fail-closed 결정을
|
|
같은 availability 의미로 합치지 않는다.
|
|
- 종료 시 `redis.capability.lifecycle.drain.total`에서 `drained`,
|
|
`forced_after_timeout`, `interrupted`를 구분한다. repeated close는 새 drain을 시작하거나
|
|
중복 관측을 만들지 않는다.
|
|
- reconnect, cache source-load, session repository error 지표의 변화를 함께 본다.
|
|
- Redis server 측에서는 memory/eviction, rejected clients, replication link/lag,
|
|
persistence error, Cluster coverage를 operator dashboard에서 확인한다.
|
|
- `NOSCRIPT`, result-schema mismatch, ACL denial, TLS/auth failure, OOM, timeout을 서로 다른
|
|
incident category로 분류한다. timeout은 command 미실행 증거가 아니다.
|
|
|
|
### Observability and lifecycle boundaries
|
|
|
|
- 여섯 `redis.capability.*` meter의 tag는 닫힌 enum에서만 생성된다. key, subject, session id,
|
|
token, endpoint, exception text, script/SHA, value 같은 identity/wire material을 metric이나
|
|
ticket에 복사하지 않는다.
|
|
- semantic operation 계측은 logical provider가 실제로 반환한 hit/miss/denied/conflict/
|
|
unavailable/indeterminate 결과를 기록한다. cache의 `stale`/`skipped`, session의
|
|
`tombstoned`/`absolute_expired`도 정상 hit/miss와 분리한다. meter registry, classifier,
|
|
monotonic ticker 장애는 command 결과나 원래 exception instance를 바꾸지 않는다.
|
|
- route 응답이 설정된 byte/collection bound를 넘으면 동일 logical operation을
|
|
`unavailable`로 종료한다. GET/read-only 응답은 `not_applied`, mutation VALUE/MULTI 응답은
|
|
서버 실행 여부를 되돌릴 수 없으므로 `indeterminate`다. 앞선 `success` 표본과 이 실패를 두
|
|
operation으로 합산하지 않는다.
|
|
- Spring 종료의 dependency order는 invalidation subscription 같은 capability dependent를 먼저
|
|
닫고, capability bean을 닫은 다음 canonical registry가 router admission을 닫아 in-flight를
|
|
bounded drain하고 마지막에 runtime을 닫는 순서다. 종료 중 새 command를 허용하거나 drain
|
|
timeout 뒤 무기한 기다리지 않는다.
|
|
- 현재 composition에는 active Redis scheduler나 dormant credential-rotation coordinator가 없다.
|
|
존재하지 않는 lifecycle coordinator를 복구 절차에서 찾거나 수동 호출하지 않는다.
|
|
- 이 meter와 단일-process lifecycle test는 Sentinel/Cluster failover, TLS/ACL 배포 적합성,
|
|
k3s multi-node, L1/L2 분산 일관성, distributed session 동작의 qualification 증거가 아니다.
|
|
해당 label은 별도 topology/conformance lane의 실제 증거가 있어야 한다.
|
|
|
|
## Immediate mitigation
|
|
|
|
1. 새 배포나 credential/program 전환 직후라면 해당 rollout을 중지한다. 이미 실행된 mutation을
|
|
무조건 재시도하지 않는다.
|
|
2. optional cache만 영향을 받으면 source bulkhead와 stale/source fallback 예산을 확인한 뒤
|
|
degraded serving을 유지한다. source가 포화되면 cache miss를 더 많은 source 요청으로
|
|
증폭시키지 않는다.
|
|
3. rate limit이 불확실하면 정책에 정의된 fail-closed 또는 bounded local-emergency만 사용한다.
|
|
local provider를 조용한 primary fallback으로 바꾸지 않는다.
|
|
4. idempotency claim/complete 응답이 유실됐으면 같은 operation token으로 inspect/reconcile한다.
|
|
record를 삭제하거나 새 owner를 추측하지 않는다.
|
|
5. lease 결과가 불확실하면 소유권이 있다고 가정하지 않는다. fencing 없는 efficiency lease를
|
|
correctness lock으로 승격하지 않는다.
|
|
6. session repository 장애에서는 기존 요청을 인증된 것으로 간주하지 않는다. fail closed 또는
|
|
재인증으로 전환하고 JWT와 Redis Session filter를 동시에 활성화하지 않는다.
|
|
|
|
## Diagnosis
|
|
|
|
### Connectivity, TLS, ACL
|
|
|
|
- 배포 설정이 올바른 role을 참조하고 TLS, hostname verification, explicit trust bundle, named ACL
|
|
user를 사용하는지 확인한다.
|
|
- runtime identity로 `CONFIG`, `KEYS`, `FLUSH*`, arbitrary program deployment를 시도하지
|
|
않는다. Catalog digest로 닫힌 recovery 외 ACL 점검은 별도 operator/deployer identity의
|
|
`ACL DRYRUN` 또는 동등한 관리 절차로 수행한다.
|
|
- runtime readiness identity에는 bounded probe namespace `~ca-health:*`, SET/GET/DEL,
|
|
PING/EVALSHA와 catalog recovery에 필요한 SCRIPT LOAD, 그리고 선택 capability manifest의 exact
|
|
command set이 필요하다. broad `~*`/`+@all`로 장애를 우회하지 않는다.
|
|
- readiness probe는 5초 TTL의 opaque key만 사용한다. `ca-health:*` key가 5초를 넘겨 남는다면
|
|
cleanup/expiry 이상으로 분류하되 key나 value를 ticket/log에 복사하지 않는다.
|
|
- 기본 semantic cadence는 minimum interval 5초, maximum staleness 15초다. refresh follower는
|
|
blocking하지 않는다. maximum staleness를 넘은 관측을 backend 정상으로 해석하지 말고,
|
|
probe 부하를 줄이기 위해 interval을 1초 미만으로 낮추지 않는다.
|
|
- optional CACHE의 typed temporary connect/PING outage만 dormant degraded startup과
|
|
health-triggered reconnect를 허용한다. reconnect 후보는 full semantic qualification 뒤에만
|
|
설치된다. auth/TLS/material/version/ACL/schema mismatch를 transient로 재분류하거나 required
|
|
role에 같은 fallback을 적용하지 않는다.
|
|
- credential rotation 중이라면 new credential 검증, traffic switch, old connection drain,
|
|
old credential revoke 순서를 확인한다. secret 값은 ticket, log, shell history에 복사하지 않는다.
|
|
|
|
### Program or schema
|
|
|
|
- checked-in program manifest digest와 배포 artifact digest를 대조한다.
|
|
- `semantic-capability-acl-v1` contract와 Redis minimum 7.2를 확인한다. 이 프로그램은
|
|
Redis Lua API의 `redis.acl_check_cmd`로 선택 capability의 exact command/key 권한을
|
|
비변경 방식으로 검사하고 `redis.REDIS_VERSION_NUM`의 explicit >=7.2 gate를 먼저 적용한다.
|
|
두 API는 7.0부터 존재하지만 repository support policy minimum은 7.2다.
|
|
- `NOSCRIPT`는 bounded `SCRIPT LOAD -> digest verify -> EVALSHA` recovery가 수행됐는지 확인한다.
|
|
arbitrary `EVAL`로 우회하지 않는다.
|
|
- result-schema/key/codec future version은 장애가 아니라 호환성 위반으로 분류하고 writer rollout을
|
|
중지한다.
|
|
- `BUSY` 또는 slow program이면 affected capability admission을 줄이고 isolated environment에서만
|
|
재현한다. shared Redis에 장시간 script를 추가 실행하지 않는다.
|
|
|
|
### Memory and eviction
|
|
|
|
- `CACHE` 배포와 `COORDINATION`/`SESSION` 배포가 물리적으로 분리됐는지 확인한다.
|
|
- correctness role에서 eviction이 관측되면 P1이다. 새 write를 중지하고 record loss를 전제로
|
|
idempotency/session reconciliation 또는 재인증 범위를 산정한다.
|
|
- noeviction OOM은 성공으로 변환하지 않는다. cache write는 degraded/indeterminate, coordination
|
|
mutation은 unavailable/indeterminate로 유지한다.
|
|
- big key를 찾을 때 production request path에서 `KEYS`나 unbounded collection read를 사용하지
|
|
않는다. 승인된 operator job의 bounded `SCAN`/sampling을 사용한다.
|
|
|
|
### Topology and persistence
|
|
|
|
- 현재 구현 후보 card의 promotion topology는 readiness registry의 `selected-topology`가 정본이다.
|
|
이는 selection 또는 R2 qualification을 뜻하지 않는다. Sentinel/Cluster evidence가 없는
|
|
상태에서 standalone 증거를 HA 증거로 재사용하지 않는다.
|
|
- Cluster same-slot semantic probe는 해당 hash slot owner 한 노드만 검증한다. 이를 cluster-wide
|
|
또는 failover target version/ACL/program 증거로 해석하지 말고, promotion 전에 모든 target을
|
|
별도 conformance lane으로 검증한다.
|
|
- failover 뒤에는 in-flight mutation의 certainty, primary role, program availability, replication
|
|
offset/lag, persistence status를 각각 확인한다.
|
|
- restore 후 session/idempotency/lease record를 자동으로 신뢰하지 않는다. security epoch,
|
|
tombstone, durable receipt/fencing high-watermark가 필요한 capability는 별도 reconciliation을
|
|
수행한다.
|
|
|
|
### Sentinel failover
|
|
|
|
1. affected role의 semantic readiness가 unavailable인지 확인하고 단순 PING success로 정상 판정하지
|
|
않는다. required coordination/session은 새 mutation admission을 닫는다.
|
|
2. 세 Sentinel 중 응답 수와 같은 master에 동의한 수를 확인한다. 2-of-3 동의 전에는 임의 endpoint,
|
|
최초 응답 또는 DNS 추측으로 data runtime을 바꾸지 않는다.
|
|
3. Sentinel discovery credential/CA와 Redis data credential/CA가 분리되어 있는지 확인한다.
|
|
장애 우회를 위해 trust-all, hostname verification off, plaintext 또는 broad ACL을 열지 않는다.
|
|
4. election, discovered primary qualification, new runtime install, old runtime admission close/drain의
|
|
순서를 확인한다. old runtime을 강제로 닫아야 했다면 그 시점의 mutation을 성공/미실행으로
|
|
추정하지 않는다.
|
|
5. response-only cut, timeout, disconnect가 있었던 rate/idempotency/session mutation은
|
|
`INDETERMINATE`를 보존한다. rate evaluation replay, 같은 idempotency/session operation token의
|
|
inspect/reconcile 또는 재인증을 사용하고 blind retry하지 않는다.
|
|
6. semantic readiness 복구 전에는 traffic을 정상화하지 않는다. 복구 뒤 old primary의 replica
|
|
재합류, replication lag/acknowledgement, program digest, actor runtime generation을 확인한다.
|
|
|
|
Sentinel은 asynchronous replication의 zero-data-loss나 strong consistency를 보장하지 않는다.
|
|
`min-replicas-to-write`, lag bound, replica acknowledgement가 설정돼도 acknowledgement 결과가
|
|
불명확한 mutation은 여전히 `INDETERMINATE`다.
|
|
|
|
`min-replicas-to-write 1` + `min-replicas-max-lag 1`은 선택이 아니라 **필수**다. 미설정 시
|
|
promotion 중 교체된 구 primary가 계속 `+OK`를 반환하고 그 write는 resync에서 폐기된다. 7.4
|
|
레인 실측: 승격 후 강등까지 11초, 그 사이 **2,086건이 acknowledge된 뒤 소실**, 실패한 명령은
|
|
1건. 클라이언트는 이를 감지할 수단이 없다 — 서버가 응답했으므로 driver·SDK·호출자 모두
|
|
정상 성공으로 기록한다. 설정 후 동일 promotion에서 소실 1건, 나머지 2,020건은 `NOREPLICAS`로
|
|
명시 거부됐다. 근거: `docs/redis/operations.md`, `LiveRedisSentinelPromotionTest`.
|
|
|
|
### Disposable Multipass k3s qualification safety
|
|
|
|
qualification lab은 host k3s incident 조치 도구가 아니다. VM exact allowlist는
|
|
`ca-redis-lab-server`, `ca-redis-lab-agent-1`, `ca-redis-lab-agent-2`이며 전용 kubeconfig와
|
|
`ca-redis-lab` context만 사용한다.
|
|
|
|
- 시작 전 host context/API/node/CIDR/NodePort와 Multipass inventory fingerprint를 기록한다.
|
|
- lab pod/service CIDR `10.52.0.0/16`, `10.53.0.0/16`이 host와 겹치면 생성하지 않는다.
|
|
- default kubeconfig를 merge/overwrite하거나 host context에 write command를 실행하지 않는다.
|
|
- cleanup은 exact 세 VM만 대상으로 한다. global `multipass purge`, wildcard delete를 사용하지
|
|
않는다.
|
|
- 성공/실패 뒤 postflight fingerprint와 VM resource 0을 확인한다. local retain-on-failure가
|
|
명시적으로 활성화됐으면 보존 이유와 exact inventory를 기록하며 CI에서는 보존하지 않는다.
|
|
- 이 한 물리 host의 3 VM 결과를 k3s control-plane HA, physical host/AZ failure 또는
|
|
multi-region 증거로 승격하지 않는다.
|
|
|
|
## Recovery and verification
|
|
|
|
1. affected role의 connection/auth/TLS와 `ca-health:` SET/GET/cleanup probe가 정상인지
|
|
확인한다. probe 잔여 key가 있으면 최대 TTL 5초 뒤 소멸하는지도 확인한다.
|
|
2. 선택 capability의 대표 program digest/result schema, semantic ACL contract와 Redis minimum
|
|
version 7.2를 재확인한다.
|
|
3. capability별 smoke를 수행한다: cache generation guarded write, rate evaluation replay,
|
|
idempotency same-operation inspect, lease stale-owner reject, session create/read/logout.
|
|
4. queue saturation, indeterminate outcome, source fallback, re-auth 지표가 incident 전 범위로
|
|
돌아온 뒤에만 rollout을 재개한다.
|
|
5. `CONFIGURED_EXPECTATION_ONLY`인 eviction은 operator/deployer identity의 외부 conformance
|
|
job 또는 서명 attestation으로 effective policy를 별도 검증한다. runtime user에 CONFIG/ACL
|
|
권한을 추가하지 않는다.
|
|
6. production label을 변경하기 전 repository readiness task를 실행한다. Sentinel/Cluster task가
|
|
zero-evidence로 실패한다면 topology를 낮춰 표기하거나 실제 evidence를 먼저 추가한다.
|
|
7. Sentinel qualification에서는 actual image ID/digest와 fault/election/runtime-swap/readiness
|
|
timeline, capability certainty, teardown 결과가 sanitizer/reconciler를 통과했는지 확인한다.
|
|
clean committed source와 실제 remote CI가 없으면 `implemented-candidate`,
|
|
`releaseQualification=NOT_CLAIMED`를 유지한다.
|
|
|
|
## Escalation
|
|
|
|
- `COORDINATION` 또는 `SESSION` required role이 5분 이상 unavailable이면 P1로 Redis/platform,
|
|
application on-call을 동시에 호출한다.
|
|
- data loss, stale session resurrection, conflicting idempotency completion, duplicate correctness
|
|
side effect가 의심되면 security/business owner까지 즉시 확대한다.
|
|
- 한 물리 host의 VM 세 개 또는 standalone container 결과를 AZ/host failure 증거로 해석하지
|
|
않는다. 그 증거가 필요한 release는 별도 disposable multi-node qualification을 요구한다.
|