ElastiCache에서 @Indexed 사용 시 TTL 문제 해결 방법

일단 해볼게·2025년 11월 7일
0

Springboot

목록 보기
27/27

문제 상황

사내에서 AWS ElastiCache를 사용하면서 @Indexed 어노테이션을 이용했는데 key에 맞는 value는 TTL을 이용해 삭제가 되었으나 key에 맞는 보조 인덱스를 저장하는 Set은 삭제되지 않아 ElastiCache 용량이 가득차는 문제가 생겼다.

  • @Index 어노테이션 : 지정된 필드 값을 기준으로 보조 인덱스를 생성하여, 마치 JPA에서 파생 쿼리 메서드를 쓰듯 findBy() 형태의 조회를 가능하게 해준다.

해결 방안

  • Spring Data Redis의 Keyspace Notifications 기능을 이용해 엔티티 키의 TTL이 만료되는 순간 이벤트를 받아서 보조 인덱스를 삭제한다.
@Configuration
@EnableRedisRepositories(
        enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP,
)
public class RedisConfig {}

enableKeyspaceEvents을 ON_STARTUP으로 설정하면 애플리케이션이 시작할 때 TTL 만료 이벤트를 받아서 삭제할 수 있다.

또한 ElastiCache가 이벤트를 수신할 수 있도록 notify-keyspace-events 옵션을 활성화 시킨다. 참고 링크

해당 방법을 사용해도 오류가 발생했다.

Caused by: org.springframework.data.redis.RedisSystemException: Error in execution;
nested exception is io.lettuce.core.RedisCommandExecutionException: ERR unknown command `CONFIG`, with args beginning with: `GET`, `notify-keyspace-events`

그러나 ElastiCache에서는 자체적으로 CONFIG 명령어를 허용하지 않았다. 참고 링크

해당 문제를 해결하기 위해 구글링을 해보니 keyspaceNotificationsConfigParameter 옵션을 추가하면 해결된다고 한다.

@Configuration
@EnableRedisRepositories(
        enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP,
        keyspaceNotificationsConfigParameter = "" // 핵심!
)
public class RedisConfig {}

해당 옵션을 추가해서 보조 인덱스의 TTL 설정이 동작하는 것을 확인했다!

무슨 이유 때문에 그러는지 궁금해서 찾아보니 RedisKeyValueAdapter의 코드에서

private @Nullable String keyspaceNotificationsConfigParameter = null;

Nullable 이었다. 그 중 initKeyExpirationListener() 메서드에서 setKeyspaceNotificationsConfigParameter 할 때 null 값이라 에러가 발생했다.

null이 아닐 때 상세 동작은 다음과 같다.

private void initKeyExpirationListener() {

		if (this.expirationListener.get() == null) {

			MappingExpirationListener listener = new MappingExpirationListener(this.messageListenerContainer, this.redisOps,
					this.converter);
			listener.setKeyspaceNotificationsConfigParameter(keyspaceNotificationsConfigParameter);

			if (this.eventPublisher != null) {
				listener.setApplicationEventPublisher(this.eventPublisher);
			}

			if (this.expirationListener.compareAndSet(null, listener)) {
				listener.init();
			}
		}
public void setKeyspaceNotificationsConfigParameter(String keyspaceNotificationsConfigParameter) {
		this.keyspaceNotificationsConfigParameter = keyspaceNotificationsConfigParameter;
	}

참고

https://devpro.kr/posts/Spring-Data-Redis-@Indexed-어노테이션-사용-주의-사항과-문제-해결-방법/

https://zorba91.tistory.com/354

profile
시도하고 More Do하는 백엔드 개발자입니다.

0개의 댓글