一:什么是分布式锁。

  -  通俗来说的话,就是在分布式架构的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. 纯js房贷计算器开源

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. ES6函数的个人总结

    默认参数: 1. 在 ES5 语法中,为函数形参指定默认值的写法: 写法一: function foo (bar) { bar = bar || 'abc'; console.log(bar) } f ...

  3. HTML 009 select_jquery操作下拉框select

    取值问题 <select id="selector"> <option value="1">选项一</option> < ...

  4. php Web 项目的文件/文件夹上传下载

    PHP用超级全局变量数组$_FILES来记录文件上传相关信息的. 1.file_uploads=on/off 是否允许通过http方式上传文件 2.max_execution_time=30 允许脚本 ...

  5. Mybatis02

    1.mybatis动态sql   foreach 添加接口方法 编写BookVo类 BookMapper.xml 测试 结果 2.模糊查询 3.查询返回结果集 resultMap:适合使用返回值是自定 ...

  6. 洛谷 P3183 [HAOI2016]食物链 题解

    P3183 [HAOI2016]食物链 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形 ...

  7. shell脚本编程基础之case语句

    基础简介 脚本编程分为: 面向过程 选择结构:if语句,单分支.双分支.多分支:case语句 控制结构:顺序结构(默认) 循环结构:for.while.until 面向对象 case语句结构 case ...

  8. php 进制转换base_convert

    16进制 转为 8进制 base_convert(number,frombase,tobase); 参数 描述 number 必需.规定要转换的数. frombase 必需.规定数字原来的进制.介于 ...

  9. python中的base64加密解密

    介绍 Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法.可查看RFC2045-RFC2049,上面有MIME的详细规范. ...

  10. java操作数据库,以页面显示学生信息为例

    该部分内容实现的功能主要是:从数据库中查询数据并展示到页面,在页面中新增数据信息,在页面中修改数据信息,在页面中删除数据信息. =================stuList.jsp======== ...