一:什么是分布式锁。

  -  通俗来说的话,就是在分布式架构的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. Access数据库连接封装类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  2. 让一个项目同时提交到码云和GitHub两个仓库

    在项目目录里找到.git文件夹然后找到config文件. 打开这个文件后找到下面的代码 [remote "origin"] url = git提交地址 fetch = +refs/ ...

  3. docker容器配置加速器

    1.编辑docker配置文件 vi /etc/docker/daemon.json 加入如下配置: {"registry-mirrors":["https://docke ...

  4. LeetCode 439. Ternary Expression Parser

    原题链接在这里:https://leetcode.com/problems/ternary-expression-parser/description/ 题目: Given a string repr ...

  5. Git的基本使用方法(受益匪浅)

    git指令介绍,下面有详解指令可以先跳过直接看下面的详解 $ mkdir learngit     //创建一个learngit文件夹 $ cd learngit         //进入learng ...

  6. 关于windbg报错"No symbols for ntdll. Cannot continue."问题

    最近我写个例子程序研究下某个异常情况,故意制造了个崩溃.然后分析dmp文件. 当我执行!address -summary命令想观察下进程当前内存情况时,去报如下错误: 0:000> !addre ...

  7. Using HAProxy as an API Gateway, Part 1 [Introduction]

    转自:https://www.haproxy.com/blog/using-haproxy-as-an-api-gateway-part-1/ An API gateway handles load ...

  8. CSS行内块元素(内联元素)

    一.典型代表 input img 二.特点: 在一行上显示 可以设置宽高 <style type="text/css"> img{ width: 300px; /* 顶 ...

  9. 括号匹配(POJ2955)题解

    原题地址:http://poj.org/problem?id=2955 题目大意:给出一串括号,求其中的最大匹配数. 我这么一说题目大意估计很多人就蒙了,其实我看到最开始的时候也是很蒙的.这里就来解释 ...

  10. 【洛谷P5049】旅行(数据加强版)

    题目链接 m=n-1是直接按字典序dfs就行, m=n时是一棵基环树,我们发现当一个点在环上时,可以把它和它的一个在环上的儿子之间的边删掉,然后回溯,到达它的第一个有其他儿子的祖先的另一个儿子上,我们 ...