Redis에서 만료된 키를 수신하거나 subscribe 하는 방법을 알아보다가 Redis에서 알림 이벤트를 발견하였습니다.
만료된 키에 대한 Redis Keyspace 알림에 대해 알아보겠습니다.
우선 redis.conf를 사용하여 keyspace 알림을 활성화하겠습니다.
/etc 하위에 존재하는 redis.conf에 notify-keyspace-events Ex를 추가합니다.
이벤트 종류
- K Keyspace events, publish prefix "__keyspace@<db>__:".
- E Keyevent events, publish prefix "__keyevent@<db>__:".
- g 공통 명령: del, expire, rename, ...
- $ 스트링(String) 명령
- l 리스트(List) 명령
- s 셋(Set) 명령
- h 해시(Hash) 명령
- z 소트 셋(Sorted set) 명령
- x 만료(Expired) 이벤트 (키가 만료될 때마다 생성되는 이벤트)
- e 퇴출(Evicted) 이벤트 (최대메모리 정책으로 키가 삭제될 때 생성되는 이벤트)
- A 모든 이벤트(g$lshzxe), "AKE"로 지정하면 모든 이벤트를 받는다.
AWS의 Elasticache를 사용한다면 https://aws.amazon.com/ko/premiumsupport/knowledge-center/elasticache-redis-keyspace-notifications/ 를 참조하여 Ex 값을 넣어주세요.
redis 재시작
$ sudo systemctl restart redis
설정을 완료하였으니 기능이 잘 작동하는지 테스트해보겠습니다.
만료된 이벤트에 대한 subscribe를 추가합니다.
만료 시간을 5초로 설정하고 값을 설정해보겠습니다.
5초 후
pom.xml에 dependency를 추가합니다.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
RedisListenerConfiguration.java
@Configuration
public class RedisListenerConfiguration {
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
return redisMessageListenerContainer;
}
}
RedisKeyExpiredListener.java
@Component
public class RedisKeyExpiredListener extends KeyExpirationEventMessageListener {
/**
* Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
*
* @param listenerContainer must not be {@literal null}.
*/
public RedisKeyExpiredListener(@Qualifier("redisMessageListenerContainer") RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
*
* @param message redis key
* @param pattern __keyevent@*__:expired
*/
@Override
public void onMessage(Message message, byte[] pattern) {
System.out.println("########## onMessage pattern " + new String(pattern) + " | " + message.toString());
}
}
5초 후
기본적으로 expired 이벤트는 레디스 서버가 키를 삭제할 때 발생되는 이벤트고, 이론적으로 TTL이 0으로 도달했을 때는 발생하지 않습니다.
만약 강제로 expired 이벤트를 실행하고 싶다면 ttl을 1로 설정하시면 됩니다.
redisCommands.expire(key, 1);
RedisCommandExecutionException: ERR unknown command `CONFIG`, with args beginning with: `SET`, `notify-keyspace-events`, `Ex`
위 오류 발생시 해결방법
1.
@Bean
public ConfigureRedisAction configureRedisAction(){
return ConfigureRedisAction.NO_OP;
}
2.
/**
* Elastic Cache 사용을 위한 KeyspaceEventMessageListener 커스텀 클래스
* - config command 사용 방지.
* - Elastic Cache 에서 사용할 수 없는 command. https://docs.amazonaws.cn/en_us/AmazonElastiCache/latest/red-ug/RestrictedCommands.html
*
*/
@Slf4j
public abstract class CustomKeyspaceEventMessageListener implements MessageListener, InitializingBean, DisposableBean {
/**
* Initialize the message listener by writing requried redis config for {@literal notify-keyspace-events} and
* registering the listener within the container.
*/
public void init() {
if (StringUtils.hasText(keyspaceNotificationsConfigParameter)) {
RedisConnection connection = listenerContainer.getConnectionFactory().getConnection();
try {
// ## Elastic Cache에서 https://docs.amazonaws.cn/en_us/AmazonElastiCache/latest/red-ug/RestrictedCommands.html 정책으로 config command 사용 불가. Sass parameter group에 설정된 값 사용
// Properties config = connection.getConfig("notify-keyspace-events");
// log.info("### notify-keyspace-events : {}", config.getProperty("notify-keyspace-events"));
//
// if (!StringUtils.hasText(config.getProperty("notify-keyspace-events"))) {
// connection.setConfig("notify-keyspace-events", keyspaceNotificationsConfigParameter);
// }
log.info("### Skip redis 'config' command because of not supporting on elastic cache(AWS. restriction command) ###");
} finally {
connection.close();
}
}
doRegister(listenerContainer);
}
// 나머지는 KeyspaceEventMessageListener와 동일
}
/**
* Elastic Cache 사용을 위한 KeyspaceEventMessageListener 커스텀 클래스
*
*/
public class CustomKeyExpirationEventMessageListener extends CustomKeyspaceEventMessageListener implements ApplicationEventPublisherAware {
// KeyExpirationEventMessageListener과 동일
}
@Component
public class RedisKeyExpiredListener extends CustomKeyExpirationEventMessageListener {
// KeyExpirationEventMessageListener 대신 CustomKeyExpirationEventMessageListener 상속
}
[Reference]
sauravomar01.medium.com/redis-keyspace-notifications-for-expired-keys-f38c18484a89
'redis' 카테고리의 다른 글
[Spring] redis keys 대신 scan (0) | 2022.06.29 |
---|---|
[SpringBoot2] Lettuce Java Redis Client와 RedisCommands method 설명 (0) | 2021.01.16 |
댓글