1. 前言
在使用redis集群時(shí),發(fā)現(xiàn)過(guò)期key始終監(jiān)聽不到。網(wǎng)上也沒(méi)有現(xiàn)成的解決方案。于是想,既然不能監(jiān)聽集群,那我可以建立多個(gè)redis連接,分別對(duì)每個(gè)redis的key過(guò)期進(jìn)行監(jiān)聽。以上做法可能不盡人意,目前也沒(méi)找到好的解決方案,如果有好的想法,請(qǐng)留言告知哦!不多說(shuō),直接貼我自己的代碼!
2. 代碼實(shí)現(xiàn)
關(guān)于Redis集群配置代碼此處不貼,直接貼配置監(jiān)聽類代碼!
redis.host1: 10.113.56.68
redis.port1: 7030
redis.host2: 10.113.56.68
redis.port2: 7031
redis.host3: 10.113.56.68
redis.port3: 7032
redis.host4: 10.113.56.68
redis.port4: 7033
redis.host5: 10.113.56.68
redis.port5: 7034
redis.host6: 10.113.56.68
redis.port6: 7035
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Arrays;
/**
* @Author xiabing5
* @Create 2019/8/6 14:46
* @Desc 監(jiān)聽redis中Key過(guò)期事件
**/
@Configuration
public class RedisListenerConfig {
@Value("${redis.host1}")
private String host1;
@Value("${redis.host2}")
private String host2;
@Value("${redis.host3}")
private String host3;
@Value("${redis.host4}")
private String host4;
@Value("${redis.host5}")
private String host5;
@Value("${redis.host6}")
private String host6;
@Value("${redis.port1}")
private int port1;
@Value("${redis.port2}")
private int port2;
@Value("${redis.port3}")
private int port3;
@Value("${redis.port4}")
private int port4;
@Value("${redis.port5}")
private int port5;
@Value("${redis.port6}")
private int port6;
@Bean
JedisPoolConfig jedisPoolConfig(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(100);
jedisPoolConfig.setMaxWaitMillis(1000);
return jedisPoolConfig;
}
// redis-cluster不支持key過(guò)期監(jiān)聽,建立多個(gè)連接,對(duì)每個(gè)redis節(jié)點(diǎn)進(jìn)行監(jiān)聽
@Bean
RedisMessageListenerContainer redisContainer1() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host1);
jedisConnectionFactory.setPort(port1);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
@Bean
RedisMessageListenerContainer redisContainer2() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host2);
jedisConnectionFactory.setPort(port2);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
@Bean
RedisMessageListenerContainer redisContainer3() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host3);
jedisConnectionFactory.setPort(port3);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
@Bean
RedisMessageListenerContainer redisContainer4() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host4);
jedisConnectionFactory.setPort(port4);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
@Bean
RedisMessageListenerContainer redisContainer5() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host5);
jedisConnectionFactory.setPort(port5);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
@Bean
RedisMessageListenerContainer redisContainer6() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host6);
jedisConnectionFactory.setPort(port6);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
jedisConnectionFactory.afterPropertiesSet();
container.setConnectionFactory(jedisConnectionFactory);
return container;
}
@Bean
RedisKeyExpirationListener redisKeyExpirationListener1() {
return new RedisKeyExpirationListener(redisContainer1());
}
@Bean
RedisKeyExpirationListener redisKeyExpirationListener2() {
return new RedisKeyExpirationListener(redisContainer2());
}
@Bean
RedisKeyExpirationListener redisKeyExpirationListener3() {
return new RedisKeyExpirationListener(redisContainer3());
}
@Bean
RedisKeyExpirationListener redisKeyExpirationListener4() {
return new RedisKeyExpirationListener(redisContainer4());
}
@Bean
RedisKeyExpirationListener redisKeyExpirationListener5() {
return new RedisKeyExpirationListener(redisContainer5());
}
@Bean
RedisKeyExpirationListener redisKeyExpirationListener6() {
return new RedisKeyExpirationListener(redisContainer6());
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import java.util.Date;
/**
* @Author xiabing5
* @Create 2019/9/4 9:47
* @Desc redis過(guò)期監(jiān)聽
**/
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
@Autowired
RedisUtil redisUtil;
@Autowired
LoginUserStatisticsMapper loginUserStatisticsMapper;
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
// 用戶做自己的業(yè)務(wù)處理即可,message.toString()可以獲取失效的key
String mesg = message.toString();
}
}
3. Redis防止過(guò)期key重復(fù)監(jiān)聽
對(duì)于項(xiàng)目集群情況下,部署多個(gè)服務(wù)后,容易出現(xiàn)redis過(guò)期被多個(gè)服務(wù)同時(shí)監(jiān)聽到,從而執(zhí)行相同的業(yè)務(wù)邏輯,這不是我們期望的。單機(jī)部署下方法的同步可以采用synchronize關(guān)鍵字。但集群下,就得采用分布式鎖。在需要加鎖的地方,只要加鎖和解鎖即可。此處正好寫到Redis,那就貼一個(gè)自己用的redis分布式鎖。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import java.util.Collections;
import java.util.UUID;
/**
* @Author xiabing5
* @Create 2019/9/6 15:54
* @Desc redis分布式鎖
**/
@Component
public class RedisLock {
@Autowired
Jedis jedis;
private static final String SET_IF_NOT_EXIST = "NX"; // NX表示如果不存在key就設(shè)置value
private static final String SET_WITH_EXPIRE_TIME = "PX"; // PX表示毫秒
// 加鎖
public String tryLock(String key,Long acquireTimeout) {
// 生成隨機(jī)value
String identifierValue = UUID.randomUUID().toString();
// 設(shè)置超時(shí)時(shí)間
Long endTime = System.currentTimeMillis() + acquireTimeout;
// 循環(huán)獲取鎖
while (System.currentTimeMillis() endTime) {
String result = jedis.set(key,identifierValue, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, acquireTimeout);
if("OK".equals(result)) {
return identifierValue;
}
}
return null;
}
// 解鎖
// public void delLock(String key,String identifierValue) {
// // 判斷是否是同一把鎖
// try{
// if(jedis.get(key).equals(identifierValue)){
// // 此處操作非原子性,容易造成釋放非自己的鎖
// jedis.del(key);
// }
// }catch(Exception e) {
// e.printStackTrace();
// }
// }
// 使用Lua代碼解鎖
public void delLock(String key,String identifierValue) {
try{
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Long result = (Long) jedis.eval(script, Collections.singletonList(key), Collections.singletonList(identifierValue));
if (1 == result) {
System.out.println(result+"釋放鎖成功");
} if (0 == result) {
System.out.println(result+"釋放鎖失敗");
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
4. 總結(jié)
自己實(shí)現(xiàn)的一個(gè)小demo,廢話比較少。小白自己寫的配置類,理解有問(wèn)題請(qǐng)留言!自己實(shí)現(xiàn)的方案感覺(jué)不妥,只是基本完成需求,還得繼續(xù)研究。
以上所述是小編給大家介紹的Redis集群下過(guò)期key監(jiān)聽的實(shí)現(xiàn)代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
您可能感興趣的文章:- 基于docker搭建redis集群的方法
- Docker 部署單機(jī)版 Pulsar 和集群架構(gòu) Redis(開發(fā)神器)的方法
- Redis Cluster集群數(shù)據(jù)分片機(jī)制原理
- springcloud微服務(wù)基于redis集群的單點(diǎn)登錄實(shí)現(xiàn)解析
- springboot整合redis集群過(guò)程解析
- Java調(diào)用Redis集群代碼及問(wèn)題解決
- Linux(Centos7)下redis5集群搭建和使用說(shuō)明詳解
- 基于docker搭建redis-sentinel集群的方法示例
- 詳細(xì)分析Redis集群故障
- 比較幾種Redis集群方案