《Redis 分布式锁》
一:什么是分布式锁。
- 通俗来说的话,就是在分布式架构的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 分布式锁》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- Git的个人总结
Git Git简史: 同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代. Linux 内核开源项目有着为数众多的参与者. 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存 ...
- BZOJ 3672: [Noi2014]购票 树上CDQ分治
做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以, ...
- 从TEB到PEB再到SEH(一)
什么是TEB? TEB(Thread Environment Block,线程环境块) 线程环境块中存放着进程中所有线程的各种信息 这里我们了解到了TEB即为线程环境块, 进程中每一条线程都对应着的自 ...
- [Gradle] 发布 library 到本地 maven 仓库
Java Library // publish_local_java.gradle apply plugin: 'maven-publish' publishing { publications { ...
- 暂时性死区TDZ理解与总结
为什么会出现暂时性死区? 先来看看 ES6 标准中对 let/const 声明中的解释 第13章,有如下一段文字:The variables are created when their contai ...
- Android App专项测试
https://www.jianshu.com/p/141b84f14505 http://www.cnblogs.com/finer/p/9601140.html 专项 概念 adb命令 App启动 ...
- Eclipse R语言开发环境搭建 StatET插件
StatET 官网 http://www.walware.de/goto/statet Installation 点击菜单栏 help --> Install New Software 配置R语 ...
- plsql 如何导入excel数据?
oracle 导入excel数据? 通过plsql实现 1.准备工作 Excel中的字段名称,必须和表结构字段一 一对应 下面以tdoctor_apply表为例,进行演示 表结构 Excel表数据 ...
- HBase(一) —— 基本概念及使用
一.安装&启动 下载 https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/2.1.8/ 快速开始文档,HBase2.1.8 http://hba ...
- HTTP/1.0和HTTP/1.1 http2.0的区别,HTTP怎么处理长连接(阿里)
HTTP1.0 HTTP 1.1主要区别 长连接 HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接. HTTP是基于TCP/IP协议的,创 ...