Files
llm-wiki/raw/branch-notes/feature-cache-consistency-contract.md
T

19 KiB

title, source_type, status, branch, related_projects, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, parent_branch, contract_packet_sha256
title source_type status branch related_projects tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet parent_branch contract_packet_sha256
branch / feature-cache-consistency-contract branch-note raw feature-cache-consistency-contract
ca-skeleton
branch
ca-skeleton
cache
redis
consistency
2026-05-22 in-progress BR-CA-SKELETON-OPERATIONAL-CONTRACT-024 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-024
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1
1 6d4978b50ddf3cab75e6803a198f9ca53753f9812e8f3a158f96c3544c843008

branch: feature-cache-consistency-contract

Layer: raw/branch-notes/ — cache consistency와 Redis/cache adapter 기준을 정의합니다.

[!important] 주도권 이전 고지 (2026-07-28) 아래 관심사의 owner 가 신규 branch 로 이동했다. 근거·절차: docs/superpowers/specs/2026-07-28-ca-skeleton-production-capability-feature-decomposition-design.md §5.

이전 ID 대상 D-row 이전한 관심사 신규 owner
H3 D3·D4·D5·D6·D7·D8·D9 cache 전략 — stampede·TTL·직렬화·negative·cluster raw/branch-notes/feature-cache-strategy-registry-contract

본문은 아직 제거하지 않았다. 신규 branch 는 현재 스캐폴딩 상태(D-row 없음)이므로, 지금 본문을 지우면 결정 근거가 소실된다. 위 D-row 는 신규 branch 의 /branch-spec 이 재판정을 마칠 때까지 잠정 근거로만 유효하며, 그 시점에 설계 §5.2 6단계에 따라 포인터(superseded → [[<신규 branch>]] D<m>)로 치환한다.

이 기간 중 새 결정을 본 branch 에 추가하지 않는다 — 신규 owner 에 작성한다.

부모 (필수)

ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§<관련 섹션>) 의 결정/근거/금지 사항을 정제한다.

묶음

본 feature branch 는 leaf — 자식 자료 없음. Phase C2 실 코드 작성 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.

오류 기록 (본 feature 작업 중 발생)

  • (없음 — 현재 documented-only 단계)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

  • (없음 — Phase C2 실 구현 단계에 누적)

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: after-commit invalidation·stampede failure fixture가 통과한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-DATABASE-001@1 database는 PostgreSQL 16 단일 stack이다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

cache miss/unavailable만으로는 cache 운영 기준이 부족합니다. stale cache, stampede, key naming, TTL, invalidation 실패를 skeleton 기준에 포함해야 합니다.

  • 이슈:
  • PR:

범위

포함 범위

  • cache aside 기준.
  • stale cache 허용 범위.
  • cache stampede 방지 기준.
  • cache key naming.
  • TTL 기준.
  • invalidation 실패 분류.
  • Redis unavailable degrade 기준과 연결.

제외 범위

  • business-specific cache policy.
  • distributed lock 기본 구현.
  • Redis cluster 운영 설정.

TODO

TODO drained — 결정은 아래 표/결정 사항 참조.

Work Item Contract

각 TODO는 아래 판정 단위로 재작성되어야 canonical 승급 가능합니다. TODO가 단순히 기준 작성으로 남아 있으면 이 branch는 완료로 보지 않습니다.

field required rule
Decision yes 구현자가 선택해야 하는 기본값
Allowed yes 허용되는 예외와 조건
Forbidden yes 절대 금지되는 구현/문서 상태
Required registry update conditional error/env/header/log/metric/capability 변경 시 필수
Required contract test yes 계약 위반 시 실패해야 하는 테스트
Failure condition yes review/build에서 실패로 판정할 상태
Canonical extraction target yes wiki/projects 승급 위치

진행 중 메모

  • cache consistency는 optional adapter이지만, 붙였을 때 같은 실패 계약을 따라야 합니다.

결정 사항 (decisions)

  • 2026-05-22: cache consistency를 Redis adapter 내부 세부사항으로만 두지 않음.
  • 2026-05-22: core는 single-instance/local cache policy만 완결. distributed cache lock/stampede 방지는 multi-instance package 활성화 시 필요.
  • 2026-05-22: Redis cluster 운영은 out of core이나 cluster mode 활성화 시 key hash/tag policy와 failover runbook이 필요.
  • 2026-05-22: cache invalidation = after-commit only. Spring TransactionSynchronizationManager.registerSynchronization으로 강제. tx 내부 또는 tx 미참여 상태에서의 cache mutation은 forbidden.
  • 2026-05-22: stampede 방지 default = single-instance Caffeine local lock, multi-instance HPA 시 Redisson RLock distributed mutex. application 별 override 금지.
  • 2026-05-22: cache value serialization = JSON (Jackson). 스키마 변경 시 key version suffix(v{n} 접미사) 필수.
  • 2026-05-22: negative cache 정책 = 존재하지 않는 row는 짧은 TTL(60s) 캐싱 허용. application별 override 가능.
  • 2026-05-22: eventual consistency window default = 5s (TTL과는 별개로 invalidation propagation 허용 한계).
  • 2026-05-22: negative cache TTL(60s)와 invalidation propagation window(5s)는 독립 축. negative cache는 invalidation 채널 적용 대상에서 제외 (적용 시 정상화). 두 수치는 의도된 분리.

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. company-tech-blog 는 company-case-study 로만 라벨 (best practice 단정 금지).

Decision ID Decision (요약) Supporting Claims Evidence Strength Open Risk
D1 cache pattern default = cache-aside (write-through without consistency contract 는 forbidden) raw/official-docs/cache-aside-vs-write-through-aws.md#CACHE-PAT-C1, #CACHE-PAT-C2, #CACHE-PAT-C3 official-vendor-doc (AWS + Redis 공식 — lazy caching 정의 + application 책임 + write-through latency tradeoff) "write-through 가 결제/주문 도메인에 부적합" 은 cited raw 가 직접 prescribe 안 함 — ca-tmpl 내부 결정. write-behind 의 data loss 메커니즘 (#CACHE-PAT-C5) 은 needs-confirmation — AWS Database Blog 또는 Redis docs 별도 raw 필요
D2 cache invalidation = after-commit only. Spring TransactionSynchronizationManager.registerSynchronization 으로 강제. tx 내부/tx 미참여 상태 cache mutation forbidden raw/company-tech-blogs/cache-woowahan-after-commit-invalidation.md (company-case-study — 우아한형제들 한국 사례) company-case-study (NOT official best practice) Spring TransactionSynchronizationManager 공식 reference 의 after-commit hook 시맨틱 verbatim 미수집 — 별도 official-doc raw 필요. 우아한형제들 사례는 한 회사의 결정이며 official-standard 가 아님
D3 stampede 방지 default = single-instance Caffeine local lock, multi-instance HPA 시 Redisson RLock distributed mutex raw/official-docs/cache-redisson-rlock-vs-setnx.md#LOCK-C1 (Redis SET NX PX 단순 패턴, 단일 인스턴스 efficiency lock), #LOCK-C4 (Kleppmann: efficiency vs correctness lock 분리), raw/official-docs/cache-caffeine-asyncloadingcache-readme.md (single-instance LoadingCache stampede 방지) official-vendor-doc (LOCK-C1 — Redis 공식 verbatim 확인) + engineering-blog (LOCK-C4 — Kleppmann 비판, WebFetch 차단으로 재확인 보류) LOCK-C3 (Redisson RLock watchdog + j.u.c.locks.Lock 호환) 은 needs-confirmation — redisson.org → redisson.pro redirect 차단. Redisson Javadoc 직접 다운로드 필요. Caffeine raw 의 claim ID 매핑 미확인 (본 세션 mandatory read 범위 밖)
D4 core 는 single-instance/local cache policy 만 완결. distributed cache lock/stampede 방지는 multi-instance package 활성화 시 필요 raw/official-docs/cache-redisson-rlock-vs-setnx.md#LOCK-C4 (efficiency vs correctness lock 분리 — cache stampede = efficiency lock) engineering-blog (Kleppmann, 재확인 보류) "stampede = efficiency lock" 의 분류가 모든 cache 시나리오 (token bucket, rate limit 등) 에 적용되는지 미검증 — correctness 가 필요한 endpoint 식별 필요
D5 cache value serialization = JSON (Jackson). 스키마 변경 시 key version suffix (v{n}) 필수 (UNSUPPORTED_DECISION — cited raw 4종 중 직접 verbatim claim 없음. Jackson docs / Redis serialization 공식 raw 별도 필요) internal-policy schema versioning 컨벤션은 ca-tmpl 내부 결정 — 외부 권위 근거 미수집
D6 negative cache 정책 = 존재하지 않는 row 는 짧은 TTL(60s) 캐싱 허용 (UNSUPPORTED_DECISION — cited raw 4종에 negative cache TTL verbatim 없음) internal-policy 60s 값은 ca-tmpl 내부 SLO — 외부 근거 미수집
D7 eventual consistency window default = 5s (TTL 과는 별개로 invalidation propagation 허용 한계) (UNSUPPORTED_DECISION — cited raw 4종에 propagation window 수치 verbatim 없음) internal-policy 5s 값은 ca-tmpl 내부 SLO — 외부 근거 미수집
D8 negative cache TTL(60s) 와 invalidation propagation window(5s) 는 독립 축 (D6/D7 분리) (UNSUPPORTED_DECISION — 위 두 값 자체가 internal policy) internal-policy 두 수치 모두 외부 근거 없음
D9 Redis cluster 운영은 out of core. cluster mode 활성화 시 key hash/tag policy + failover runbook 필요 (UNSUPPORTED_DECISION — cited raw 4종에 Redis cluster key hashtag 시맨틱 verbatim 없음. Redis 공식 cluster spec 별도 필요) internal-policy Redis cluster keyspace 분배 권고 (hashtag {}) verbatim raw 별도 수집 필요

검증해야 할 주장

공식 문서 인용이 결정의 근거이지만, ca-tmpl 자체 구현에서의 동작은 별도 검증이 필요한 주장.

Claim Why uncertain How to verify Status
LOCK-C3 (Redisson RLock watchdog + j.u.c.locks.Lock 호환) 의 verbatim 재확인 1차 URL redisson.org → redisson.pro 301 redirect, redirect 호스트 호출 차단으로 verbatim 재확인 불가 Redisson Javadoc 직접 다운로드 또는 archive.org 스냅샷으로 verbatim 격상 needs-confirmation
LOCK-C4 (Kleppmann fencing token) verbatim 재확인 martin.kleppmann.com WebFetch permission denied archive.org Kleppmann "How to do distributed locking" 스냅샷 verbatim 확보 needs-confirmation
stampede 방지 contract test (ArchUnit methodsThat().areAnnotatedWith(@Cacheable)... withAttribute("sync", "true")또는AsyncLoadingCache또는RLock` wrap) 가 실제로 위반 검출 cited raw 는 stampede 방지 도구 비교까지만 보장 — ArchUnit rule 동작은 별도 ArchUnit test 작성 + 의도적 위반 case (sync=false 한 @Cacheable 추가) 로 fail 확인 planned
multi-instance cache claim consistency (env APP_MULTI_INSTANCE_ENABLED=true + APP_CACHE_REDIS_ENABLED=true 시 Redisson bean 등록 + 모든 hot cache 메서드 RLock wrap) LOCK-C3 가 needs-confirmation 인 상태에서 RLock wrap 의 실제 효과 미보증 MultiInstanceCacheStampedeContractTest 작성 + 두 flag true 일 때 Redisson bean verify + 동시 cache miss 1회 backend 호출 확인 planned
after-commit invalidation 이 tx rollback 시 cache 에 stale write 를 남기지 않음 우아한형제들 사례 (D2) 는 company-case-study — 우리 환경에서의 동작 별도 보장 필요 TransactionTemplate rollback 시나리오 integration test + Redis key 미존재 단언 planned
Redis unavailable 시 degrade 가능 endpoint 가 declared 된 경우에만 fail-fast 회피 (generic INTERNAL 금지) cited raw 는 degrade 정책 자체를 prescribe 안 함 — 내부 결정 contract test: Redis down 시 declared degrade endpoint 는 fallback 응답, undeclared 는 503/CACHE_UNAVAILABLE 반환 planned
negative cache TTL 60s + invalidation propagation 5s 값의 적절성 (D6/D7) UNSUPPORTED_DECISION — 외부 근거 없음 도메인별 stale tolerance SLO 측정 + p99 user-visible staleness 추적 planned
Spring TransactionSynchronizationManager.registerSynchronization 의 after-commit hook 시맨틱 (D2 메커니즘) 공식 reference verbatim raw 미수집 Spring Framework Reference §Transaction Synchronization raw 수집 후 afterCommit hook 보장 verbatim 확인 needs-confirmation

Decisionized Work Items

item Decision Allowed Forbidden Required test
cache pattern cache-aside default read-through if adapter owns it write-through without consistency contract cache behavior test
TTL explicit per key family no-cache for sensitive data immortal cache TTL test
stampede local lock in single-instance distributed lock for HPA hot key without guard stampede test
key scope app/profile/operation/tenant-if-enabled hash compact key PII/raw user id key naming test
Redis unavailable degrade only if declared fail-fast for required cache generic INTERNAL unavailable mapping

테스트 계약

  • cache key naming에 operation/tenant/profile 기준이 없으면 실패.
  • invalidation 실패가 조용히 무시되면 실패.
  • stampede 방지 검증: @Cacheable이 적용된 모든 메서드는 (a) sync=true 명시 또는 (b) Caffeine의 AsyncLoadingCache 사용 또는 (c) Redisson RLock wrap 중 하나여야 함. 측정 방법: ArchUnit methodsThat().areAnnotatedWith(@Cacheable).should().beAnnotatedWith(@Cacheable.class).withAttribute("sync", "true") 또는 동등 reflection check. 위반 시 fail.
  • Redis unavailable이 degrade 가능 여부 없이 INTERNAL로 처리되면 실패.
  • multi-instance cache claim consistency: env property APP_MULTI_INSTANCE_ENABLED=true이고 APP_CACHE_REDIS_ENABLED=true이면 Redisson RedissonClient bean이 등록되어 있고 모든 hot cache 메서드가 RLock으로 wrap되어 있어야 함. 측정 방법: 두 flag 모두 true일 때 contract test MultiInstanceCacheStampedeContractTest.java에서 Redisson bean verify + RLock 사용 검증.
  • tx rollback 시 cache에 stale write가 남으면 실패.
  • 동일 key에 대해 동시 cache miss 시 backend 호출이 1회로 제한되는지 verify (stampede). 미충족 시 실패.

마주친 문제

  • 아직 없음.

근거 (필수, 최소 1개+)

본 branch의 결정 근거. 상세 비교는 §외부 근거 / 대안 조사 (있다면) 참조.

Source 정당화하는 결정
raw/official-docs/cache-aside-vs-write-through-aws cache-aside default 채택의 trade-off 표 + AWS 공식 분류
raw/official-docs/cache-caffeine-asyncloadingcache-readme single-instance stampede 방지를 LoadingCache / `@Cacheable(sync=true
raw/official-docs/cache-redisson-rlock-vs-setnx multi-instance HPA에서 Redisson RLock 채택 + SETNX/Redlock 배제 근거 (Kleppmann 비판 포함
raw/company-tech-blogs/cache-woowahan-after-commit-invalidation after-commit invalidation 결정의 한국 사례 + Spring TransactionSynchronizationManager 강제 근거

외부 근거 (Group G-C — Cache consistency)

ca-tmpl cache 결정 backbone + stampede 방지 도구 비교 자료.

검색 키워드 기록: cache-aside vs write-through trade-off, Caffeine AsyncLoadingCache stampede, Redisson RLock vs SETNX, Kleppmann Redlock unsafe, 우아한형제들 캐시 무효화 트랜잭션.

구현 가이드

  • write transaction commit 이후에만 invalidate하고 rollback 시 cache를 변경하지 않는다.
  • TTL·key namespace·stampede 방지 정책은 registry 값으로 고정하고 backend adapter가 적용한다.
  • hit·miss·eviction·fallback을 contract test와 metric으로 함께 검증한다.

엣지·실패·의존

  • commit 전 eviction은 rollback 뒤 stale miss를, eviction 실패 무시는 stale read를 만들 수 있다.
  • database transaction·multi-backend router·runtime context 계약에 의존한다.

관련 일일 노트

  • 별도 일일 노트 없음.

완료 후 정리

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경:
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목:
    • locally-verified 항목:
    • prod-verified 항목:
  • 추출하지 않을 항목 (planned / documented-only / abandoned):