Near Cache 구조와 Region
최신 안정판 Bluetape4k 1.11.0 릴리스 기준
두 계층이 맡는 일
섹션 제목: “두 계층이 맡는 일”각 LettuceNearCache는 프로세스 안의 Caffeine L1과 여러 프로세스가 공유하는 Redis L2를 묶습니다. 읽을 때 L1을 먼저 보고, miss이면 Redis에서 읽어 L1을 채웁니다. 쓸 때는 Redis에 먼저 저장한 뒤 L1을 갱신합니다.
Hibernate SessionFactory └─ LettuceNearCacheRegionFactory ├─ entity Region ─ Caffeine L1 + Redis L2 ├─ collection Region ─ Caffeine L1 + Redis L2 └─ query Region ─ Caffeine L1 + Redis L2Redis 쓰기가 실패하면 LettuceNearCache.put은 L1을 갱신하기 전에 예외를 던집니다. StorageAccess는 그 예외를 경고로 바꾸므로 database transaction은 계속되지만 cache put은 완료되지 않습니다.
Region당 인스턴스 하나
섹션 제목: “Region당 인스턴스 하나”LettuceNearCacheRegionFactory는 ConcurrentHashMap.computeIfAbsent로 같은 Region의 cache를 재사용합니다. entity와 collection access가 같은 Region을 여러 번 요청해도 Redis connection과 Caffeine cache를 중복으로 만들지 않습니다.
val nearCache = caches.computeIfAbsent(regionName) { LettuceNearCache(client, codec, properties.buildNearCacheConfig(regionName))}getCaches()는 Metrics와 Actuator가 읽을 수 있도록 현재 Region map을 반환하지만 수정 불가능한 view입니다. 애플리케이션이 여기에 entry를 추가하거나 제거해 수명주기를 우회할 수 없습니다.
Redis key 공간
섹션 제목: “Redis key 공간”Near Cache는 Redis key 앞에 {regionName}:을 붙입니다. Hibernate key 자체는 StorageAccess가 hck2:<SHA-256 digest>로 바꾼 뒤 전달하므로 실제 key는 다음 형태입니다.
io.example.Product:hck2:K3...digestRegion 전체 제거는 FLUSHDB가 아니라 ${regionName}:*를 SCAN하고 UNLINK합니다. 다른 Region과 같은 Redis database를 쓰더라도 해당 prefix 밖의 key는 지우지 않습니다.
1차 캐시와 혼동하지 않기
섹션 제목: “1차 캐시와 혼동하지 않기”Hibernate Session의 persistence context가 1차 캐시입니다. 같은 Session에서 entity를 두 번 찾았을 때 SQL이 한 번만 실행되는 결과만으로 Lettuce 2차 캐시가 동작한다고 판단할 수 없습니다.
repeat(2) { sessionFactory.openSession().use { session -> session.beginTransaction() checkNotNull(session.find(Product::class.java, id)) session.transaction.commit() }}새 Session에서 반복하고 secondLevelCacheHitCount를 확인해야 2차 캐시를 검증할 수 있습니다.