Redisson JCache와 Near Cache
최신 안정판 Bluetape4k 1.11.0 릴리스 기준
제공하는 기능
섹션 제목: “제공하는 기능”bluetape4k-cache-redisson은 Redisson을 bluetape4k-cache-core의 공통 cache API에 연결합니다. JCache와 coroutine용 SuspendJCache, sync·async·suspend memoizer, RLocalCachedMap 기반 Near Cache를 제공합니다.
이 모듈이 해결하는 문제는 Redis 연결 자체가 아닙니다. Redisson client를 애플리케이션이 소유한 상태에서 표준 JCache, 같은 key 계산 병합, JVM local entry의 Pub/Sub 무효화, coroutine 취소 전파를 일관된 API로 다루는 데 초점을 둡니다.
사용하기 전에 결정할 것
섹션 제목: “사용하기 전에 결정할 것”- 애플리케이션이 이미 Redisson을 사용하거나 Redisson의 distributed object와 codec을 함께 사용합니다.
- 완료된 계산 결과는 Redis에 공유하되 같은 key의 진행 중인 계산은 한 JVM 안에서만 합치면 됩니다.
- 별도 local cache와 invalidation listener를 직접 조립하지 않고
RLocalCachedMap의 Pub/Sub 동기화를 사용하려 합니다. - cache miss를 caller가 채우는 cache-aside인지,
CacheLoader·MapLoader가 맡는 read-through인지 먼저 정합니다. close()가 entry를 지우지 않는다는 점과 Redisson client의 종료 책임이 애플리케이션에 있다는 점을 받아들입니다.
단일 JVM cache면 cache-core가 더 작습니다. Redis 자료구조와 lock·topic까지 필요하면 redisson 매뉴얼도 함께 읽습니다.
의존성 추가
섹션 제목: “의존성 추가”사용자는 Redisson이나 하위 라이브러리 버전을 따로 맞추지 않고 중앙 BOM 버전만 관리합니다.
dependencies { implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>")) implementation("io.github.bluetape4k:bluetape4k-cache-redisson")}Gradle project path는 :bluetape4k-cache-redisson, source directory는 cache/cache-redisson입니다. 1.11.0 폴더 재편 뒤에도 Maven artifact와 io.bluetape4k.cache package는 그대로입니다.
첫 Redisson Near Cache
섹션 제목: “첫 Redisson Near Cache”Redisson client는 애플리케이션에서 만들고 종료합니다. Near Cache wrapper만 사용 범위에 맞춰 닫습니다.
import io.bluetape4k.cache.RedissonCachesimport io.bluetape4k.cache.nearcache.redissonNearCacheConfigimport java.time.Duration
val products = RedissonCaches.suspendNearCache<Product>( redisson = redissonClient, config = redissonNearCacheConfig { cacheName = "products" maxLocalSize = 5_000 timeToLive = Duration.ofMinutes(30) },)
products.put("p:1", Product("p:1", "keyboard"))val product = products.get("p:1")products.close()기본 codec은 RedissonCodecs.LZ4Fory입니다. key는 String으로 고정됩니다. close()는 wrapper를 destroy하지만 clearAll()처럼 entry 전체 삭제를 뜻하지 않습니다.
API 선택 지도
섹션 제목: “API 선택 지도”| 필요한 작업 | 시작할 API | 기억할 경계 |
|---|---|---|
| 표준 JCache | RedissonJCaching, RedissonCaches.jcache | lazy singleton CacheManager에서 같은 이름 cache를 재사용합니다. |
| coroutine JCache | RedissonSuspendJCache, suspendJCache | *Async().await()를 사용하지만 getAndPut은 get→put 두 단계입니다. |
| 동기 계산 재사용 | RMap.memoizer | evaluator는 호출 thread에서 실행되고 in-flight 공유는 JVM 내부입니다. |
| future 계산 재사용 | RMap.asyncMemoizer | cache 저장 실패는 경고하고 계산 결과 future는 정상 완료될 수 있습니다. |
| suspend 계산 재사용 | RMap.suspendMemoizer | evaluator 실패·취소는 저장하지 않고 다음 호출이 다시 계산합니다. |
| 동기 Near Cache | RedissonCaches.nearCache | blocking RLocalCachedMap 연산을 호출합니다. |
| suspend Near Cache | RedissonCaches.suspendNearCache | Redisson async 연산을 await()하며 clearLocal()은 local 호출입니다. |
| legacy front/back 조합 | nearJCache, suspendNearJCache | 새 코드는 native RLocalCachedMap 경로를 우선 검토합니다. |
학습 경로
섹션 제목: “학습 경로”아래 장은 기능 목록보다 한 단계 더 들어갑니다. 1.11.0의 실제 source와 test를 따라가며 기본값, 경쟁 조건, 실패 뒤 상태와 운영 판단을 설명합니다. 예제를 실행한 뒤 source link에서 전체 구현을 확인할 수 있습니다.
- Redisson JCache와 suspend wrapper — provider 생성, cache 재사용, async bridge와 비원자적
getAndPut을 확인합니다. - Memoizer와 같은 key 계산 병합 — sync·future·suspend 경로의 JVM 내부 single-flight와 실패 복구를 비교합니다.
- RLocalCachedMap Near Cache와 무효화 — local/Redis tier, Pub/Sub invalidation, clear 범위와 통계 한계를 설명합니다.
- 설정, codec과 client 소유권 — TTL, idle, eviction, reconnect, wire format과 resource owner를 정합니다.
- 실패, 취소, 수명주기와 운영 — Redis 장애, partial failure, cancellation, close와 관측 지표를 다룹니다.
- Cache 전략과 생태계 경로 — cache-aside와 read/write-through·behind를 구분하고 Hibernate, Spring, Exposed와 workshop으로 이어집니다.
처음 도입한다면 1→3→4 순서로 provider와 Near Cache 경계를 먼저 잡고, 계산 캐시가 필요할 때 2장을 읽습니다. 운영 중이라면 5장의 실패 표와 6장의 persistence 경로부터 확인해도 됩니다.
권장 패턴
섹션 제목: “권장 패턴”cache 이름은 서비스와 데이터 계약을 드러내게 정하고 환경 간 충돌을 피합니다. TTL과 local capacity를 명시하며 INVALIDATE와 reconnect CLEAR 기본값이 stale read 허용 범위에 맞는지 검토합니다.
memoizer evaluator는 재실행해도 안전한 조회·계산으로 제한합니다. 완료 값은 Redis에서 여러 JVM이 공유하지만 in-flight map은 process local이므로 서로 다른 JVM의 첫 miss는 evaluator를 각각 실행할 수 있습니다.
cache put을 database write-through라고 부르지 않습니다. persistence까지 연결하려면 loader·writer가 원본 저장소를 실제로 호출하는 별도 설계가 필요합니다.
이 모듈은 bluetape4k-cache-core의 API와 test fixture를 구현하고 bluetape4k-redisson의 client·codec 지원을 사용합니다. resilience4j는 Near Cache decorator 계약을 지원하기 위해 직접 연결됩니다.
cache-core는 provider-independent 계약을, redisson은 더 넓은 Redisson API와 codec·future/coroutine bridge를 설명합니다. persistence cache는 Hibernate, Spring Boot Hibernate Lettuce, Exposed workshop 경로에서 별도 transaction 규칙과 함께 다룹니다.
RedissonNearCacheConfig의 기본값은 cache name redisson-near-cache, local 최대 10,000개, TTL·idle 없음, INVALIDATE, reconnect CLEAR, LRU입니다. cache name은 blank일 수 없고 크기·TTL·idle은 양수여야 합니다.
wire format은 cache 생성 뒤 쉽게 바꿀 수 있는 UI 설정이 아닙니다. 기본 LZ4Fory와 다른 codec을 쓰려면 모든 producer·consumer가 같은 key/value format을 사용하도록 배포 순서를 정합니다.
JCache provider는 META-INF/services/javax.cache.spi.CachingProvider로 발견됩니다. 이름이 같은 cache가 이미 있으면 manager가 재사용하므로 테스트와 tenant마다 고유 이름을 씁니다.
실패 동작
섹션 제목: “실패 동작”RedissonSuspendJCache.getAndPut은 원자 연산이 아닙니다. 엄격한 원자성이 필요하면 Redisson RMap의 원자 API를 직접 선택합니다. suspend memoizer는 evaluator의 CancellationException을 성공 값으로 저장하지 않고 다시 던지며 in-flight entry를 제거합니다.
동기 Near Cache close()는 destroy 실패를 runCatching으로 소비합니다. suspend close는 일반 예외를 경고로 기록하지만 CancellationException은 전파합니다. 어느 경우에도 close()를 데이터 정리 API로 사용하지 않습니다.
Redis가 잠깐 불안정되었을 때 cache miss가 원본 저장소 부하로 이어질 수 있습니다. retry를 무작정 늘리면 cache가 장애 증폭기가 될 수 있으므로 timeout, fallback, 원본 pool 여유를 함께 정합니다.
Redis latency·오류·reconnect와 local cache size, 통합 hit·miss를 함께 봅니다. 1.11.0의 native Near Cache 통계는 Redisson이 local/back hit를 분리해 노출하지 않아 localHits와 localMisses가 0이고, backHits/backMisses도 통합 조회 결과를 세는 값입니다. 이를 실제 Redis 왕복 횟수로 해석하면 안 됩니다.
codec decode 오류, cache name 충돌, local capacity와 eviction, Pub/Sub reconnect 뒤 clear 횟수를 운영 점검에 포함합니다. Redisson client 종료는 애플리케이션 lifecycle이 담당합니다.
테스트
섹션 제목: “테스트”모듈 테스트는 Redis Testcontainer를 사용하므로 병렬로 무겁게 실행하지 않습니다.
./gradlew :bluetape4k-cache-redisson:test --no-build-cache --no-configuration-cacheRedissonCachesTest와 RedissonSuspendJCacheTest는 factory·CRUD·close를, memoizer 테스트는 thread·virtual thread·coroutine 경합과 실패·취소 복구를 검증합니다. Near Cache 테스트는 cache-core의 공통 conformance fixture를 상속하며 resilient decorator도 별도로 확인합니다.
워크숍
섹션 제목: “워크숍”가장 작은 실행 예제는 이 모듈의 테스트입니다. persistence read-through, write-through, write-behind까지 보려면 redisson-demo 매뉴얼과 examples/redisson-demo의 cache strategy 테스트를 따라갑니다.
Exposed repository cache는 exposed-workshop의 cache 장에서 JdbcCacheRepository, EntityMapLoader, EntityMapWriter로 확장합니다. 일반 Kotlin/Spring 예제는 bluetape4k-workshop에서 이어갈 수 있습니다.
1.11.0 범위
섹션 제목: “1.11.0 범위”이 매뉴얼은 bluetape4k-projects 1.11.0 배포 소스를 기준으로 합니다. RESP3 hybrid Near Cache API는 이 모듈에 없습니다. native Redisson 경로는 RLocalCachedMap, legacy JCache 경로는 Caffeine front와 Redisson JCache back을 사용하므로 두 모델을 섞어 설명하지 않습니다.
memoizer의 in-flight 조율은 분산 lock이 아닙니다. native Near Cache 통계는 local/back을 정확히 분리하지 못합니다. JCache getAndPut의 coroutine wrapper도 원자성을 보장하지 않습니다.