Redis集群下過期key監(jiān)聽的實(shí)現(xiàn)代碼
1. 前言
在使用redis集群時,發(fā)現(xiàn)過期key始終監(jiān)聽不到。網(wǎng)上也沒有現(xiàn)成的解決方案。于是想,既然不能監(jiān)聽集群,那我可以建立多個redis連接,分別對每個redis的key過期進(jìn)行監(jiān)聽。以上做法可能不盡人意,目前也沒找到好的解決方案,如果有好的想法,請留言告知哦!不多說,直接貼我自己的代碼!
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過期事件 **/ @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過期監(jiān)聽,建立多個連接,對每個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過期監(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防止過期key重復(fù)監(jiān)聽
對于項目集群情況下,部署多個服務(wù)后,容易出現(xiàn)redis過期被多個服務(wù)同時監(jiān)聽到,從而執(zhí)行相同的業(yè)務(wù)邏輯,這不是我們期望的。單機(jī)部署下方法的同步可以采用synchronize關(guān)鍵字。但集群下,就得采用分布式鎖。在需要加鎖的地方,只要加鎖和解鎖即可。此處正好寫到Redis,那就貼一個自己用的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è)置超時時間 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)的一個小demo,廢話比較少。小白自己寫的配置類,理解有問題請留言!自己實(shí)現(xiàn)的方案感覺不妥,只是基本完成需求,還得繼續(xù)研究。
以上所述是小編給大家介紹的Redis集群下過期key監(jiān)聽的實(shí)現(xiàn)代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
Redis數(shù)據(jù)結(jié)構(gòu)之listpack和quicklist使用學(xué)習(xí)
這篇文章主要為大家介紹了Redis數(shù)據(jù)結(jié)構(gòu)之listpack和quicklist的使用學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07RedisTemplate中boundHashOps的使用小結(jié)
redisTemplate.boundHashOps(key)?是 RedisTemplate 類的一個方法,本文主要介紹了RedisTemplate中boundHashOps的使用小結(jié),具有一定的參考價值,感興趣的可以了解一下2024-04-04Redis實(shí)現(xiàn)用戶關(guān)注的項目實(shí)踐
本文主要介紹了Redis實(shí)現(xiàn)用戶關(guān)注的項目實(shí)踐,通過使用Redis的set數(shù)據(jù)結(jié)構(gòu)來存儲關(guān)注對象,方便高效地進(jìn)行添加和取消關(guān)注操作,具有一定的參考價值,感興趣的可以了解一下2024-02-02基于redis實(shí)現(xiàn)定時任務(wù)的方法詳解
這篇文章主要給大家介紹了基于redis實(shí)現(xiàn)定時任務(wù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08springboot +redis 實(shí)現(xiàn)點(diǎn)贊、瀏覽、收藏、評論等數(shù)量的增減操作
這篇文章主要介紹了springboot +redis 實(shí)現(xiàn)點(diǎn)贊、瀏覽、收藏、評論等數(shù)量的增減操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09Redis底層數(shù)據(jù)結(jié)構(gòu)SkipList的實(shí)現(xiàn)
本文主要介紹了Redis底層數(shù)據(jù)結(jié)構(gòu)SkipList的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05