分布式锁-redission锁的MutiLock原理
此时我们去写命令,写在主机上, 主机会将数据同步给从机,但是假设在主机还没有来得及把数据写入到从机去的时候,此时主机宕机,哨兵会发现主机宕机,并且选举一个slave变成master,而此时新的master中实际上并没有锁信息,此时锁信息就已经丢掉了。
为了解决这个问题,redission提出来了MutiLock锁,使用这把锁咱们就不使用主从了,每个节点的地位都是一样的, 这把锁加锁的逻辑需要写入到每一个主丛节点上,只有所有的服务器都写入成功,此时才是加锁成功,假设现在某个节点挂了,那么他去获得锁的时候,只要有一个节点拿不到,都不能算是加锁成功,就保证了加锁的可靠性。
当我们去设置了多个锁时,redission会将多个锁添加到一个集合中,然后用while循环去不停去尝试拿锁,但是会有一个总共的加锁时间,这个时间是用需要加锁的个数 * 1500ms ,假设有3个锁,那么时间就是4500ms,假设在这4500ms内,所有的锁都加锁成功, 那么此时才算是加锁成功,如果在4500ms有线程加锁失败,则会再次去进行重试.
代码:
@Configuration public class RedissonConfig { @Bean public RedissonClient redissonClient(){ // 配置 Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.1.8:6379").setPassword("123456"); // 创建RedissonClient对象 return Redisson.create(config); } @Bean public RedissonClient redissonClient2(){ // 配置 Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.1.8:6380").setPassword("123456"); // 创建RedissonClient对象 return Redisson.create(config); } @Bean public RedissonClient redissonClient3(){ // 配置 Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.1.8:6381").setPassword("123456"); // 创建RedissonClient对象 return Redisson.create(config); } }
创建一个联锁,并用这个锁对象去尝试获取锁。
@Slf4j @SpringBootTest class RedissonTest { @Resource private RedissonClient redissonClient; @Resource private RedissonClient redissonClient2; @Resource private RedissonClient redissonClient3; private RLock lock; @BeforeEach void setUp() { // lock = redissonClient.getLock("order"); RLock lock1 = redissonClient.getLock("order"); RLock lock2 = redissonClient2.getLock("order"); RLock lock3 = redissonClient3.getLock("order"); //创建连锁 multiLock lock = redissonClient.getMultiLock(lock1,lock2,lock3); } @Test void method1() throws InterruptedException { // 尝试获取锁 boolean isLock = lock.tryLock(1L, TimeUnit.SECONDS); if (!isLock) { log.error("获取锁失败 .... 1"); return; } try { log.info("获取锁成功 .... 1"); method2(); log.info("开始执行业务 ... 1"); } finally { log.warn("准备释放锁 .... 1"); lock.unlock(); } } void method2() { // 尝试获取锁 boolean isLock = lock.tryLock(); if (!isLock) { log.error("获取锁失败 .... 2"); return; } try { log.info("获取锁成功 .... 2"); log.info("开始执行业务 ... 2"); } finally { log.warn("准备释放锁 .... 2"); lock.unlock(); } } }
任何一个节点挂掉,锁没有获取到,整个锁都会获取失败,解决了因redis主从同步有延迟导致的锁失效问题。