一:什么是分布式锁。

  -  通俗来说的话,就是在分布式架构的redis中,使用锁。

二:分布式锁的使用选择。

  - 当 Redis 的使用场景不多,而且也只是单个在用的时候,可以构建自己使用的 锁。

  - 如果在公司里落地生产环境用分布式锁的时候,一般是会用开源类库。

  - Redis分布式锁,一般就是用 Redisson 框架就好了,非常的简便易用。

三:Redisson 实现Redis分布式锁的原理。

  - 整体流程图

    - 

  - 详解

    - 当某个请求的客户端需要加锁时候。

      - 如果该客户端面对的是一个redis cluster集群,他首先会根据hash算法选择一台机器。(一致hash算法)

    - 随后会向Redis发送加锁请求(原理为Lua脚本)

      - Lua 脚本会保证业务执行的原子性,所以采用 Lua 的方式为加锁命令。

      - 

      - 这个Lua 脚本的大致意思为(这个Key的锁是否存在,如果存在,则一直循环等待,如不存在,则上锁,并设置过期时间。)

    - watch dog 提供的锁自动延期的能力

      - 加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?

      - RedisSon 只要加锁成功,就会启动一个watch dog看门狗, 他是一个后台线程,会每隔10秒检查一下 ,如果还持有锁key,那么就会不断的延长锁key的生存时间。

四:分布式锁锁带来的问题

  - 在分布式架构中的问题,就是如果你对某个redis master实例,写入了key的锁,此时会异步复制给对应的master slave实例。

  - 但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。

  - 接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。

  - 此时就会导致多个客户端对一个分布式锁完成了加锁。

  - 这时系统在业务语义上一定会出现问题, 导致各种脏数据的产生 。

  - 这个就是redis cluster/redis master-slave架构的 主从异步复制 导致的redis分布式锁的问题:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。

五:简单实现的redis锁

  - 原理

    -  通过 redis 的 setnx 功能进行加锁

  - 实现(PHP)

    • <?php
      /**
      * 创建 Redis 单例
      * @return mixed
      */
      class redisInstance
      {
      static $redis; private function __construct()
      {
      } public static function getInstance()
      {
      if (self::$redis) {
      return self::$redis;
      } self::$redis = new \Redis(); return self::$redis;
      } } class redisLock
      {
      public $reids; public function __construct()
      {
      $this->reids = redisInstance::getInstance();
      } /**
      * 键加锁,默认加锁时间为 1分钟 = 60 * 1000(毫秒)
      * @param $key
      * @param int $ttl
      * @return bool
      */
      public function lock($key, $ttl = 60000)
      {
      $lockKey = $key . '_lock'; // 通过setNx命令拿到锁
      $lock = $this->reids->set($lockKey, 1, ['NX', 'PX' => $ttl]); // 拿到锁则直接返回
      if ($lock) {
      return true;
      } // 没有拿到锁,则一直循环等待锁资源释放
      while (!$lock) {
      $lock = $this->reids->set($key, 1, ['NX', 'PX' => $ttl]);
      } return $lock;
      } /**
      * 释放锁
      * @param $key
      * @return bool
      */
      public function unLock($key)
      {
      $lockKey = $key . '_lock'; $lock = false; // 释放锁
      while (!$lock) {
      $lock = $this->reids->del($lockKey);
      } return true;
      }
      } $redis = redisInstance::getInstance();
      $redisLock = new redisLock(); /**
      * 例如,买商品,进行库存递减
      * 1:对库存加锁
      * 2:递减
      * 3:释放锁
      * 影响
      * 加锁导致的并发度降低
      */
      $key = 'stock';
      $redisLock->lock($key);
      $stock = $redis->get($key);
      if ($redis->get($key) <= 0) {
      $redisLock->unLock($key);
      return false;
      }
      $redis->decr($key);
      $redisLock->unLock($key);

《Redis 分布式锁》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. Git的个人总结

    Git Git简史: 同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代. Linux 内核开源项目有着为数众多的参与者. 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存 ...

  2. BZOJ 3672: [Noi2014]购票 树上CDQ分治

    做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以, ...

  3. 从TEB到PEB再到SEH(一)

    什么是TEB? TEB(Thread Environment Block,线程环境块) 线程环境块中存放着进程中所有线程的各种信息 这里我们了解到了TEB即为线程环境块, 进程中每一条线程都对应着的自 ...

  4. [Gradle] 发布 library 到本地 maven 仓库

    Java Library // publish_local_java.gradle apply plugin: 'maven-publish' publishing { publications { ...

  5. 暂时性死区TDZ理解与总结

    为什么会出现暂时性死区? 先来看看 ES6 标准中对 let/const 声明中的解释 第13章,有如下一段文字:The variables are created when their contai ...

  6. Android App专项测试

    https://www.jianshu.com/p/141b84f14505 http://www.cnblogs.com/finer/p/9601140.html 专项 概念 adb命令 App启动 ...

  7. Eclipse R语言开发环境搭建 StatET插件

    StatET 官网 http://www.walware.de/goto/statet Installation 点击菜单栏 help --> Install New Software 配置R语 ...

  8. plsql 如何导入excel数据?

      oracle 导入excel数据? 通过plsql实现 1.准备工作 Excel中的字段名称,必须和表结构字段一 一对应 下面以tdoctor_apply表为例,进行演示 表结构 Excel表数据 ...

  9. HBase(一) —— 基本概念及使用

    一.安装&启动 下载 https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/2.1.8/ 快速开始文档,HBase2.1.8 http://hba ...

  10. HTTP/1.0和HTTP/1.1 http2.0的区别,HTTP怎么处理长连接(阿里)

    HTTP1.0 HTTP 1.1主要区别 长连接 HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接. HTTP是基于TCP/IP协议的,创 ...