一:什么是分布式锁。

  -  通俗来说的话,就是在分布式架构的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. Spring Security 认证执行流程

    本文基于 Spring Security 5.x 推荐阅读: 项目集成Spring Security SpringSecurity 整合 JWT 一.外层-正常登陆调用 项目启动后会自动寻找 User ...

  2. LeetCode 875. Koko Eating Bananas

    原题链接在这里:https://leetcode.com/problems/koko-eating-bananas/ 题目: Koko loves to eat bananas.  There are ...

  3. 4个MySQL优化工具AWR,帮你准确定位数据库瓶颈!(转载)

    对于正在运行的mysql,性能如何,参数设置的是否合理,账号设置的是否存在安全隐患,你是否了然于胸呢? 俗话说工欲善其事,必先利其器,定期对你的MYSQL数据库进行一个体检,是保证数据库安全运行的重要 ...

  4. 查看.NET应用程序中的异常(下)

    为什么要使用内存转储进行调试? 在两种主要情况下,您可能需要使用内存转储进行调试.第一种情况是应用程序有一个未处理的异常并崩溃,而您只有一个内存转储.第二种情况是,在生产环境中出现异常或特定行为,并且 ...

  5. cube.js 学习(十)cube 来自官方的学习网站

    尽管cube.js 包含了一个doc 站点,但是资料不是很全,同时如果查看了cube github 代码中的一些demo的话,发现还是很不错的 但是一些实践没有在文档展现出来,还好我们可以从cube ...

  6. HTML5 Geolocation(地理定位)

    一.背景 在HTML规范中,增加了获取用户地理信息的API,这样使得可以基于用户位置开发互联网应用,即基于位置服务 鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的. Inter ...

  7. mysql 日期处理

    mysql> select curdate(); +------------+ | curdate() | +------------+ | -- | +------------+ row in ...

  8. vue 移动端禁用安卓手机返回键

    //禁止手机返回键    下面这段代码直接复制在index.html中,可以生效// $(document).ready(function() { if (window.history &&a ...

  9. (二)OpenCV-Python学习—对比度增强

    ·对于部分图像,会出现整体较暗或较亮的情况,这是由于图片的灰度值范围较小,即对比度低.实际应用中,通过绘制图片的灰度直方图,可以很明显的判断图片的灰度值分布,区分其对比度高低.对于对比度较低的图片,可 ...

  10. 搭建阿里云服务 FTP 折中方案

    该配置的服务都配置了,端口也都打开了 ,但是ftp  就是连接不上 就是打不开目录 8uftp  出现以下情况 配置文件逐条检查,端口逐个检查 都没有问题,还是出现这种情况,实在没辙,蛋疼...... ...