redis sentinel模式 及idea 开发方式+redisson
此内容要在 前一篇 主从模式基础之上阅读
在主从模式的基础上增加 sentinel
主从模式的运行配置
conf配置文件
sentinel monitor mymaster 192.168.1.138 6385 2
192.168.1.138 6385 master
2 重新选举时达到数量
s1/sentinetl.conf
port 27001 sentinel announce-ip 192.168.1.138 sentinel monitor mymaster 192.168.1.138 6385 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 dir "/opt/module/redis-stack/s1"
s2/sentinetl.conf
port 27002 sentinel announce-ip 192.168.1.138 sentinel monitor mymaster 192.168.1.138 6385 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 dir "/opt/module/redis-stack/s2"
s3/sentinetl.conf
port 27003 sentinel announce-ip 192.168.1.138 sentinel monitor mymaster 192.168.1.138 6385 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 dir "/opt/module/redis-stack/s3"
执行命令启动sentinel
bin/redis-sentinel s1/sentinel.conf
Idea 中bean
下面连接的redis 是 sentinel的地址
@Component public class BeanRedisson { //sentinel 模式 @Bean public Redisson redisson() { List<String> sentinellist=new ArrayList<>(); sentinellist.add("redis://192.168.1.138:27001"); sentinellist.add("redis://192.168.1.138:27002"); sentinellist.add("redis://192.168.1.138:27003"); Config config=new Config(); config.useSentinelServers().setMasterName("mymaster").setDatabase(0).setSentinelAddresses(sentinellist); return (Redisson) Redisson.create(config); } }
yml
LETTUCE 的配置
redis: sentinel: master: mymaster nodes: - 192.168.1.138:27001 - 192.168.1.138:27002 - 192.168.1.138:27003
lettuce 读写分离
这个配置类会被执行 owerride原的操作
package com.hmdp.config; import io.lettuce.core.ReadFrom; import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; @Configuration public class LettuceConfig { /** * 定义这个bean 目的是让lettuce 优先在repliate节点读取数据 * @return */ @Bean public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer(){ return new LettuceClientConfigurationBuilderCustomizer() { @Override public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) { clientConfigurationBuilder.readFrom(ReadFrom.MASTER); System.out.println("lettuce read config is actived."); } }; } }
java
@RestController @RequestMapping("/stock") public class RedisLockTest { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private Redisson redisson; @RequestMapping("init") public Result addStock(@RequestParam("count") String count) { String tipmsg = ""; String stockkey = "stock:101"; synchronized (this) { //synchronized 单线程锁 不能解决分布式并发问题 if (StrUtil.isBlank(count)) count = "1000"; stringRedisTemplate.opsForValue().set(stockkey, count); String redisStock = stringRedisTemplate.opsForValue().get(stockkey); return Result.ok("库存初始化成功:" + redisStock); } } @RequestMapping("/substock") public Result substock() { String tipmsg = ""; String stockkey = "stock:101"; String stockLockkey = "stockLock:101"; String clientThreadID = UUID.randomUUID().toString().replace("-", "");//用于标识当前进程,redis 锁删除时判断是当前进程的锁 //synchronized (this){ //synchronized 单线程锁 不能解决分布式并发问题 // ctrl+alt +L 格式化代码 //利用 redisson 工具 创建一个锁对象 RLock redissonLock = redisson.getLock(stockLockkey); redissonLock.lock();//默认30s 每隔10秒检测一下主线程没有完成则续命锁 tryLockInnerAsync lua scripts try { //redis 分布式锁实现 //设置有效期 /* boolean isredisLock = stringRedisTemplate.opsForValue().setIfAbsent(stockLockkey,"stockLockValue", 10, TimeUnit.SECONDS);//redis setnx(key,value) if (!isredisLock) { return Result.fail(stockLockkey + "获取失败。"); }*/ String stock = stringRedisTemplate.opsForValue().get(stockkey); System.out.println(stockkey + "执行了。"); if (stock == "null" || StrUtil.isBlank(stock))//isEmpty() 只是对字符串长度为 0 进行判断,没有对null 进行判断,所以isEmpty()可能 有空指针的情况 { tipmsg = "当前库存记录不存在。key:" + stockkey; //return Result.fail(tipmsg); } else { int stockInt = Integer.parseInt(stock);//redis.get(stockkey) if (stockInt > 0) { int realStock = stockInt - 1; //redis 字符 串操作 所以key value都必须是string stringRedisTemplate.opsForValue().set(stockkey, StrUtil.toString(realStock));//jedis.set(key,value) tipmsg = "库存扣减成功,剩余库存:" + realStock; //return Result.ok(tipmsg); } else { tipmsg = "库存不足:" + stockkey; //return Result.fail(tipmsg); } } return Result.ok(tipmsg); } finally { //try catch 解决异常导致的死锁问题 /* if(clientThreadID.equals(stringRedisTemplate.opsForValue().get(stockLockkey))) {//判断是否为自已的锁 //删除redis 分步式锁 //TODO 但是此时如果锁的有效期 失效了。。此时再另有一个进程重新进行了加锁,那么此时删除的锁已经是别的锁了,因不自已的锁已经到期自动释放了 //TODO 这个问题可以通过 锁续命来解决 就是在主线程之外增加一个分线程,只要主线程不结束 就自动完成锁有效期的延长 redisson已经封装好了 stringRedisTemplate.delete(stockLockkey); }*/ redissonLock.unlock();//解锁 } } }
redisson idea 中启动信息
2023-03-01 16:10:16.577 INFO 67124 --- [ main] org.redisson.Version : Redisson 3.19.3 2023-03-01 16:10:17.176 INFO 67124 --- [ main] o.r.c.SentinelConnectionManager : master: redis://192.168.1.138:6385 added 2023-03-01 16:10:17.180 INFO 67124 --- [ main] o.r.c.SentinelConnectionManager : slave: redis://192.168.1.138:6386 added 2023-03-01 16:10:17.180 INFO 67124 --- [ main] o.r.c.SentinelConnectionManager : slave: redis://192.168.1.138:6387 added 2023-03-01 16:10:17.191 INFO 67124 --- [isson-netty-4-8] o.r.c.SentinelConnectionManager : sentinel: redis://192.168.1.138:27003 added 2023-03-01 16:10:17.192 INFO 67124 --- [isson-netty-4-9] o.r.c.SentinelConnectionManager : sentinel: redis://192.168.1.138:27002 added 2023-03-01 16:10:17.192 INFO 67124 --- [sson-netty-4-10] o.r.c.SentinelConnectionManager : sentinel: redis://192.168.1.138:27001 added 2023-03-01 16:10:17.216 INFO 67124 --- [sson-netty-4-19] o.r.c.pool.MasterPubSubConnectionPool : 1 connections initialized for 192.168.1.138/192.168.1.138:6385 2023-03-01 16:10:17.253 INFO 67124 --- [isson-netty-4-2] o.r.c.pool.MasterConnectionPool : 24 connections initialized for 192.168.1.138/192.168.1.138:6385 2023-03-01 16:10:17.258 INFO 67124 --- [sson-netty-4-31] o.r.c.pool.PubSubConnectionPool : 1 connections initialized for 192.168.1.138/192.168.1.138:6387 2023-03-01 16:10:17.258 INFO 67124 --- [sson-netty-4-32] o.r.c.pool.PubSubConnectionPool : 1 connections initialized for 192.168.1.138/192.168.1.138:6386 2023-03-01 16:10:17.294 INFO 67124 --- [isson-netty-4-5] o.r.connection.pool.SlaveConnectionPool : 24 connections initialized for 192.168.1.138/192.168.1.138:6386 2023-03-01 16:10:17.295 INFO 67124 --- [sson-netty-4-29] o.r.connection.pool.SlaveConnectionPool : 24 connections initialized for 192.168.1.138/192.168.1.138:6387 2023-03-01 16:10:18.079 INFO 67124 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path '' 2023-03-01 16:10:18.155 INFO 67124 --- [ main] com.hmdp.HmDianPingApplication : Started HmDianPingApplication in 6.287 seconds (JVM running for 7.421)
测试