Redis集群下过期key监听
程序员文章站
2022-03-25 22:45:50
1. 前言 在使用redis集群时,发现过期key始终监听不到。网上也没有现成的解决方案。于是想,既然不能监听集群,那我可以建立多个redis连接,分别对每个redis的key过期进行监听。以上做法可能不尽人意,目前也没找到好的解决方案,如果有好的想法,请留言告知哦!不多说,直接贴我自己的代码! 2 ......
1. 前言
在使用redis集群时,发现过期key始终监听不到。网上也没有现成的解决方案。于是想,既然不能监听集群,那我可以建立多个redis连接,分别对每个redis的key过期进行监听。以上做法可能不尽人意,目前也没找到好的解决方案,如果有好的想法,请留言告知哦!不多说,直接贴我自己的代码!
2. 代码实现
关于redis集群配置代码此处不贴,直接贴配置监听类代码!
1 redis.host1: 10.113.56.68 2 redis.port1: 7030 3 redis.host2: 10.113.56.68 4 redis.port2: 7031 5 redis.host3: 10.113.56.68 6 redis.port3: 7032 7 redis.host4: 10.113.56.68 8 redis.port4: 7033 9 redis.host5: 10.113.56.68 10 redis.port5: 7034 11 redis.host6: 10.113.56.68 12 redis.port6: 7035
1 import org.springframework.beans.factory.annotation.value; 2 import org.springframework.cache.cachemanager; 3 import org.springframework.context.annotation.bean; 4 import org.springframework.context.annotation.configuration; 5 import org.springframework.data.redis.cache.rediscachemanager; 6 import org.springframework.data.redis.connection.redisclusterconfiguration; 7 import org.springframework.data.redis.connection.jedis.jedisconnectionfactory; 8 import org.springframework.data.redis.core.redistemplate; 9 import org.springframework.data.redis.listener.redismessagelistenercontainer; 10 import org.springframework.data.redis.serializer.stringredisserializer; 11 import redis.clients.jedis.jedis; 12 import redis.clients.jedis.jedispoolconfig; 13 14 import java.util.arrays; 15 16 /** 17 * @author xiabing5 18 * @create 2019/8/6 14:46 19 * @desc 监听redis中key过期事件 20 **/ 21 @configuration 22 public class redislistenerconfig { 23 24 @value("${redis.host1}") 25 private string host1; 26 27 @value("${redis.host2}") 28 private string host2; 29 30 @value("${redis.host3}") 31 private string host3; 32 33 @value("${redis.host4}") 34 private string host4; 35 36 @value("${redis.host5}") 37 private string host5; 38 39 @value("${redis.host6}") 40 private string host6; 41 42 @value("${redis.port1}") 43 private int port1; 44 45 @value("${redis.port2}") 46 private int port2; 47 48 @value("${redis.port3}") 49 private int port3; 50 51 @value("${redis.port4}") 52 private int port4; 53 54 @value("${redis.port5}") 55 private int port5; 56 57 @value("${redis.port6}") 58 private int port6; 59 60 @bean 61 jedispoolconfig jedispoolconfig(){ 62 jedispoolconfig jedispoolconfig = new jedispoolconfig(); 63 jedispoolconfig.setmaxidle(100); 64 jedispoolconfig.setmaxwaitmillis(1000); 65 return jedispoolconfig; 66 } 67 68 // redis-cluster不支持key过期监听,建立多个连接,对每个redis节点进行监听 69 @bean 70 redismessagelistenercontainer rediscontainer1() { 71 final redismessagelistenercontainer container = new redismessagelistenercontainer(); 72 jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(); 73 jedisconnectionfactory.sethostname(host1); 74 jedisconnectionfactory.setport(port1); 75 jedisconnectionfactory.setpoolconfig(jedispoolconfig()); 76 jedisconnectionfactory.afterpropertiesset(); 77 container.setconnectionfactory(jedisconnectionfactory); 78 return container; 79 } 80 81 @bean 82 redismessagelistenercontainer rediscontainer2() { 83 final redismessagelistenercontainer container = new redismessagelistenercontainer(); 84 jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(); 85 jedisconnectionfactory.sethostname(host2); 86 jedisconnectionfactory.setport(port2); 87 jedisconnectionfactory.setpoolconfig(jedispoolconfig()); 88 jedisconnectionfactory.afterpropertiesset(); 89 container.setconnectionfactory(jedisconnectionfactory); 90 return container; 91 } 92 93 @bean 94 redismessagelistenercontainer rediscontainer3() { 95 final redismessagelistenercontainer container = new redismessagelistenercontainer(); 96 jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(); 97 jedisconnectionfactory.sethostname(host3); 98 jedisconnectionfactory.setport(port3); 99 jedisconnectionfactory.setpoolconfig(jedispoolconfig()); 100 jedisconnectionfactory.afterpropertiesset(); 101 container.setconnectionfactory(jedisconnectionfactory); 102 return container; 103 } 104 105 @bean 106 redismessagelistenercontainer rediscontainer4() { 107 final redismessagelistenercontainer container = new redismessagelistenercontainer(); 108 jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(); 109 jedisconnectionfactory.sethostname(host4); 110 jedisconnectionfactory.setport(port4); 111 jedisconnectionfactory.setpoolconfig(jedispoolconfig()); 112 jedisconnectionfactory.afterpropertiesset(); 113 container.setconnectionfactory(jedisconnectionfactory); 114 return container; 115 } 116 117 @bean 118 redismessagelistenercontainer rediscontainer5() { 119 final redismessagelistenercontainer container = new redismessagelistenercontainer(); 120 jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(); 121 jedisconnectionfactory.sethostname(host5); 122 jedisconnectionfactory.setport(port5); 123 jedisconnectionfactory.setpoolconfig(jedispoolconfig()); 124 jedisconnectionfactory.afterpropertiesset(); 125 container.setconnectionfactory(jedisconnectionfactory); 126 return container; 127 } 128 129 @bean 130 redismessagelistenercontainer rediscontainer6() { 131 final redismessagelistenercontainer container = new redismessagelistenercontainer(); 132 jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(); 133 jedisconnectionfactory.sethostname(host6); 134 jedisconnectionfactory.setport(port6); 135 jedisconnectionfactory.setpoolconfig(jedispoolconfig()); 136 jedisconnectionfactory.afterpropertiesset(); 137 container.setconnectionfactory(jedisconnectionfactory); 138 return container; 139 } 140 141 @bean 142 rediskeyexpirationlistener rediskeyexpirationlistener1() { 143 return new rediskeyexpirationlistener(rediscontainer1()); 144 } 145 146 @bean 147 rediskeyexpirationlistener rediskeyexpirationlistener2() { 148 return new rediskeyexpirationlistener(rediscontainer2()); 149 } 150 151 @bean 152 rediskeyexpirationlistener rediskeyexpirationlistener3() { 153 return new rediskeyexpirationlistener(rediscontainer3()); 154 } 155 156 @bean 157 rediskeyexpirationlistener rediskeyexpirationlistener4() { 158 return new rediskeyexpirationlistener(rediscontainer4()); 159 } 160 161 @bean 162 rediskeyexpirationlistener rediskeyexpirationlistener5() { 163 return new rediskeyexpirationlistener(rediscontainer5()); 164 } 165 166 @bean 167 rediskeyexpirationlistener rediskeyexpirationlistener6() { 168 return new rediskeyexpirationlistener(rediscontainer6()); 169 } 170 171 }
1 import org.springframework.beans.factory.annotation.autowired; 2 import org.springframework.data.redis.connection.message; 3 import org.springframework.data.redis.listener.keyexpirationeventmessagelistener; 4 import org.springframework.data.redis.listener.redismessagelistenercontainer; 5 6 import java.util.date; 7 8 9 /** 10 * @author xiabing5 11 * @create 2019/9/4 9:47 12 * @desc redis过期监听 13 **/ 14 public class rediskeyexpirationlistener extends keyexpirationeventmessagelistener { 15 16 @autowired 17 redisutil redisutil; 18 19 @autowired 20 loginuserstatisticsmapper loginuserstatisticsmapper; 21 22 public rediskeyexpirationlistener(redismessagelistenercontainer listenercontainer) { 23 super(listenercontainer); 24 } 25 26 @override 27 public void onmessage(message message, byte[] pattern) { 28 // 用户做自己的业务处理即可,message.tostring()可以获取失效的key 29 string mesg = message.tostring(); 30 31 } 32 }
3. redis防止过期key重复监听
对于项目集群情况下,部署多个服务后,容易出现redis过期被多个服务同时监听到,从而执行相同的业务逻辑,这不是我们期望的。单机部署下方法的同步可以采用synchronize关键字。但集群下,就得采用分布式锁。在需要加锁的地方,只要加锁和解锁即可。此处正好写到redis,那就贴一个自己用的redis分布式锁。
1 import org.springframework.beans.factory.annotation.autowired; 2 import org.springframework.stereotype.component; 3 import redis.clients.jedis.jedis; 4 5 import java.util.collections; 6 import java.util.uuid; 7 8 /** 9 * @author xiabing5 10 * @create 2019/9/6 15:54 11 * @desc redis分布式锁 12 **/ 13 @component 14 public class redislock { 15 16 @autowired 17 jedis jedis; 18 19 private static final string set_if_not_exist = "nx"; // nx表示如果不存在key就设置value 20 private static final string set_with_expire_time = "px"; // px表示毫秒 21 22 // 加锁 23 public string trylock(string key,long acquiretimeout) { 24 // 生成随机value 25 string identifiervalue = uuid.randomuuid().tostring(); 26 // 设置超时时间 27 long endtime = system.currenttimemillis() + acquiretimeout; 28 // 循环获取锁 29 while (system.currenttimemillis() < endtime) { 30 string result = jedis.set(key,identifiervalue, set_if_not_exist, set_with_expire_time, acquiretimeout); 31 if("ok".equals(result)) { 32 return identifiervalue; 33 } 34 } 35 return null; 36 } 37 38 // 解锁 39 // public void dellock(string key,string identifiervalue) { 40 // // 判断是否是同一把锁 41 // try{ 42 // if(jedis.get(key).equals(identifiervalue)){ 43 // // 此处操作非原子性,容易造成释放非自己的锁 44 // jedis.del(key); 45 // } 46 // }catch(exception e) { 47 // e.printstacktrace(); 48 // } 49 // } 50 51 // 使用lua代码解锁 52 public void dellock(string key,string identifiervalue) { 53 try{ 54 string script = "if redis.call('get', keys[1]) == argv[1] then return redis.call('del', keys[1]) else return 0 end"; 55 long result = (long) jedis.eval(script, collections.singletonlist(key), collections.singletonlist(identifiervalue)); 56 if (1 == result) { 57 system.out.println(result+"释放锁成功"); 58 } if (0 == result) { 59 system.out.println(result+"释放锁失败"); 60 } 61 }catch (exception e) { 62 e.printstacktrace(); 63 } 64 } 65 66 }
4. 总结
自己实现的一个小demo,废话比较少。小白自己写的配置类,理解有问题请留言!自己实现的方案感觉不妥,只是基本完成需求,还得继续研究。
推荐阅读
-
Linux(Centos7)下redis5集群搭建和使用说明详解
-
Redis集群下过期key监听
-
python中redis查看剩余过期时间及用正则通配符批量删除key的方法
-
Linux(Centos7)下redis5集群搭建和使用
-
详解centos下搭建redis集群
-
Python操作Redis之设置key的过期时间实例代码
-
Redis集群模式下的redis-py-cluster方式读写测试
-
redis 对过期key监听处理
-
Linux(Centos7)下redis5集群搭建和使用说明详解
-
lua脚本在redis集群中执行报错--Lua script attempted to access a non local key in a cluster node...