Redisson实现分布式锁 Redisson实现分布式锁

转;

Redisson实现分布式锁

Redisson文档参考:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95

   redis是实现分布式锁的一种方式,其他还可以基于数据库,zookeeper等方式实现;这里拿出redis单说一下,redis从原理上大概有两种实现方式,要么是调用redis原生的原子性命令,要么是通过eval执行封装好的lua脚本;而从使用上来讲也有两种方式,要么自己动手实现(参考:https://www.cnblogs.com/linjiqin/p/8003838.html),要么使用别人已经封装好的,例如Redis官方推荐的Redisson客户端。考虑到Redisson的官方推荐,加上大牛效应,当然是“拿来主义”好了。

开始引入

pom文件中引入依赖:

<!-- redisson 分布式锁实现 -->
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.8.2</version> </dependency>

spring中配置:

  引入约束:

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd" default-lazy-init="true">
复制代码

         测试staging环境:

复制代码
<!-- redisson 客户端 配置实现 -->
<redisson:client id="redissonClient"> <redisson:cluster-servers password="${password}"> <redisson:node-address value="redis://127.0.0.1:6600"/> <redisson:node-address value="redis://127.0.0.1:6601"/> <redisson:node-address value="redis://127.0.0.1:6602"/> </redisson:cluster-servers> </redisson:client>
复制代码

         生产production环境:

复制代码
<!-- redisson 客户端 配置实现 -->
<redisson:client id="redissonClient"> <redisson:cluster-servers password="${password}"> <redisson:node-address value="redis://127.0.0.1:6602"/> <redisson:node-address value="redis://127.0.0.1:6603"/> <redisson:node-address value="redis://127.0.0.2:6602"/> <redisson:node-address value="redis://127.0.0.2:6603"/> <redisson:node-address value="redis://127.0.0.3:6602"/> <redisson:node-address value="redis://127.0.0.3:6603"/> </redisson:cluster-servers> </redisson:client>
复制代码

业务中使用:

复制代码
public class LockBiz {

    @Autowired
    RedissonClient redissonClient;

    public boolean doWithLock(long groupId, OperateType operateType, String operator, List<Config> configList) { boolean isLocked = false; String lockName = "fi_config_groupid_" + groupId; RLock lock = redissonClient.getLock(lockName); if (lock == null) { log.error("lock is null"); return false; } try { try { boolean lockedState = lock.isLocked(); if (lockedState) { log.error("lock_redisson state seems already locked: {}, name of lock is: {}", lockedState, lockName); } for (int i = 0; i < Constants.TRY_TIMES; ++i) { isLocked = lock.tryLock(Constants.TRY_LOCK_TIME, Constants.AUTO_UNLOCK_TIMES, Constants.LOCK_TIME_UNIT); log.info("lock_redisson result: {}, try times: {}, time consuming: {}", isLocked, (i+1), (System.currentTimeMillis() - startLock)); if (isLocked) { break; } } } catch (InterruptedException e) { log.error("failed to get lock_redisson: ", e); } if (!isLocked) { log.error("try lock_redisson failed"); } /** 加锁成功,处理业务逻辑 */ } finally { if (isLocked) { try { lock.unlock(); } catch (Throwable t) { log.error("failed to unlock_redisson, {}", ExceptionUtils.getStackTrace(t)); } } } } }
复制代码

注意事项:

  1. redisson的2版本和3版本在配置redis地址的时候貌似不一致,2版本无需前缀“redis://”,而3版本需要;

  2. getLock时,RLock lock = redissonClient.getLock(lockName);  这个lockName一定要唯一,redisson应该是将这个lockName同时作为lock的name和key的名称,如果和别人重复了,就需要和别人竞争同一把锁了,而不是自己的业务和自己的业务竞争锁了。(今天就出现了个问题,我把lockName设置为2,经常会出现加锁失败,并且是在循环加锁之前 这把锁就已经锁上了,现在想想应该是别人在其他地方给redis中添加了个key=2的,导致我无法加锁,排查了挺长时间)

Redisson的大概原理

首先是获取到了一个可重入锁:

然关键后是tryLock方法:

 

从上面可以看出,redisson底层也是基于封装Lua脚本实现分布式锁的,但是应该解决了一些其他可能存在的问题,例如官方说的:

 

Redisson文档参考:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95

   redis是实现分布式锁的一种方式,其他还可以基于数据库,zookeeper等方式实现;这里拿出redis单说一下,redis从原理上大概有两种实现方式,要么是调用redis原生的原子性命令,要么是通过eval执行封装好的lua脚本;而从使用上来讲也有两种方式,要么自己动手实现(参考:https://www.cnblogs.com/linjiqin/p/8003838.html),要么使用别人已经封装好的,例如Redis官方推荐的Redisson客户端。考虑到Redisson的官方推荐,加上大牛效应,当然是“拿来主义”好了。

开始引入

pom文件中引入依赖:

<!-- redisson 分布式锁实现 -->
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.8.2</version> </dependency>

spring中配置:

  引入约束:

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd" default-lazy-init="true">
复制代码

         测试staging环境:

复制代码
<!-- redisson 客户端 配置实现 -->
<redisson:client id="redissonClient"> <redisson:cluster-servers password="${password}"> <redisson:node-address value="redis://127.0.0.1:6600"/> <redisson:node-address value="redis://127.0.0.1:6601"/> <redisson:node-address value="redis://127.0.0.1:6602"/> </redisson:cluster-servers> </redisson:client>
复制代码

         生产production环境:

复制代码
<!-- redisson 客户端 配置实现 -->
<redisson:client id="redissonClient"> <redisson:cluster-servers password="${password}"> <redisson:node-address value="redis://127.0.0.1:6602"/> <redisson:node-address value="redis://127.0.0.1:6603"/> <redisson:node-address value="redis://127.0.0.2:6602"/> <redisson:node-address value="redis://127.0.0.2:6603"/> <redisson:node-address value="redis://127.0.0.3:6602"/> <redisson:node-address value="redis://127.0.0.3:6603"/> </redisson:cluster-servers> </redisson:client>
复制代码

业务中使用:

复制代码
public class LockBiz {

    @Autowired
    RedissonClient redissonClient;

    public boolean doWithLock(long groupId, OperateType operateType, String operator, List<Config> configList) { boolean isLocked = false; String lockName = "fi_config_groupid_" + groupId; RLock lock = redissonClient.getLock(lockName); if (lock == null) { log.error("lock is null"); return false; } try { try { boolean lockedState = lock.isLocked(); if (lockedState) { log.error("lock_redisson state seems already locked: {}, name of lock is: {}", lockedState, lockName); } for (int i = 0; i < Constants.TRY_TIMES; ++i) { isLocked = lock.tryLock(Constants.TRY_LOCK_TIME, Constants.AUTO_UNLOCK_TIMES, Constants.LOCK_TIME_UNIT); log.info("lock_redisson result: {}, try times: {}, time consuming: {}", isLocked, (i+1), (System.currentTimeMillis() - startLock)); if (isLocked) { break; } } } catch (InterruptedException e) { log.error("failed to get lock_redisson: ", e); } if (!isLocked) { log.error("try lock_redisson failed"); } /** 加锁成功,处理业务逻辑 */ } finally { if (isLocked) { try { lock.unlock(); } catch (Throwable t) { log.error("failed to unlock_redisson, {}", ExceptionUtils.getStackTrace(t)); } } } } }
复制代码

注意事项:

  1. redisson的2版本和3版本在配置redis地址的时候貌似不一致,2版本无需前缀“redis://”,而3版本需要;

  2. getLock时,RLock lock = redissonClient.getLock(lockName);  这个lockName一定要唯一,redisson应该是将这个lockName同时作为lock的name和key的名称,如果和别人重复了,就需要和别人竞争同一把锁了,而不是自己的业务和自己的业务竞争锁了。(今天就出现了个问题,我把lockName设置为2,经常会出现加锁失败,并且是在循环加锁之前 这把锁就已经锁上了,现在想想应该是别人在其他地方给redis中添加了个key=2的,导致我无法加锁,排查了挺长时间)

Redisson的大概原理

首先是获取到了一个可重入锁:

然关键后是tryLock方法:

 

从上面可以看出,redisson底层也是基于封装Lua脚本实现分布式锁的,但是应该解决了一些其他可能存在的问题,例如官方说的:

 

猜你喜欢

转载自www.cnblogs.com/libin6505/p/10790575.html