Redis集群下過(guò)期key監(jiān)聽的實(shí)現(xiàn)代碼
1. 前言
在使用redis集群時(shí),發(fā)現(xiàn)過(guò)期key始終監(jiān)聽不到。網(wǎng)上也沒有現(xiàn)成的解決方案。于是想,既然不能監(jiān)聽集群,那我可以建立多個(gè)redis連接,分別對(duì)每個(gè)redis的key過(guò)期進(jìn)行監(jiān)聽。以上做法可能不盡人意,目前也沒找到好的解決方案,如果有好的想法,請(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)的方案感覺不妥,只是基本完成需求,還得繼續(xù)研究。
以上所述是小編給大家介紹的Redis集群下過(guò)期key監(jiān)聽的實(shí)現(xiàn)代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
- spring boot+redis 監(jiān)聽過(guò)期Key的操作方法
- redis監(jiān)聽key過(guò)期事件的詳細(xì)步驟
- Redis設(shè)置key的過(guò)期時(shí)間
- Redis監(jiān)聽過(guò)期的key實(shí)現(xiàn)流程詳解
- Redis刪除過(guò)期key策略詳解
- redis?key鍵過(guò)期刪除策略及淘汰機(jī)制探究
- redis key過(guò)期監(jiān)聽的實(shí)現(xiàn)示例
- Redis Key過(guò)期監(jiān)聽的配置詳解
- Redis?key的過(guò)期時(shí)間和永久有效的實(shí)現(xiàn)
- Redis中key過(guò)期策略的實(shí)現(xià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 類的一個(gè)方法,本文主要介紹了RedisTemplate中boundHashOps的使用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04redis實(shí)現(xiàn)簡(jiǎn)單分布式鎖
這篇文章主要介紹了redis實(shí)現(xiàn)簡(jiǎn)單分布式鎖,文中通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2013-09-09Redis實(shí)現(xiàn)用戶關(guān)注的項(xiàng)目實(shí)踐
本文主要介紹了Redis實(shí)現(xiàn)用戶關(guān)注的項(xiàng)目實(shí)踐,通過(guò)使用Redis的set數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)關(guān)注對(duì)象,方便高效地進(jìn)行添加和取消關(guān)注操作,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02基于redis實(shí)現(xiàn)定時(shí)任務(wù)的方法詳解
這篇文章主要給大家介紹了基于redis實(shí)現(xiàn)定時(shí)任務(wù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08springboot +redis 實(shí)現(xiàn)點(diǎn)贊、瀏覽、收藏、評(píng)論等數(shù)量的增減操作
這篇文章主要介紹了springboot +redis 實(shí)現(xiàn)點(diǎn)贊、瀏覽、收藏、評(píng)論等數(shù)量的增減操作,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Redis底層數(shù)據(jù)結(jié)構(gòu)SkipList的實(shí)現(xiàn)
本文主要介紹了Redis底層數(shù)據(jù)結(jié)構(gòu)SkipList的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05