综合中间件Redisson实战
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了综合中间件Redisson实战相关的知识,希望对你有一定的参考价值。
参考技术A 布隆过滤器也可以用于解决Redis缓存击穿。RMap的特性:
Redisson中包含有序集合功能组件SortedSet,积分排序集合功能组件ScoredSortedSet,字典排序集合功能组件LexSortedSet等。
队列底层核心的执行逻辑是记录"基于发布-订阅"的主题来实现。
在使用延迟队列的时候,不要将TTL不同的时间放入到同一个队列,Redisson可以按照TTL从小到大的顺序先后被真正的队列监听、消费。
一次性锁:在高并发的时候,如果当前线程可以获取到分布式锁,则成功获取,如果获取不到,当前线程将永远的被抛弃。
用户重复提交场景:
分布式锁的可重入,当高并发产生多线程时,如果当前线程不能获取到分布式锁,它并不会立即被抛弃,而是等待一定的时间,重新尝试去获取分布式锁。
如果在规定的时间内获取到锁,执行后面的操作,如果不能获取到锁,就会被抛弃。
(分布式中间件技术实战(Java版).钟林森.机械工业出版社)
Redis实战——Redisson分布式锁
目录
2.5 Redisson分布式锁的主从一致性(MutiLock锁)
1 基于Redis中setnx方法的分布式锁的问题
之前我们使用setnx方法自定义的分布式锁,仍然会有许多的问题:
主要分为下面5点
1. 不可重入:即同一个线程无法多次获取同一把锁。
2. 不可重试:获取锁只尝试一次就返回false,没有重试机制
3. 超时释放:锁超时释放虽然可以避免死锁,但如果是业务执行耗时较长,也会导致锁释放,存在安全隐患
4. 主从一致性:如果Redis提供了主从集群,主从同步存在延迟,当主宕机时,如果从并同步主中的锁数据,则会出现锁实现。
这就需要我们去使用Redisson
2 Redisson
2.1 什么是Redisson
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。
说人话,它是一个基于Redis实现的分布式工具的集合,其中就包含了各种分布式锁的实现。
官网地址: https://redisson.org
2.2 Redisson实现分布式锁快速入门
第一步,先引依赖。
<!--Redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
第二步,配置Redisson客户端
@Configuration
public class RedissonConfig
@Bean
public RedissonClient redissonClient()
// 配置
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.150.101:6379")
.setPassword("123321");
// 创建RedissonClient对象
return Redisson.create(config);
然后就可以使用Redisson中的getLock方法获取锁对象了。
在锁对象中通过tryLock方法尝试获取锁,该方法可以传入三个参数,分别是,获取锁失败的等待时间、超时时间和时间单位。默认分别是 -1秒(也就是不等待),30秒 和秒单位。
//1.创建锁对象
//SimpleRedisLock lock = new SimpleRedisLock(stringRedisTemplate, "order:" + userId);
RLock lock = redissonClient.getLock("order:" + userId);
//2.尝试获取锁
boolean isLock = lock.tryLock();
if (!isLock)
//获取锁失败
return Result.fail("一个用户只能下一单!");
try
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
return proxy.createVoucherOrder(voucherId);
finally
//释放锁
lock.unlock();
2.3 Redisson 可重入锁原理
什么是可重入锁?
先看一段代码:
方法1,先尝试获取锁,当获取锁成功后,调用方法2,在方法2中,又尝试获取锁,并执行完方法2的逻辑后,执行方法1 的逻辑,最后释放锁。
这个时候,因为方法1和方法2在同一个线程里,所以获取的是同一把锁,所以方法2中获取到的锁就是可重入锁。
Redisson中又是如何实现的呢?
很简单,就是新增了一个获取锁的次数。它舍弃了我们之前使用的Redis中String类型的setnx方法,改成用Hash类型的方法,分别存入锁的key,value存线程标识和锁的次数。
当同一个中的方法获取到同一把锁后,锁的次数+1,在释放锁的时候,不仅判断线程标识是否是自己的,还要判断锁的次数,如果次数-1 为0,采取释放锁。 以此来实现可重入锁。
我们可以根据此图来实现Lua脚本:
获取锁
释放锁:
2.4 Redisson分布式锁的可重试性
直接看底层实现原理:
这里主要三点:
1.当锁超时时间过期时,会使用看门口WatchDog不断重新设置超时时间去重试获取锁
2. 看门狗只有在我们没有设置超时时间,在超时时间默认的情况下才会有。
3.在每次重新获取锁之前,不会马上不断的进行去重试,会等待是否有释放锁的信号和不断的精确判断剩余超时时间是否充裕。
这样就能实现锁的重试了。
2.5 Redisson分布式锁的主从一致性(MutiLock锁)
主从一致性问题:
为了提高redis的可用性,我们会搭建集群或者主从,现在以主从为例
此时我们去写命令,写在主机上, 主机会将数据同步给从机,但是假设在主机还没有来得及把数据写入到从机去的时候,此时主机宕机,哨兵会发现主机宕机,并且选举一个slave变成master,而此时新的master中实际上并没有锁信息,此时锁信息就已经丢掉了。、
为了解决这个问题,redission提出来了MutiLock锁,使用这把锁咱们就不使用主从了,每个节点的地位都是一样的, 这把锁加锁的逻辑需要写入到每一个主丛节点上,只有所有的服务器都写入成功,此时才是加锁成功,假设现在某个节点挂了,那么他去获得锁的时候,只要有一个节点拿不到,都不能算是加锁成功,就保证了加锁的可靠性。
那么MutiLock 加锁原理是什么呢?笔者画了一幅图来说明
当我们去设置了多个锁时,redission会将多个锁添加到一个集合中,然后用while循环去不停去尝试拿锁,但是会有一个总共的加锁时间,这个时间是用需要加锁的个数 * 1500ms ,假设有3个锁,那么时间就是4500ms,假设在这4500ms内,所有的锁都加锁成功, 那么此时才算是加锁成功,如果在4500ms有线程加锁失败,则会再次去进行重试.
以上是关于综合中间件Redisson实战的主要内容,如果未能解决你的问题,请参考以下文章