欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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,废话比较少。小白自己写的配置类,理解有问题请留言!自己实现的方案感觉不妥,只是基本完成需求,还得继续研究。