[Spring Boot] Redis Key Expired Event
Redis에서 TTL 설정 된 key에 대해 expire 될 때 이벤트를 받을 필요가 생겨 리서치를 진행 했다. Reids 버전 언제부터인지는 모르겠지만 아래 redis.conf를 보니 key expired 이벤트를 받을 수 있도록 되어 있었다.
출처 : https://github.com/redis/redis/blob/unstable/redis.conf
expired 이벤트는 disabled가 default라 아래처럼 redis node에서 따로 설정을 해 줘야 한다.
$> config set notify-keyspace-events Ex
note) 맨 뒤 Ex는 위 redis.conf에 있는 E : Keyevent events / x : Expired events 두 개를 사용하겠다는 의미.
Redis 서버에 셋팅 후 Spring Boot에서 이벤트를 받아 보기 위해 코드를 작성했는데 두 가지가 가능 했다. 첫째로 Redis의 KeyExpirationEventMessageListener와 Spring Boot EventListener를 활용하는 방법과 두번째는 그냥 Redis의 MessageListener를 구현하는 방법이다.
1) Spring EventListner
RedisKeyExpiredEvent를 받는 리스너를 만들어 준다.
@Component public class MyRedisKyeExpiredSpringListener { @EventListener public void expiredKey(RedisKeyExpiredEvent event) { System.out.println("=========== spring listener ==========="); System.out.println("event : " + event); System.out.println("event varlue : " + event.getValue()); System.out.println("======================================="); } }
그리고 기존 Redis 설정 부분에 KeyExpirationEventMessageListener를 bean으로 등록만 해 주면 RedisMessageListenerContainer에 알아서 추가가 된다.
@Bean public KeyExpirationEventMessageListener keyExpirationEventMessageListener() { return new KeyExpirationEventMessageListener(redisMessageListenerContainer()); }
redis-cli로 3초 TTL key를 만들어 보면,
127.0.0.1:6379> set mykey "test" ex 3
3초 뒤 Redis expired 이벤트가 수신되고 ApplicationEventPublisher를 통해 @EventListner로 전달 되는걸 볼 수 있다.
2) MessageListener Override
아래처럼 MessageListener를 구현하고,
@RequiredArgsConstructor public class MyRedisListener implements MessageListener { @Override public void onMessage(final Message message, final byte[] pattern) { System.out.println("================== normal ===================="); System.out.println("message : " + message); System.out.println("message channel : " + message.getChannel()); System.out.println("message channel str : " + new String(message.getChannel())); System.out.println("message body : " + message.getBody()); System.out.println("message body str : " + new String(message.getBody())); System.out.println("pattern : " + pattern); System.out.println("pattern str : " + new String(pattern)); System.out.println("=============================================="); } }
Redis 기존 설정에 adapter와 container 설정을 추가해 주면 1과 마찬가지로 해당 이벤트를 받아 볼 수 있다.
public static final String EXPIRED_PATTERN = "__key*__:expired"; @Bean public MessageListenerAdapter messageListenerAdapter() { return new MessageListenerAdapter(new MyRedisListener()); } @Bean public RedisMessageListenerContainer redisMessageListenerContainer() { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(redisConnectionFactory()); container.addMessageListener(messageListenerAdapter(), new PatternTopic(EXPIRED_PATTERN)); return container; }
참고로 keyspace 와 keyevent라는 용어가 좀 헷갈려 Redis 공식 문서를 참고해 보았다.
- keyspace : key에 대한 event를 수신
- keyevent : event에 대한 key를 수신
무슨 말인지 더 알기 어려운데 공식 문서의 내용을 가져와 보면
PUBLISH __keyspace@0__:mykey del PUBLISH __keyevent@0__:del mykey
위와 같이 keyspace는 이벤트인 del이 수신되고 keyevent는 mykey가 수신이 된다. Redis에서 받은 expired 이벤트의 내용을 로그로 출력해 보면 더 이해가 쉬울 것이다. 기억 해 둘만한 것은 key에 대한 value는 받지 못한다는 점.
AWS ElastiCache에도 같은 방법이니 참고 해 보자.
출처 : https://aws.amazon.com/ko/premiumsupport/knowledge-center/elasticache-redis-keyspace-notifications/
댓글
댓글 쓰기