一:什么是分布式锁。

  -  通俗来说的话,就是在分布式架构的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 version info & svn version info map(七)

    To generate the same version number as SVN, we can generate the same version number as SVN with the ...

  2. WinDbg常用命令系列---显示局部变量dv

    dv (Display Local Variables) dv命令显示当前作用域中所有局部变量的名称和值. dv [Flags] [Pattern] 参数: Flags显示其他信息.可以包括以下任何区 ...

  3. HEXO快速搭建自己的博客

    关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号 欢迎大家关注我的微信公众号:「醉翁猫咪」 很多人有自己的博客,那么你想要吗?利用Hexo就可以搭建专属自己 ...

  4. BMP文件格式详解(BMP file format)

    BMP文件格式,又称为Bitmap(位图),或是DIB(Device-Independent Device,设备无关图),是windows系统中广泛使用的图片文件格式,由于它可以不作任何变换地址保存图 ...

  5. win10 无法使用内置管理员账户打开应用

    运行gpedit.msc 启用两项 如何登陆 win 10 账户? 进入 win 10 应用商店,下载一个软件,然后登陆即可

  6. python学习笔记二:(python3 logging函数中format说明)

    背景,在学习logging时总是遇到无法理解的问题,总结,尝试一下更清晰明了了,让我们开始吧! logging模块常用format格式说明 %(levelno)s: 打印日志级别的数值 %(level ...

  7. 用户账户——《Python编程从入门到实践》

    Web应用程序的核心是让任何用户都能够注册账户并能够使用它,不管用户身处何方 1.让用户能够输入数据 建立用于创建用户的身份验证系统之前,我们先来添加几个页面,让用户能够输入数据.当前,只有超级用户能 ...

  8. dockerfile文件语法命令

    dockerfile文件语法命令 (1) FROM命令,支持两种形式,构建新镜像使用的基础镜像,所以源镜像必须存在,并且是非注释的第一条命令. DOCKERFILEFORM <image> ...

  9. hangfire控制台应用程序中添加控制面板

    1.使用nuget 管理包安装 Microsoft.AspNet.WebApi.OwinSelfHost 2.根目录添加新建类 名为:Startup.cs public class Startup { ...

  10. Centos7安装PHP、安装MySQL、安装apache

    Centos7安装PHP.MySQL.apache 这里今天教大家如何在centos7安装PHP,apache,mysql. 首先我们需要先安装centos7,我们可以在我们的电脑上安装一个虚拟机,在 ...