点击上方“蓝字”带你去看小星星

菜菜哥,复联四上映了,要不要一起去看看?

又想骗我电影票,对不对?

呵呵,想去看了叫我呀

看来你工作不饱和呀

哪有,这两天我刚基于redis写了一个分布式锁,很简单

不管你基于什么做分布式锁,你觉得很简单吗?来来来

在计算机世界里,对于锁大家并不陌生,在现代所有的语言中几乎都提供了语言级别锁的实现,为什么我们的程序有时候会这么依赖锁呢?这个问题还是要从计算机的发展说起,随着计算机硬件的不断升级,多核cpu,多线程,多通道等技术把计算机的计算速度大幅度提升,原来同一时间只能执行一条cpu指令的时代已经过去。随着多条cpu指令可以并行执行的原因,原来不曾出现的资源竞争随着出现,在程序中的体现就是随处可见的多线程环境。比如要更新数据库的一个信息,如果没有并发控制,多个线程同时操作的话,就会出现互相覆盖的现象发生。

锁要解决的就是资源竞争的问题,也就是要把执行的指令顺序化

01为什么需要分布式锁

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

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

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

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

1互斥性和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。2可重入性同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。3锁超时和本地锁一样支持锁超时,防止死锁。4高效,高可用加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。5支持阻塞和非阻塞和 ReentrantLock 一样支持 lock 和 trylock 以及 tryLock(long timeOut)。
02基于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 redislockOK

redis> GET redislock  # 值"redislock"

redis> TTL redislock  # 剩余生存时间(integer) 49

2超时问题

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

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

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

3获取锁失败

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

4可重入性

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

5redis挂了

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

6时钟跳跃问题

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

当把以上问题都有解决方案了之后,基于redis的分布式锁才可以放心使用


基于redis设计简单分布式锁容易,但是设计完美分布式锁不易, 还觉得基于redis的分布式锁好做吗?

●程序员修神之路--问世间异步为何物?●程序员修神之路--提高网站的吞吐量?●程序员修神之路--?分布式高并发下Actor模型如此优秀?●程序员过关斩将--论商品促销代码的优雅性●程序员过关斩将--请不要随便修改基类●程序员过关斩将--你的面向接口编程一定对吗?●程序员修神之路--高并发下为什么更喜欢进程内缓存●程序员修神之路--高并发优雅的做限流

架构师之路,菜菜与君一起成长

长按识别二维码关注

程序员修神之路--redis做分布式锁可能不那么简单相关推荐

  1. 程序员修神之路--高并发优雅的做限流(有福利)

    点击上方蓝色字体,关注我们 菜菜哥,有时间吗? YY妹,什么事? 我最近的任务是做个小的秒杀活动,我怕把后端接口压垮,X总说这可关系到公司的存亡 简单呀,你就做个限流呗 这个没做过呀,菜菜哥,帮妹子写 ...

  2. 程序员修神之路--用NOSql给高并发系统加速

    领取福利 记得长按,领取技术书籍哦 随着互联网大潮的到来,越来越多网站,应用系统需要海量数据的支撑,高并发.低延迟.高可用.高扩展等要求在传统的关系型数据库中已经得不到满足,或者说关系型数据库应对这些 ...

  3. 程序员修神之路--高并发下如何缩短响应时间

    点击上方"蓝字"带你去看小星星 菜菜哥,请你看电影呀,但是得帮我一个忙 好呀,看什么? 哥斯拉2:怪兽之王 看过了~ X战警:黑凤凰 看过了 追龙2和黑衣人呢? 都看过了,你说帮什 ...

  4. 程序员修神之路--问世间异步为何物?

    菜菜哥,今天天气挺热的,我都穿裙子了 说吧,什么事?? 苦笑一下..... 老大说把所有的接口都改成异步操作 异步好呀,最少比同步能提高吞吐量 异步是怎么回事呢,能讲讲不? 来,凑近一点,哥给你解释一 ...

  5. 多个容器一起打包_程序员修神之路容器技术为什么会这么流行(记得去抽奖)

    菜菜哥,你上次讲的kubernetes我研究了一下,你再给我讲讲docker呗 docker可很流行呀 kubernetes是容器编排技术,容器不就是指的docker吗? docker可不等于容器哦, ...

  6. 程序员修神之路--晦涩难懂的CAP,是否完全正确?

    微信搜一搜 架构师修行之路 菜菜哥,帮忙解决一个问题 是不是面试又被虐了? 是的呢,这次面试官问我什么是CAP? 这个可就说来话长了...... 01 PART CAP 说到CAP,首先不能不说分布式 ...

  7. 程序员修神之路--简约而不简单的分布式通信基石

    点击"蓝字"关注,领取架构书籍 菜菜哥,请教一个问题呗 面试又被卡住了? 还是你了解我呀,tcp协议面向连接是怎么回事呢? 这个说详细起来,那本好几百页的tcp协议的书籍你倒是可以 ...

  8. 程序员修神之路--打通Docker镜像发布容器运行流程

    菜菜哥,我看了一下docker相关的内容,但是还是有点迷糊 还有哪不明白呢? 如果我想用docker实现所谓的云原生,我的项目该怎么发布呢? 这还是要详细介绍一下docker了 Docker 是一个开 ...

  9. 程序员修神之路--容器技术为什么会这么流行(记得去抽奖)

    菜菜哥,你上次讲的kubernetes我研究了一下,你再给我讲讲docker呗 docker可很流行呀 kubernetes是容器编排技术,容器不就是指的docker吗? docker可不等于容器哦, ...

最新文章

  1. Mybatis学习记录-使用问题总结之一DISTINCT
  2. 未能加载文件或程序集“*****.dll”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。(异常来自HRESULT:0x80131040)
  3. TCP/IP 广播的发送和接收
  4. 简单插入排序,折半插入排序和2路插入排序 c源码
  5. MongoDB实战(7)索引与性能
  6. jdbc连接数据scanip_JDBC连接数据库的四种方式:DriverManager,DataSource,DBCP,C3P0
  7. 【吼吼睡cocos2d学习笔记】第四章 - 第一个游戏
  8. 面试官:Redis中的缓冲区了解吗
  9. c语言pic延时1ms程序,几个延时子程序
  10. 手机wps取消不等宽分栏_wps取消分栏怎么设置
  11. 泛微某oa系统ssrf漏洞分析
  12. 【Qt学习】 一键生成函数注释
  13. Xcode14 build WebDriverAgent提示“Cannot link directly with dylib/framework“的解决方法
  14. 新版标准日本语中级_第十一课
  15. 15个小时彻底搞懂NLP自然语言处理(2021最新版附赠课件笔记资料)【LP自然语言处理涉及到深度学习和神经网络的介绍、 Pytorch、 RNN自然语言处理】 笔记
  16. 深度学习与计算机视觉系列(5)_反向传播与它的直观理解
  17. 蒲慕明院士PNAS最新研究:神经元数量在共同激活诱导大脑神经元兴奋性增强的重要性...
  18. Mysqldump参数解析大全
  19. Arm架构的M1芯片MacOs下如何安装Windows虚拟机
  20. 快速入门网络爬虫系列 Chapter16 | 爬虫性能提升

热门文章

  1. 使Safari在Windows Vista上每20秒停止崩溃
  2. 如何重新打开Windows防火墙提示?
  3. 用户帐户控制设置_创建快捷方式以避免用户帐户控制弹出式快捷方式
  4. python 位置参数、默认参数、可变参数位置关系_python的位置参数、默认参数、关键字参数、可变参数区别...
  5. 打游戏要存进度-备忘录模式
  6. MySQL安装时出现的问题
  7. 数据挖掘——数据仓库
  8. Scribefire发CSDN博客
  9. 写在《ASP.NET MVC 4 Web 编程》即将出版之际!献给有节操的程序员!
  10. .NET6之MiniAPI(二十五):Dapper