Redis学习笔记01-分布式锁
1.分布式锁的定义与理解
在并发任务中,当对数据执行修改和删除时为了防止多个任务同时拿到数据而产生的混乱,这时就要用到分布式锁来限制程序的并发执行。
Redis分布式锁本质上要实现的目标就是在Redis里声明一块暂时领地,当其他进程要来使用这块领地时,发现已经有一个进程在占有这块领地时不得不选择放弃或者等待。
2.Redis分布式锁的使用
在Redis中声明一块领地一般会使用setnx(set if not exists)指令,只允许被一个客户端占据。先到者先得,使用完成时调用del指令离开领地。
>setnx island-1 ll
(integer) 1
>setnx island-1 pp
(integer) 0
>get island-1
"ll"
>del island-1
(integer) 0
>get island-1
(nil)
但这样使用会出现一些问题,如果占到领地的进程执行到了一半,出现异常导致无法调用后续的del指令来释放,这样就会造成死锁的现象,那这块领地将会一直被占用,锁一直无法释放。
这时通常的做法是给这个锁添加一个过期时间,比如5s(expire key 5),这样即使中间出现了异常也可以保证5s之后锁会自动释放。
```Redis
>setnx island-2 ll
ok
>expire island-2 5
>get island-2
"ll"
...5s之后...
>get island-2
(nil)
```
但是这样做还是会有问题,如果程序在 setnx指令和expire指令之间挂掉如突然断电或人为操作等,那么同样可能会造成死锁现象。问题的根源在于setnx与expire指令并不是同时执行。
一般的想法可能会想到用事务来解决,但遗憾的是这种方法并不可行,因为expire是依赖于setnx的执行结果的,如果setnx圈地失败,expire就无法执行,而事务的特点就是要么全部执行, 要么都不执行。所幸在redis2.8以后的版本中添加了set指令的扩展参数,使得这个问题得以解决。
```Redis
>set island-2 ll ex 5 nx
ok
>get island-2
"ll"
... 5s之后...
>get island-2
(nil)
```
其中 nx( if not exists), ex即expire
3. Redis分布式锁扩展
===
3.1 超时问题
---
redis的分布式锁不能解决超时问题,原因在于如果加锁与释放锁之间执行的时间太长,以至于超过了设定的超时限制,就会导致第一个线程的逻辑还未执行完,其他线程就会劫持到这把锁。为了避免这种情况,Redis分布式锁一般不用于较长时间的任务。
3.2 可重入性
可重入是指在原先持有锁的情况下再次请求加锁,如果同一线程中的一个锁支持这种特性,那么这个锁就是可重入的。Redis分布式锁要想实现可重入性,就必须对客户端的set方法进行包装,使用线程的Threadlocal变量存储当前持有锁的计数。python版本的代码如下:
```python
import redis
import threading
locks = threading.local()
locks.redis = {}
def key_for(user_id):
return 'account_{}'.format(user_id)
# 加锁
def _lock(client,key):
return bool(client.set(key,True,nx=True,ex=5))
# 解锁
def _unlock(client,key):
client.delete(key)
# 执行加锁 + 计数
def lock(client,user_id):
key = key_for(user_id)
if key in locks.redis:
locks.redis[key] += 1
return True
ok = _lock(client,key)
if not ok:
return False
locks.redis[key] = 1
return True
# 执行解锁 + 计数
def unlock(user_id):
key = key_for(user_id)
if key in locks.redis:
locks.redis[key] -= 1
if locks.redis[key] <= 0:
del locks.redis[key]
return True
return False
client = redis.StrictRedis()
print('lock',lock(client,'ll')) # lock True
print('lock',lock(client,'ll')) # lock True
print('unlock',unlock('ll')) # unlock False 未完全解锁
print('unlock',unlock('ll')) # unlock False
<font size=3>
这并不是一个精确的可重入锁,还可以加入过期时间等等,但代码的复杂度会一直增加,所以并不推荐使用可重入锁。
</font>
-----------------------------------------------------------------------------------------
文章借鉴于《Redis深度历险:核心原理与应用实践》 --作者:钱文品
-----------------------------------------------------------------------------------------
Redis学习笔记01-分布式锁的更多相关文章
- Redis学习系列七分布式锁
一.简介 熟悉.Net多线程的都知道,当多个线程同时操作一个全局缓存对象(static对象实例.Dictionary.List等)时,会存在多线程争用问题,包括EF.Dapper等本身的缓存机制,都存 ...
- Redis学习笔记11--Redis分布式
Redis-2.4.15目前没有提供集群的功能,Redis作者在博客中说将在3.0中实现集群机制.目前Redis实现集群的方法主要是采用一致性哈稀分片(Shard),将不同的key分配到不同的redi ...
- redis学习笔记-01:redis简介
1.redis是一个高性能的Nosql数据库,遵守BSD协议,使用c语言编写.支持网络.可基于内存亦可持久化,是一种日志型.Key-Value数据库,也可看做是一个分布式的.基于内存的缓存工具. 2. ...
- redis学习笔记01 — 基本介绍、安装配置及常用命令
redis--NoSQL的一种 为了解决高并发.高可用.高扩展.大数据存储等一系列问题而产生的数据库解决方案,就是NoSQL NoSQL,非关系型数据库,全名:Not Only Sql,它不能代替关系 ...
- redis学习笔记-01 string类型命令
一.set key value set joker 123456 #设定key为joker,value为123456的数据 二.keys * keys * #用于查看该数据库中所有的key值 三.se ...
- Redis:学习笔记-01
Redis:学习笔记-01 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 1. Redis入门 2.1 ...
- Redis学习笔记~目录
回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...
- redis学习笔记(详细)——高级篇
redis学习笔记(详细)--初级篇 redis学习笔记(详细)--高级篇 redis配置文件介绍 linux环境下配置大于编程 redis 的配置文件位于 Redis 安装目录下,文件名为 redi ...
- redis 学习笔记(6)-cluster集群搭建
上次写redis的学习笔记还是2014年,一转眼已经快2年过去了,在段时间里,redis最大的变化之一就是cluster功能的正式发布,以前要搞redis集群,得借助一致性hash来自己搞shardi ...
- Redis学习笔记(1)——Redis简介
一.Redis是什么? Remote Dictionary Server(Redis) 是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value ...
随机推荐
- java 3des加密问题记录
3des加密有不同的加密模式和填充模式,这个网上很多不多说了,只要保证加解密的时候加密模式和填充模式保持一致就可以了 首先对于密钥的生成,java中有2种方式: 1.第一种,采用ECB模式和不填充模式 ...
- MySQL数据库之DML(数据操作语言)
对表记录的增删改 1.MySQL之DML创建数据表user create table user( id int unsigned not null auto_increment primary key ...
- 360自动抢票还不够,几行js代码设置无人值守
360就是牛逼哄哄的...... 但是最近在使用360浏览器抢票的时候还是发现了一些体验不好的地方,比如搞着搞着就退出了登录,有时候能帮你自动登录进去,但是自动登录之后又不会帮你自动开始抢.然后验证码 ...
- CSIC_716_20191101【编程语言、变量、垃圾回收机制】
编程语言分类:机器语言.汇编语言.高级语言. 机器语言:机器能直接识别的程序语言或指令代码(二进制指令),勿需经过翻译,每一操作码在计算机内部都有相应的电路来完成它 汇编语言:比机器语言略高级,用英文 ...
- delphi判断MDI窗体的子窗体是否存在
转]delphi判断MDI窗体的子窗体是否存在//*************************************************************************** ...
- linxu(centos)安装php-fpm
编译安装php-fpm 安装前准备 yum -y install gcc automake autoconf libtool make yum -y install gcc gcc-c++ glibc ...
- 现金贷平台下载量TOP100 涉逾30家P2P
一.什么是现金贷,现状如何 那么什么是现金贷呢?在笔者看来,狭义的现金贷主要是指基于互联网等技术手段的小额现金贷款,广义的现金贷可以包括任何以小额现金和存款为标的进行借贷的行为,是一种无担保.无抵押. ...
- Vue的组件及传参
目录 Vue的组件及传参 Vue组件的概念 根组件 子组件(局部组件) 父组件向子组件传值 子组件向父组件传值 Vue的组件及传参 Vue组件的概念 我们首先要知道组件的概念,实际上每一个组件都是一个 ...
- 零基础入门学习python--第二章 用Python设计第一个游戏
知识点汇总1. 什么是BIF? BIF(Built-in Functions)内置函数,共68个,可直接调用,方便程序员快速编写脚本程序.输入dir(__builtins__)即可查看所有内置函数,h ...
- POJ 3376 Finding Palindromes EX-KMP+字典树
题意: 给你n个串串,每个串串可以选择和n个字符串拼接(可以自己和自己拼接),问有多少个拼接后的字符串是回文. 所有的串串长度不超过2e6: 题解: 这题由于是在POJ上,所以string也用不了,会 ...