Files
llm-wiki/wiki/concepts/data-layer-persistence-cache-outbound.md
T

11 KiB

title, source_type, status, confidence, tags, related_projects, last_reviewed
title source_type status confidence tags related_projects last_reviewed
Data Layer Baseline (Persistence + Cache + Outbound HTTP) llm-generated draft medium
persistence
jpa
cache
http-client
resilience
ca-skeleton
2026-05-22

Data Layer Baseline (Persistence + Cache + Outbound HTTP)

Layer: wiki/concepts/ — Phase E Group G-C 합성. 3개 sub-topic(Persistence failure / Cache consistency / Outbound HTTP)을 하나의 baseline canonical로 묶음. 프로젝트 적용 사실은 wiki/projects/에 별도 작성하고 본 문서에서는 링크만 둠.

Summary

Data layer baseline은 세 가지 축으로 구성된다.

  • Persistence: SQLState 매트릭스로 DB 실패를 분류하고, Spring DataAccessException 계층 위에 매핑하여 PERSISTENCE / CONFLICT / TRANSIENT_DEPENDENCY 카테고리를 만든다. OSIV는 off가 기본.
  • Cache: cache-aside default + Caffeine local lock(single-instance) + Redisson RLock distributed mutex(multi-instance HPA) + after-commit invalidation + eventual consistency window 5초.
  • Outbound HTTP: Spring RestClient를 baseline으로 두고, retry/circuit breaker는 Resilience4j로 일원화. timeout default = connect 2s / read 5s / global 10s.

Standard (공식 정의)

Persistence — SQLState + Spring DAO hierarchy

  • SQLState (ISO/IEC 9075): 5-char code로 DB 오류를 표준 분류. 08* = connection exception, 40001 = serialization failure, 40P01 = deadlock(Postgres), 23xxx = integrity constraint, 57014 = query canceled.
  • Spring DataAccessException hierarchy: TransientDataAccessException / NonTransientDataAccessException / RecoverableDataAccessException로 retryable/non-retryable 1차 분리. JPA PersistenceExceptionJpaSystemException으로 흡수.
  • OSIV (Open Session In View): Hibernate session을 view rendering까지 열어두는 패턴. Vlad Mihalcea가 anti-pattern으로 명시했고 Spring Boot는 활성화 시 startup WARN 로그를 출력. 운영 baseline은 off.
  • HikariCP pool sizing: 공식 wiki는 connections = ((core_count * 2) + effective_spindle_count) 공식과 단일 small pool 권장. pool wait p99 / pool exhaustion이 1차 alert 지표.

Cache — cache-aside + stampede control

  • Cache-aside (Microsoft Cloud Design Patterns / AWS ElastiCache): application이 cache miss 시 DB 조회 → cache 채움. invalidation도 application 책임. write-through는 cache layer가 sync 책임, write-behind는 async, read-through는 cache layer가 loader를 안다. 책임 위치가 다름.
  • Caffeine AsyncLoadingCache / @Cacheable(sync = true): 동일 key 동시 miss를 단일 loader 호출로 직렬화 (in-process stampede 방지).
  • Redisson RLock: Redis 기반 reentrant lock + watchdog lease extension. Kleppmann의 Redlock 비판을 회피하기 위해 단일 master 기반 RLock + fence token 사용.
  • after-commit invalidation: Spring TransactionSynchronizationManager.registerSynchronizationafterCommit() hook에서만 cache mutation 수행. tx rollback 시 stale write 차단.

Outbound HTTP — RestClient + Resilience4j

  • Spring RestClient (6.1+): RestTemplate의 fluent 후속 API. RestTemplate은 Spring 공식 maintenance-only 상태로 신규 기능 추가 없음.
  • Resilience4j: Netflix Hystrix의 사실상 후속. Hystrix는 2018년 maintenance mode 진입. Retry / CircuitBreaker / TimeLimiter / Bulkhead / RateLimiter를 functional decorator로 제공.
  • Circuit breaker 상태: CLOSEDOPEN (failure rate threshold 초과) → HALF_OPEN (probe) → CLOSED 복귀. Micrometer로 state transition을 metric으로 노출.
  • Timeout 계층: connect timeout(소켓 연결) < read timeout(응답 첫 바이트 대기) < global call timeout(전체 호출). 셋 중 하나라도 미설정이면 무한 대기 위험.

한계 / 주의점

Persistence

  • SQLState 9-row matrix의 vendor-specific row(PostgreSQL 23505, 40P01 등)는 DB 변경 시 재검증 필요. MySQL은 40001만 공유하고 40P01 대신 다른 코드를 사용.
  • OSIV off는 lazy loading exception을 presentation까지 새지 않게 막아주지만, application 경계에서 명시적 fetch 전략(@EntityGraph, fetch join, DTO projection)을 강제한다. 익숙하지 않은 팀은 운영 부담이 늘 수 있음.
  • R2DBC reactive는 throughput 우위가 있으나 JPA tooling을 포기해야 한다. baseline은 JPA blocking으로 고정한 trade-off의 반대편.

Cache

  • cache-aside의 eventual consistency window가 5초로 잡혀 있어 strict consistency가 요구되는 use case(잔액, 인증, idempotency 검증)에는 부적합. 해당 use case는 cache bypass를 명시.
  • Caffeine local cache + Redisson 분산 mutex 조합은 노드 간 sync lag이 존재. 한 노드가 invalidation을 발행한 뒤 다른 노드의 local cache가 비워질 때까지 lag 발생.
  • Redisson RLock도 Kleppmann의 분산 lock 비판에서 완전히 자유롭지 않다. 정확한 fencing을 요구하는 경우 token + DB-level optimistic lock 병행이 필요.
  • negative cache(존재하지 않는 row, TTL 60s)는 invalidation 채널 적용 대상에서 제외 — 의도된 분리이지만 row가 실제로 생성된 직후 60초간 stale empty 응답이 나갈 수 있음.

Outbound HTTP

  • RestClient는 Spring 6.1+ 한정. 기존 RestTemplate 코드는 마이그레이션 비용이 따른다.
  • WebClient는 reactor event-loop 위에서 동작하므로 MVC(servlet) baseline에 강제 도입하면 blocking risk가 있다. baseline에서는 extension 문서로 분리.
  • OpenFeign은 declarative interface로 편리하지만 Spring Cloud 의존이 붙는다. Spring 6.1+ @HttpExchange가 framework-level 대안.
  • Stripe engineering blog는 retry default-on을 옹호하지만 이는 idempotency-key 헤더 보장이 전제. 일반 API에 default-on retry를 적용하면 비-idempotent endpoint의 중복 write 위험이 생긴다.
  • Resilience4j는 Spring Boot starter 통합이 매끄럽지만, Spring 외 환경(plain Java, Vert.x 등)에서는 verbose한 functional decorator 작성이 필요. "vendor-neutral"로 단언하기에는 일부 마찰이 있음.

Project Application

Interview Questions

  • SQLState 코드를 어떻게 retryable / non-retryable로 매핑했고 그 분류가 Spring DataAccessException hierarchy와 어떻게 정합한가?
  • OSIV가 anti-pattern으로 평가되는 이유는 무엇이고 off로 두었을 때 lazy loading은 어떻게 해결하는가?
  • cache-aside의 eventual consistency window 5초가 의미하는 바와, 그 안에서 stale read가 허용되지 않는 use case는 어떻게 분리하는가?
  • Resilience4j를 Hystrix 대신 선택한 이유와 두 라이브러리의 차이는?
  • outbound HTTP timeout을 connect 2s / read 5s / global 10s로 둔 의도와 셋 중 어떤 게 빠지면 어떤 위험이 생기는가?
  • after-commit invalidation을 강제하는 이유와, transaction rollback 시 cache 일관성이 어떻게 보장되는가?

Do Not Overclaim

  • "cache-aside면 항상 안전하다" — strict consistency가 요구되는 use case에서는 cache bypass가 필요하다. cache-aside는 eventual consistency 모델이다.
  • "Resilience4j는 vendor-neutral이라 어디서나 동일하게 동작" — Spring Boot starter 통합 외 환경에서는 functional decorator를 직접 조립해야 하고 boilerplate가 늘어난다.
  • "RestClient가 RestTemplate를 완전히 대체했다" — Spring 6.1+ 한정이고 기존 코드 마이그레이션 비용이 있다.
  • "Redisson RLock이면 분산 lock 문제 해결" — Kleppmann 비판은 완화되었지만 fencing token / DB optimistic lock 병행이 필요한 경우가 있다.
  • "Stripe처럼 retry default-on이 좋은 패턴이다" — Stripe는 idempotency-key 보장이 전제. 일반 API에 그대로 적용하면 위험하다.

Sources

공식 근거 (Persistence)

공식 근거 (Cache)

사례 (Cache)

공식 근거 (Outbound HTTP)

사례 (Outbound HTTP)

Canonical contract