Redis叢集下過期key監聽的實現程式碼
阿新 • • 發佈:2020-01-09
1. 前言
在使用redis叢集時,發現過期key始終監聽不到。網上也沒有現成的解決方案。於是想,既然不能監聽叢集,那我可以建立多個redis連線,分別對每個redis的key過期進行監聽。以上做法可能不盡人意,目前也沒找到好的解決方案,如果有好的想法,請留言告知哦!不多說,直接貼我自己的程式碼!
2. 程式碼實現
關於Redis叢集配置程式碼此處不貼,直接貼配置監聽類程式碼!
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 監聽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過期監聽,建立多個連線,對每個redis節點進行監聽 @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過期監聽 **/ 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) { // 使用者做自己的業務處理即可,message.toString()可以獲取失效的key String mesg = message.toString(); } }
3. Redis防止過期key重複監聽
對於專案叢集情況下,部署多個服務後,容易出現redis過期被多個服務同時監聽到,從而執行相同的業務邏輯,這不是我們期望的。單機部署下方法的同步可以採用synchronize關鍵字。但叢集下,就得采用分散式鎖。在需要加鎖的地方,只要加鎖和解鎖即可。此處正好寫到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就設定value private static final String SET_WITH_EXPIRE_TIME = "PX"; // PX表示毫秒 // 加鎖 public String tryLock(String key,Long acquireTimeout) { // 生成隨機value String identifierValue = UUID.randomUUID().toString(); // 設定超時時間 Long endTime = System.currentTimeMillis() + acquireTimeout; // 迴圈獲取鎖 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. 總結
自己實現的一個小demo,廢話比較少。小白自己寫的配置類,理解有問題請留言!自己實現的方案感覺不妥,只是基本完成需求,還得繼續研究。
以上所述是小編給大家介紹的Redis叢集下過期key監聽的實現程式碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!