zoukankan      html  css  js  c++  java
  • redis 实现分布式锁

     单系统的时候可以通过 同步锁等机制实现,但是多个服务器多个进程如何实现呢。首先看一下分布式锁的必要条件:

    1)原子性:加锁和释放锁的操作必须满足原子性

    2)不会产生死锁,有各种原因会导致锁没有被释放从而产生死锁

    3)互斥性,某个时间只能有一个线程占有锁,其他线程处于阻塞状态

    4)可重入性,也就是释放锁的线程可以再次获取该锁(这个涉及偏向锁等知识)

    实现的思路:

    利用 Jedis 的  setnx() 方法,设置键值,如果键已经存在,则返回0 。多个线程同时设置,但只有一个能设置成功,也就是返回 1,返回1的线程就获取到分布锁,处理完业务后,需要删除设置的键(要注意只能删除自己所设置的键,删除的时候需要判断此时的锁是不是自己的,有可能要删除的时候,刚好过期了,这个键是另一个线程设置的)

      public Long setnx(final String key, final String value) {
        checkIsInMultiOrPipeline();
        client.setnx(key, value);
        return client.getIntegerReply();
      }

    但是, 获取锁的线程有可能意外挂掉,此时锁并没有被释放,就会产生死锁。随着阻塞线程的增加堆积,最终导致系统崩溃。此时,可以让获取锁的线程主动设置键的过期时间,但是要注意的是,键的过期时间必须要大于业务处理时间,否则业务没处理完,当有新的线程获取到锁,也会导致问题。

      public Long expire(final String key, final int seconds) {
        checkIsInMultiOrPipeline();
        client.expire(key, seconds);
        return client.getIntegerReply();
      }

    所以关键问题点在于,这个业务时间和锁的过期时间怎么设置?可以从两个方面考虑,业务不复杂的时候,保证业务时间<过期时间。第二是获取锁的线程开启一个守护线程,用来给快过期的锁“续航”(守护线程执行expire指令)

    总结

    Redis 来实现一个分布式同步锁的方式,其特点是:

    1. 加锁和释放锁是原子性的
    2. 满足互斥性,同一个时刻只能有一个线程可以获取锁和释放锁
    3. 利用 Redis 的 ttl机制和守护进程的方式来保证不会出现死锁

    以上的方案中,我们是假设 Redis 服务端是单集群且高可用的,忽视了以下的问题:

    如果某一时刻 Redis master 节点发生了故障,集群中的某个 slave 节点变成 master 节点,在故障迁移(failover)过程中可能出现原 master 节点上的锁没有及时同步到 slave 节点,导致其他线程同时获得锁。对于这个问题,可以参考 Redis 官方推出的 redlock 算法,但是比较遗憾的是,该算法也没有很好地解决锁过期的问题。(PS:不过这种不安全也仅仅是在主从发生 failover 的情况下才会产生,而且持续时间极短,业务系统多数情况下可以容忍。)

    原文:https://www.cnblogs.com/wengle520/p/12484931.html

  • 相关阅读:
    tfs+git
    fis3 部署手册
    git +vs2017 操作手册+目前工作流程图
    Git 分支策略
    git 分回滚后无法合并代码问题
    git 拉取远程分支到本地并建立关联关系
    mysql查看数据库大小或者表大小
    centos7.4安装高可用(haproxy+keepalived实现)kubernetes1.6.0集群(开启TLS认证)
    centos7.4安装kubernetes1.6.0(开启TLS认证)
    Centos搭建http代理服务器(无密码验证)
  • 原文地址:https://www.cnblogs.com/yrjns/p/12497376.html
Copyright © 2011-2022 走看看