Redis CacheManager가 두 개일 때 애플리케이션이 시작되지 않은 이유

여러 CacheManager 중 기본 대상을 정하거나 캐시별 관리자를 명시하는 방법

Redis 캐시 설정을 바꾼 뒤 애플리케이션을 실행했더니 시작 단계에서 멈췄다. 로그에는 No CacheResolver specified, and no unique bean of type CacheManager found라는 메시지가 남았다. 캐시 설정을 하나 더 추가했을 뿐인데 왜 기동 자체가 실패하는지 처음엔 바로 이해되지 않았다.

원인은 Spring이 기본 캐시 처리에 사용할 CacheManager를 하나로 결정할 수 없다는 것이었다. 당시에는 서로 다른 설정이 필요한 서비스를 위해 Redis 설정 안에 관리자를 하나 더 등록했다. 두 빈 모두 정상적으로 만들어졌지만, 캐시 애노테이션에서 관리자를 지정하지 않은 호출은 어느 쪽을 써야 할지 모호해졌다.

@Primary는 기본 선택을 정한다

그때 적용한 해결은 두 빈 가운데 기본으로 사용할 하나에 @Primary를 붙이는 것이었다.

@Bean
@Primary
RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
    // 기본 캐시 설정
}

@Primary는 후보가 여러 개일 때 단일 기본 주입 대상을 표시한다. 따라서 모든 캐시가 같은 정책을 따라도 되는 상황이라면 빠르고 유효한 해결이다. 다만 어떤 캐시를 사용할지 정하는 정책 자체가 없어지는 것은 아니다. 기본값을 지정해 둔 것뿐이므로, 서비스마다 다른 저장소나 TTL을 의도했다면 호출 지점도 분명하게 표현해야 한다.

@Cacheable(cacheNames = "catalog", cacheManager = "catalogCacheManager")
public Catalog findCatalog(UUID id) {
    // ...
}

캐시 이름에 따라 관리자를 동적으로 고르는 정책이 필요하면 CacheResolver를 둘 수 있다. Spring은 애노테이션의 cacheManager 속성으로 사용할 관리자를 지정하거나, cacheResolver로 해석 정책을 제공하는 선택지를 지원한다.

관리자를 늘리기 전에 캐시 정책부터 나눈다

돌아보면 CacheManager 빈을 추가하는 것이 항상 첫 선택일 필요는 없다. 한 Redis 안에서 캐시마다 만료 시간이나 직렬화 정책만 다르게 하려는 경우라면, 단일 RedisCacheManager에 여러 캐시별 설정을 두는 편이 운영 대상을 덜 늘릴 수 있다. 저장소가 실제로 다르거나 장애 격리·접근 정책까지 나눠야 한다면 별도 관리자가 더 적절할 수 있다.

여러 저장소를 하나의 추상화로 연결하는 CompositeCacheManager도 있지만, 이것은 캐시 이름을 어느 관리자가 처리하는지 순서와 fallback 동작까지 확인해야 한다. 이름이 겹치거나 fallback이 의도치 않게 동작하면 값이 예상과 다른 저장소에 들어갈 수 있다.

확인 순서는 간단하게 잡을 수 있다.

  1. 현재 등록된 CacheManager 빈의 이름과 설정을 확인한다.
  2. 캐시마다 저장소만 다른지, TTL·직렬화만 다른지 구분한다.
  3. 공통 기본값이 필요한 애노테이션은 @Primary 또는 기본 resolver로 정한다.
  4. 특정 저장소가 필요한 메서드에는 cacheManager를 명시한다.
  5. 실제 Redis 키와 TTL이 의도한 저장소·정책에 맞는지 통합 테스트한다.

이 오류는 캐시가 고장났다는 뜻이 아니었다. 애플리케이션이 모호한 선택을 조용히 하지 않고 시작 단계에서 알려준 것이다. @Primary로 빠르게 해결한 경험은 유효했지만, 지금은 “기본 캐시”와 “의도적으로 고른 캐시”를 구분해서 설정하는 편이 더 안전하다고 본다. 만료와 무효화 정책은 공지 조회에 Redis 캐시를 적용한 기록에도 정리했다.

참고 문서: Spring의 @Primary 선택 규칙, Spring 캐시 애노테이션의 관리자 선택, CompositeCacheManager 설정

당시 기록: RedisConfig의 복수 CacheManager 문제