• 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脚本实现分布式锁的,但是应该解决了一些其他可能存在的问题,例如官方说的:

     

  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/fengyizhen/p/10074941.html
Copyright © 2020-2023  润新知