• -W.LI-
    2019-08-24
    老师好!基于数据库的实现,我现在项目中直接不开事务,select后插入(oeder_no做唯一约束)。try_catch 异常,重试3次。如果查到了返回成功保证密等。这么做会有问题么?
    课后题:万一收到的N/2+1节点全部挂了肯定会有问题。不知道,从新选为master节点的算法不知,如果会选择没有收到的节点做master也会有问题。

    作者回复: 没有问题。

    问题的答案:redis实现的分布式锁,都是有一个过期时间,如果一旦服务A出现stop the world的情况,有可能锁过期了,而此时服务A中仍然存在持有锁,此时另外一个服务B又获取了锁,这个时候存在两个服务同时获取锁的可能。

    
     6
  • a、
    2019-08-24
    不一定,因为如果集群中有5个redis,abcde,如果发生网络分区,abc在一个分区,de在一个分区,客户端A向abc申请锁成功,在c节点master异步同步slave的时候,master宕机了,slave接替,然后c的slave又和de在一个分区里,这时候如果客户端B来申请锁,也就可以成功了。
    zk锁也会出现问题,如果客户端A申请zk锁成功,这时候客户端A和zk不在一个分区里,zk就会把临时节点删除,然后如果客户端B再去申请,也就可以申请成功

    作者回复: 对的,这种情况也是可能发生的,前提是c节点在宕机之前没有持久化锁。

    第二zk锁的问题,如果连接session已经断开,客户端的锁是会释放的,不会存在同时获取锁的情况。

     1
     4
  • 我已经设置了昵称
    2019-08-25
    不太懂redission机制,每个节点各自去获取锁。超过一半以上获取成功就算成功。那是不是还有这么一步:这些一半以上的机器获取了以后,是否还要决定谁真正拿到锁,才能真正执行这个任务

    作者回复: 都会设置锁对象

    
     1
  • Demon.Lee
    2019-12-17
    老师,InterProcessMutex lock = new InterProcessMutex(client, lockPath);
    如果使用curator框架进行分布式锁的实现(针对并发修改表中的一条记录),故我对表中的id字段进行加锁,但是这个id不能放在上面的lockPath中,否则在zookeeper中就会产生成千上万个znode。所以,这个id必须是临时节点,但是InterProcessMutex中好像没有找到相应的api,是否只能走zookeeper原生的方式实现吗
    
    
  • Zend
    2019-12-12
    老师在数据库实现分布式锁的例子中,保证查询和插入在同一个事务里面,就能防止幻读。是不是不指定在一个事务里,查询和插入操作虽然在一个方法里,但是两个事务。

    作者回复: 是的

    
    
  • neohope
    2019-11-26
    老师您好,我有两个问题:
    redisson会向所有的redis节点并发发起请求,获取一半以上的锁才会进行后续操作。那我的疑问是,
    1、这样不会让整体性能变得比redis集群要差一些吗?而且redis节点越多,redisson性能越差?
    2、redisson的客户端,如果无法获取到足够多redis节点的锁,其释放规则及防止冲突的规则又是如何处理的呢?如果没有合理的防冲突规则,感觉并发量越高,性能会越差。

    作者回复: 鱼和熊掌不可兼得,保证可靠性的前提下,会带来一定的性能损失。

    当在一定时间内没有获取到足够节点时,会通过定时任务将已经超时的锁通过lua脚本来释放。

    
    
  • 任鹏斌
    2019-11-19
    老师我从redis官方文档的setnx命令里并没发现支持过期时间呀,setex倒是可以,您文中的代码里jedis使用的是set,这是怎么回事呢?

    作者回复: 2.6.12版本中,使用SET代替SETNX ,相当于SETNX+EXPIRE实现了原子性,不必担心SETNX成功,而EXPIRE失败的问题。

    
    
  • 青春超无敌
    2019-11-17
    老师,redis和zk实现分布式锁。这两种除了性能区别,还有其他方面的差别吗

    作者回复: 实现原理不一样,性能不一样

    
    
  • 李豪
    2019-11-14
    Redis setnx方式设置分布式锁存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:
    1.客户端1在Redis的master节点上拿到了锁。
    2.Master宕机了,存储锁的key还没有来得及同步到Slave上。
    3.master故障,发生故障转移,slave节点升级为master节点。
    4.客户端2从新的Master获取到了对应同一个资源的锁。
    于是,客户端1和客户端2同时持有了同一个资源的锁。锁的安全性被打破了。
    展开
    
    
  • 风轻扬
    2019-10-14
    老师,redisson实现的分布式锁。您写的例子
     .setScanInterval(2000) //集群状态的扫描时间,单位是毫秒
    这个设置有什么用啊?

    作者回复: 这是官方给出的一种连接redis集群的参考方式,具体作用已经写出了,类似一个心跳机制:
    https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95#24-%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F

    
    
  • 风轻扬
    2019-10-14
    老师,我试了一下redisson实现的分布式锁。有两个问题请教您。
    1 .redis的集群模式,我在一台机器上建了一个伪集群。创建集群时,一共6个节点。3主3从。从节点是自动分配的。从节点的只读模式需要改成no吗?(不改成no,往从节点写锁,就会转移到主节点上去)
    2 .字数限制,没办法贴代码,我在您例子的基础上增加了3个节点,也就是6个节点。核心代码如下:
    final long waitTimeout = 10;
            final long leaseTime = 3;
    final RLock lock1 = redissonClient1.getLock("lock1");
            final RLock lock2 = redissonClient2.getLock("lock2");
            final RLock lock3 = redissonClient3.getLock("lock3");
            final RLock lock4 = redissonClient4.getLock("lock4");
            final RLock lock5 = redissonClient5.getLock("lock5");
            final RLock lock6 = redissonClient6.getLock("lock6");

    for (int i = 0; i < 10; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3, lock4, lock5, lock6);
                        try {
                            if (redLock.tryLock(waitTimeout, leaseTime, TimeUnit.SECONDS)) {
                                //业务逻辑
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            redLock.unlock();
                        }
                    }
                }).start();
            }
    使用6个节点来实现redisson,但是获取锁一直失败,怎么回事呢?老师
    展开
     1
    
  • 疯狂咸鱼
    2019-10-09
    老师,分布式锁到底锁什么呢,如果说是锁数据库表,分布式应用集群的情况下,如果是单机数据库,数据库自身的锁机制可以保证并发问题吧?难道是分布式锁只是用在数据库分库分表的情况下?

    作者回复: 分布式锁是在分布式服务的情况下保证原子性操作,而不是因为数据库产生的分布式锁。

    数据库可以实现分布式锁,是一种实现方式。

    
    
  • 风轻扬
    2019-09-26
    老师,我试了一下zookeeper的集群分布式锁。测试代码如下:
    public class TestZookeeperLock {
        private static int count = 10;

        public static void main(String[] args) {
            //重试策略,以下写法为:重试3次,每次间隔时间为3秒
            final RetryPolicy retryPolicy = new RetryNTimes(3,2000);
            final String connUrl = "192.111.111.111:2181,192.222.222.222:2181";
            for (int i = 0; i < 10; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //zookeeper分布式锁
                        CuratorFramework zk = CuratorFrameworkFactory.newClient(connUrl, retryPolicy);
                        zk.start();
                        InterProcessMutex lock = new InterProcessMutex(zk, "/opt/uams/zookeeper-3.4.7/locks");
                        try {
                            if (lock.acquire(3, TimeUnit.SECONDS)){
                                get();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                //释放锁
                                lock.release();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
            }
        }

        public static void get (){
            count --;
            if (count == 3) {
                try {
                    TimeUnit.SECONDS.sleep(3);//这里设置该线程睡眠2秒,已达到锁住效果
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(count);
        }
    }
    输出了:
    9
    8
    7
    6
    5
    4
    java.lang.IllegalMonitorStateException: You do not own the lock: /opt/uams/zookeeper-3.4.7/locks
        at org.apache.curator.framework.recipes.locks.InterProcessMutex.release(InterProcessMutex.java:140)
        at cn.org.test.TestZookeeperLock$1.run(TestZookeeperLock.java:47)
        at java.lang.Thread.run(Thread.java:745)
    3
    多次输出的结果一致,这是怎么回事呢?
    展开

    作者回复: 将以下代码提出到new Thread之外:
    //zookeeper分布式锁
                        CuratorFramework zk = CuratorFrameworkFactory.newClient(connUrl, retryPolicy);
                        zk.start();
                        InterProcessMutex lock = new InterProcessMutex(zk, "/opt/uams/zookeeper-3.4.7/locks");

    
    
  • 风轻扬
    2019-09-25
    老师,zk实现的锁,不会出现redis锁一样的问题吗?
    设想:
    应用1和应用2两个服务分别部署到不同的服务器上。是使用zookeeper实现分布式锁。应用1获取到锁,然后开始长时间gc,应用2也开始长时间gc。应用1的zk锁由于心跳超时释放了锁,应用2结束gc获取到锁,应用1结束gc开始执行任务,此时不就有两个任务在同时执行了吗?

    作者回复: 是的,这种情况也同样存在同时获取锁的可能

    
    
  • 风轻扬
    2019-09-24
    老师,互联网行业,多数都是redis集群啊,如果这样,基于redis实现的分布式锁是不是就不能用了?

    作者回复: 可以,使用Redisson就好了

    
    
  • godtrue
    2019-09-13
    我们的导入功能就是用的redis分布式锁,防止多个业务操作人员同时导入,超时时间一般为五分钟。
    出现网络分区只能二选一要A或者C,不过互联网企业基本都会选择A。
    
    
  • 木刻
    2019-09-11
    老师你好,我尝试了下第一个,模拟并发情况下发现会有概率抛数据库异常: Deadlock found when trying to get lock; try restarting transaction
    https://github.com/mygodmele/DbLock.git

    作者回复: 运行了代码,并没有出现死锁问题,麻烦贴出数据库脚本

     2
    
  • K
    2019-09-08
    老师好,课后问题还是没听懂,首先我理解redis集群可能同时获取锁,是因为锁时间超时了,别的线程也能拿到,是这个原因。Redlock 算法是怎样解决这个问题的呢?

    作者回复: RedLock算法是会去每一个节点获取锁,正常情况下,别的线程无法同时获取锁的。


    
    
  • 知行合一
    2019-09-05
    老师,想问个问题,redis集群已经分了槽,客户端写入根据算法应该写入一个节点啊,为啥要多个节点同时枷锁?

    作者回复: 写入一个单点只实现了高可用,没有实现集群式分布式锁。单点的问题会存在单个节点挂了的情况下,不同应用服务同时获取锁的可能。

    
    
  • Jxin
    2019-09-04
    1.锁超时,也会出现多个任务同时持有锁进行。
    2.解决方式,守护线程续航锁持有时间。
    3.弊端,浪费线程,开销太大。
    4.根据业务情况设置合理的超时时间是最棒的。

    5.集群环境还会导致事务失效(同时提交多个key,多个key在不同节点)挺蛋疼。
    展开
    
    
我们在线,来聊聊吧