Redis之分布式锁
一、加锁原因
在一些比较高并发的业务场景,经常听到通过加锁的方法实现线程安全。
下面简单介绍一下
1.1 加锁方式
数据库锁
数据库本身提供了锁机制,比如乐观锁、悲观锁等等。下面给出我之前写的一篇博客,介绍一下mysql数据库的锁机制
Mysql的锁机制
单体环境
Java线程层面,Java的jdk本身就提供了,比如synchronized和ReentrantLock可重入锁。这是实现单体环境锁的一种方法,这里简单介绍一下,并不对synchronized和ReentrantLock进行详细介绍。
分布式环境
上面介绍的都是单体环境的和数据库层面的,下面介绍一下分布式环境的解决方法。分布式环境有两种比较常用的解决方法,一种是通过Zookeeper实现分布式;一种是通过Redis实现分布式锁。本博客比较详细地介绍一下redis分布式锁,对于Zookeeper分布式锁有时间再写博客介绍。
1.2 业务场景
为什么加锁?从业务来说其实就是有业务场景,技术层面是为了保证线程安全性,也就是说保证线程操作是原子操作。
下面简单介绍一下一些业务场景
比如电商的秒杀场景,这就是一个高并发场景了,假如一个用户购买了库存只有10的8件商品,另外一个用户也要购买5件商品,这两个用户是同时进行的,第一个用户买了8件,库存就只有2件了,第二个用户再买5件,注意是和第一个用户操作同时进行的,这时也是10-5,库存只有5件了。假如第一个用户抢占了,库存优先减8了,第一个用户进行操作,同时进行,获取到的库存是10,这时就会出现业务问题了。
二、原子操作
原子操作定义
博客介绍一下原子操作,为什么说到原子操作呢?貌似和分布式锁不搭边,其实不是的,我们说加锁,其本质目的就是为了实现线程操作是原子性的,也就是原子操作。
原子操作:是指不会被线程调度机制打断的操作,而且期间不会有任何上下文切换(context switch)。
2.1 context switch
上面介绍一下上下文切换(context switch),上下文切换是计算机的cpu从一个任务,或者说进程,从一个任务(进程)切换到另外一个任务(进程),期间确保任务(进程)不冲突的过程。
在国外的whatis.techtarget网站有进行了比较详细的定义
上下文切换定义
三、分布式锁
3.1 实现方式
可以实现方式 setnx+expire
在Redis中实现分布式锁,可以通过setnx和expire实现,setnx命令意思是set key if not exist,就是说已经有一个线程占用了,就不执行set key操作
语法:setnx key value;expire是设置key的时间
这里setnx key为tkey,value为tvalue
>setnx tkey tvalue
OK
>get tkey
tvalue
>expire tkey 5
OK
>del tkey
(integer) 1
先setnx,然后再给key加一个时间5秒,5秒后自动释放锁。当然一个进程执行过程还没5秒也可以就直接删除key。那么假如在setnx过程出现异常,锁就不能释放。
为了避免上面所说的分布式锁不能释放问题,开源社区有很多分布式解决方案,很多第三方库,直到redis2.8版本,作者给出了一个很好的解决方案。
redis2.8版本对setnx命令和expire命令进行了拓展,使这两个命令可以同时执行,也可以理解为同个事务了。
语法:
setnx key ex time nx
例子,设置tkey,时间为5秒
setnx tkey ex 5 nx
四、分布式锁常见问题
4.1 超时问题
假如在释放锁和另一个线程重新占用锁之间,执行时间过长,超过了锁的超时设置,这时候就会出现,第一个线程的锁已经被标记为过期了,可是在临界区的执行程序还没执行,也就是说锁并没有真正释放。这时候如果第二个线程持有了锁,就会出现临界区的代码不能正常串行执行,因为第一个线程的锁在临界区还没真正释放。
这是一种比较常见的Redis锁不能释放的超时问题。
通过网上资料,有提供了一种解决方案思路,是通过在set key的时候给value值加一个时间戳字符串或者一个特定的随机数,比如uuid,可以表示特定线程的标识,这个标识要唯一。
然后在删除key,重新加锁的时候,校验这个value是否为第一个线程的,匹配正确才删除key,这是一种方案,当然并不是很好的解决方案,只能说是相对安全的,因为在高并发情况下面,线程的调用机制还是可以支持另外的线程持有锁的。
4.2 集群环境
下面介绍一下集群环境的锁问题,业务场景,假如一个线程在主服务器(master)释放锁的时候,master突然冗机了,也是就是说锁还没被释放。这时集群环境检测到master机器冗机,就切换从服务器(slave)作为主服务器,这时候,另外一个线程进来了,占有了同一个锁,也就是出现了两个线程同时占有同一个锁的情况了。通过keepalive和redis实现主从服务器自动failover的方式或许可以解决问题。因为并没有实践过,所以不做详细解释。这篇博客
Redis自从自动failover或许可以参考。
ReadLock算法
集群环境的锁同步是一个难题。上面的仅仅是我的想法并没有实践过,最近找到一个算法可以解决,ReadLock算法。readlock-py库已经有对改算法进行实践。ReadLock算法简单原理就是通过先检测set是否成功,set成功之后才向所有节点发送指令,释放锁。本博客并不对ReadLock算法做详细介绍,有机会再写博客介绍。
Redis之分布式锁的更多相关文章
- 基于redis 实现分布式锁的方案
在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题.如果在库存操作上,加锁就可以避免库存卖超的问题.分布式锁使分布式系统之间同步访问共享资源的一种方式 基于redis实现分布式锁 ...
- 用Redis构建分布式锁-RedLock(真分布)
在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简单的实现其实只需采用稍微增 ...
- 用Redis实现分布式锁 与 实现任务队列(转)
这一次总结和分享用Redis实现分布式锁 与 实现任务队列 这两大强大的功能.先扯点个人观点,之前我看了一篇博文说博客园的文章大部分都是分享代码,博文里强调说分享思路比分享代码更重要(貌似大概是这个意 ...
- 利用多写Redis实现分布式锁原理与实现分析(转)
利用多写Redis实现分布式锁原理与实现分析 一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...
- Redis实现分布式锁
http://redis.io/topics/distlock 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但 ...
- 基于redis的分布式锁
<?php /** * 基于redis的分布式锁 * * 参考开源代码: * http://nleach.com/post/31299575840/redis-mutex-in-php * * ...
- Redis实现分布式锁与任务队列
Redis实现分布式锁 与 实现任务队列 这一次总结和分享用Redis实现分布式锁 与 实现任务队列 这两大强大的功能.先扯点个人观点,之前我看了一篇博文说博客园的文章大部分都是分享代码,博文里强调说 ...
- 使用Redis实现分布式锁
在天猫.京东.苏宁等等电商网站上有很多秒杀活动,例如在某一个时刻抢购一个原价1999现在秒杀价只要999的手机时,会迎来一个用户请求的高峰期,可能会有几十万几百万的并发量,来抢这个手机,在高并发的情形 ...
- 基于Redis实现分布式锁(1)
转自:http://blog.csdn.net/ugg/article/details/41894947 背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部 ...
- redis咋么实现分布式锁,redis分布式锁的实现方式,redis做分布式锁 积极正义的少年
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
随机推荐
- struts 1.x配置文件说明
<struts-config> <global-exceptions /> <!--全局映射定义--> <global-forwards> <fo ...
- linux ssh反向代理
参考:https://segmentfault.com/a/1190000002718360 内外运行:sshpass -p 123456 ssh -fNR 5000:localhost:22 ser ...
- [树上倍增+二分答案][NOIP2012]运输计划
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 公元 2044 年,人类进入了宇宙纪元 L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n− ...
- 行盒(line box)垂直方向的属性详解:从font-size、line-height到vertical-align
视觉格式化模型 在一个文档中,每个元素都被表示为0.1或多个矩形的盒子.确定这些盒子的尺寸, 属性 --- 像它的颜色,背景,边框方面 --- 和位置是渲染引擎的目标.① 在CSS中,使用标准盒模型描 ...
- excel支持正则表达式提取字符函数(支持RegExp捕获分组)
一.要让excel脚本支持Microsoft VBScript Regular Expressions 5.5 ,按快捷键alt+F11,出现下图界面,操作如图示: 二.添加VBA代码: 代码添加完毕 ...
- 修改云主机windows密码不生效
Step1:使用文本工具打开插件路径: 路径为:C:\Program Files\Cloudbase Solutions\Cloudbase-Init\Python\Lib\site-packages ...
- s6-9 TCP 定时器
TCP 定时器管理 重传定时器(retransmission timer,Positive ackn. with retransmit) 最重要的定时器 TCP 定时器管理 持续定时器(per ...
- window.open()新开网页被拦截
问题:同一个项目,同一个浏览器,不同模块,相同的代码(同是window.open()),为何一个直接打开,另一个直接被拦截? 原因:查资料发现为浏览器的广告拦截功能导致. 补充: 1.一般情况下,js ...
- 哈夫曼(Huffman)树和哈夫曼编码
一.哈夫曼(Huffman)树和哈夫曼编码 1.哈夫曼树(Huffman)又称最优二叉树,是一类带权路径长度最短的树, 常用于信息检测. 定义: 结点间的路径长度:树中一个结点到另一个结点之间分支数目 ...
- Servlet中的jsp内置对象
Servlet和jsp本质相同,那么为什么还要使用jsp呢,原来的servlet又有什么不好的呢. Servlet和jsp可以做完全相同的事情,就要借助jsp的内置对象们,比如request,resp ...