1. 前言
在使用redis集群時,發現過期key始終監聽不到。網上也沒有現成的解決方案。于是想,既然不能監聽集群,那我可以建立多個redis連接,分別對每個redis的key過期進行監聽。以上做法可能不盡人意,目前也沒找到好的解決方案,如果有好的想法,請留言告知哦!不多說,直接貼我自己的代碼!
2. 代碼實現
關于Redis集群配置代碼此處不貼,直接貼配置監聽類代碼!
1
2
3
4
5
6
7
8
9
10
11
12
|
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 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
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()); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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分布式鎖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
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監聽的實現代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!
原文鏈接:https://www.cnblogs.com/xiaobingblog/archive/2019/09/09/11490726.html