文档章节

redis做分布式锁这几个要注意

编辑之路
 编辑之路
发布于 2019/05/05 20:39
字数 1851
阅读 1.2K
收藏 4

一、为什么需要分布式锁

        随着互联网的兴起,现代软件发生了翻天覆地的变化,以前单机的程序,已经支撑不了现代的业务。无论是在抗压,还是在高可用等方面都需要多台计算机协同工作来解决问题。现代的互联网系统都是分布式部署的,分布式部署确实能带来性能和效率上的提升,但为此,我们就需要多解决一个分布式环境下,数据一致性的问题。

        当某个资源在多系统之间共享的时候,为了保证大家访问这个资源数据是一致的,那么就必须要求在同一时刻只能被一个客户端处理,不能并发的执行,否者就会出现同一时刻有人写有人读,大家访问到的数据就不一致了。

        在分布式系统的时代,传统线程之间的锁机制,就没作用了,系统会有多份并且部署在不同的机器上,这些资源已经不是在线程之间共享了,而是属于进程(服务器)之间共享的资源。

        因此,为了解决这个问题,我们就必须引入「分布式锁」。分布式锁,是指在分布式的部署环境下,通过锁机制来让多客户端互斥的对共享资源进行访问。分布式锁的特点如下:

1、互斥性

和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。

2、可重入性

同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。

3、锁超时

和本地锁一样支持锁超时,防止死锁。

4、高效,高可用

加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。

5、支持阻塞和非阻塞

和 ReentrantLock 一样支持 lock 和 trylock 以及 tryLock(long timeOut)。

二、基于redis分布式锁

        如果你通过网络搜索分布式锁,最多的就是基于redis的了。基于redis的分布式锁得益于redis的单线程执行机制,单线程在执行上就保证了指令的顺序化,所以很大程度上降低了开发人员的思考设计成本。但是,基于redis做分布式锁难道真的这么容易吗?

1、原子操作

基于redis的分布式锁常用命令是

SETNX key value

        只在键 key 不存在的情况下,将键 key的值设置为value 。若键key 已经存在, 则SETNX 命令不做任何动作。SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。代码示例:

redis> SETNX redislock "redislock"    # redislock 设置成功
(integer) 1
redis> SETNX redislock "redislock2"   # 尝试覆盖 redislock ,失败
(integer) 0
redis> GET redislock                   # 没有被覆盖
"redislock"

        成功获取到锁之后,然后设置一个过期时间(这里避免了客户端down掉,锁得不到释放的问题)

redis> expire redislock 5

成功拿到锁的客户端顺利进行自己的业务,业务代码执行完,然后再删除该key

redis> DEL redislock

        如果一切都想想象的那么顺利,程序员TMD就不用996了。假如客户端拿到锁之后,执行设置超时指令之前down掉了(现实总是那么悲剧),那这个锁就永远都释放不了.也许你会想到用 Redis 事务来解决。但是这里不行,因为 expire 是依赖于 setnx 的执行结果的,如果 setnx 没抢到锁,expire 是不应该执行的。事务里没有 if-else 分支逻辑,事务的特点是一口气执行,要么全部执行要么一个都不执行。公司几个亿的业务又被你耽误了...

        以上情况的出现是因为两个命令并非一个原子性操作,所以在redis 2.8 版本之后出现了新的命令

SETEX key seconds value

所以现在可以利用一条原子性操作的命令来获取锁

redis> SETEX redislock 60 redislock
OK
redis> GET redislock  # 值
"redislock"
redis> TTL redislock  # 剩余生存时间
(integer) 49

2、超时问题

        在正常的业务当中,当一个线程获取到锁并且设置了锁的过期时间之后,会出现由于业务代码执行时间过长,锁由于到达超时时间自动释放的情况。自动释放之后,其他的线程就会获取到分布式锁,导致业务代码不会串行执行。如果业务上允许这样的情况偶尔发生,那程序员就开干吧,最后顶多人工干预一下,update 一下数据库。

        为了避免这类情况发生,在使用redis分布式锁的时候,业务方应尽量避免长时间执行的代码任务。

        如果设置锁的超时时间比较长,在一定程度上可以缓解业务代码执行时间长锁自动到期的问题,但是一旦业务代码down掉,其他等待锁的线程等待的时间会比较长,这种情况下,确保获取到锁的程序不会down 成为了主要问题。

3、获取锁失败

当锁被一个调用方获取之后,其他调用方在获取锁失败之后,是继续轮询还是直接业务失败呢?如果是继续轮询的话,同步情况下当前线程会一直处于阻塞状态,所以这里轮询的情况还是建议使用异步。

4、可重入性

        可重入性是指已经拥有锁的客户端再次请求加锁,如果锁支持同一个客户端重复加锁,那么这个锁就是可重入的。如果基于redis的分布式锁要想支持可重入性,需要客户端封装,可以使用threadlocal存储持有锁的信息。这个封装过程会增加代码的复杂度,所以菜菜不推荐这样做。

5、redis挂了

        如果在多个客户端获取锁的过程中,redis 挂了怎么办呢?假如一个客户端已经获取到了锁,这个时候redis挂了(假如是redis集群),其他的redis服务器会接着提供服务,这个时候其他客户端可以在新的服务器上获取到锁了,这也导致了锁意义的丢失。有兴趣的同学可以去看看RedLock,这种方案以牺牲性能的代价解决了这个问题。

6、时钟跳跃问题

        在某些时候,redis的服务器时间发生的跳跃,由于锁的过期时间依赖于服务器时间,所以也会出现两个客户端同时获取到锁的情况发生。

© 著作权归作者所有

编辑之路
粉丝 54
博文 50
码字总数 109912
作品 0
长沙
私信 提问
加载中

评论(0)

jedisLock—redis分布式锁实现

搬运工:http://www.cnblogs.com/0201zcr/p/5942748.html jedisLock—redis分布式锁实现 一、使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用Reentrant...

北极之北
2017/01/06
1.3K
2
谈谈 redis 在项目中的常见使用场景

最近在写一个脚手架,其中 的使用场景还挺多,于是总结下它的常见使用场景 本文链接: shanyue.tech/post/redis-… github 备份: github.com/shfshanyue/… 缓存 缓存是 出镜率最高的一种使用...

shanyue
2019/07/17
0
0
基于redis的分布式锁的分析与实践

前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了。乐观锁和悲观锁最根本的区别...

菜蚜
2018/01/12
927
2
慢谈 Redis 实现分布式锁 以及 Redisson 源码解析

# 产生背景 Distributed locks are a very useful primitive in many environments where different processes must operate with shared resources in a mutually exclusive way. 在某些场景......

2019/01/30
0
0
Redis 常见的使用场景总结

最近在写一个脚手架,其中 的使用场景还挺多,于是总结下它的常见使用场景 本文链接: github 备份: 缓存 缓存是 出镜率最高的一种使用场景,仅仅使用 就可以实现,不过也有一些需要考虑的点 ...

shanyue
01/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

深圳哪里可以开家用电器发票-中国-新闻网

深圳哪里可以开家用电器发票【152 * 9б 28 * 21 б9】陈生,诚、信、合、作,保、真、售、后、保、障、长、期、有、效。adb的全称为Android Debug Bri...

17060824738
28分钟前
41
0
深圳哪里可以开劳保用品发票-中国-新闻网

深圳哪里可以开劳保用品发票【152 * 9б 28 * 21 б9】陈生,诚、信、合、作,保、真、售、后、保、障、长、期、有、效。adb的全称为Android Debug Bri...

17095420210
32分钟前
36
0
Mac OS X 10.15 编译和安装 Nginx

想在自己电脑里装个 Nginx 来进行各种测试,下面是详细的过程记录: 1. 下载软件 首先建个临时目录 nginx-src 并下载所需软件的源码进行配置 mkdir nginx-srccd nginx-srcwget http://n...

红薯
48分钟前
62
0
0228 我的潘多拉

我的潘多拉 从一个故事说起。<br />从前,有个Java程序员非常喜欢写程序,喜欢研究源码,读英文文档。但是它在一家小公司里工作,公司的技术栈很陈旧。<br /> <br />单个系统代码中含有很多的...

李福春carter
今天
18
0
OSChina 周六乱弹 —— 屁会不会传染病毒

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《ハレハレヤ(朗朗晴天)》- 猫瑾 手机党少年们想听歌,请使劲儿戳(这里) @空格...

小小编辑
今天
77
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部