搜索
首页数据库Redis浅析Redis中的锁,聊聊Redlock(redis分布式锁)

浅析Redis中的锁,聊聊Redlock(redis分布式锁)

Jan 20, 2022 am 10:07 AM
redisredlock分布式锁

本篇文章带大家聊聊Redis中的锁,介绍一下为什么要用锁,真的需要Redlock(redis分布式锁)吗,希望对大家有所帮助!

浅析Redis中的锁,聊聊Redlock(redis分布式锁)

为什么要用锁

我待过的一家k12教育公司,我们当时有个业务场景是这样的。业务这边要给学生排课,偶尔会反馈学生的课时明明充足的但是却提示课时不足,等再刷新一遍页面却发现学生的课时已经不够了。更可怕的是,偶尔会有学生的课时被扣成负数(公司被白嫖课时)。【相关推荐:Redis视频教程

再比如下面这个例子

1.png

上面的这俩个问题都是并发给我们的业务带来的问题。解决这个问题的核心就是,同一时间只能允许有一个请求来对这些敏感(重要)的数据进行读写操作。所以这个时候就要使用到分布式锁来限制程序的并发执行。

setnx有哪些问题

我们先来看看用Redis如何实现分布式锁,想必大家都很熟悉。比如针对我文章开头讲的学生排课的问题我们就可以这样加锁

2.png

这就是我们常规使用setnx来实现锁的方式。

现在我们假设有这样一个场景。A请求拿到锁到了第2步给学生排课的时候程序挂了,没有释放锁。那么这个锁就成了死锁,下一个操作同一个学生的请求永远就拿不到锁,那么这个学生就没法被排课了。这个时候都需要手动去把锁释放掉。

为了解决死锁的问题,我们给锁加一个过期时间。

3.png

加上过期时间之后,如果A请求没有主动释放锁,在锁过期之后也会主动释放,这样B请求一样可以获取锁处理业务逻辑。但是如果在加过期时间的时候也就是在第1步和第2步之间程序崩溃。那还是会出现死锁的问题。这个问题的根源就在于setnx和expire这两条指令不是原子指令。所以如果setnx和expire能够要么全部执行要么一个都不执行那该多好。

为此在Redis2.8之前社区涌现了一大批扩展包来解决该问题。官方为了治理该乱象,在2.8版本中加入了set指令的扩展参数使得setnx和expire指令可以一起执行,所以现在我们使用分布式锁应该是这样了

4.png

这样看起来已经很完美了,已经达成了我们的期望“setnx和expire能够要么全部执行要么一个都不执行那该多好”。我们再假设现在有如下场景:

A请求现在获取到了锁,锁的超时时间设置的是5秒。到了第2步执行业务逻辑,结果因为某些原因5秒之后业务逻辑还没有执行完,此时锁由于超时自动释放了。这个时候B请求也来了,拿到锁之后开始执行业务逻辑。A请求这个时候业务逻辑执行完了,开始执行第三步,释放了锁。而这个时候锁是B请求拿到的,结果被A请求释放了。那么C请求就可以拿到锁了。这个时候B请求和C请求就会导致并发问题了。所以可以从这个例子看出来,在分布式锁中过期时间的设置非常重要,如果设置的时间小于这个接口的响应时间那么仍然会产生并发问题。所以我们可以参考接口响应时长的监控来设置锁的过期时间。

Redlock

我们上述的方案都是基于单点的Redis的实现方式。单点的Redis实现分布式锁基本上可以满足95%的业务场景。剩下的5%就是对数据一致性要求极其严苛并且对于锁丢失的0容忍的业务场景。这个时候就得考虑Redlock了。至于单点的Redis即使通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,如果数据主从数据同步不及时那么势必会有数据丢失,那么就会出现锁丢失的情况。

假设存在多个Redis实例,这些节点是完全独立的,不需要使用复制或者任何协调数据的系统,我们假设有5个Redis master节点,客户端为了取到锁,步骤将会变成这样:

  • 以毫秒为单位获取当前的服务器时间

  • 尝试使用相同的key和随机值来获取锁,客户端对每一个机器获取锁时都应该有一个超时时间,比如锁的过期时间为10s,那么获取单个节点锁的超时时间就应该为5到50毫秒左右,他这样做的目的是为了保证客户端与故障的机器连接不耗费多余的时间!超时间时间内未获取数据就放弃该节点,从而去下一个Redis节点获取。

  • 获取完成后,获取当前时间减去步骤一获取的时间,当且仅当客户端从半数以上(这里是3个节点)的Redis节点获取到锁且获取锁的时间小于锁额超时时间,则证明该锁生效!

  • 如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。

  • 如果获取锁的机器不满足半数以上,或者锁的超时时间计算完毕后为负数等异常操作,则系统会尝试解锁所有实例,即便某些Redis实例根本就没有加锁成功,防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁

所以我们看出,redlock其实是比单点Redis看起来更加可靠的锁。

如果你跟我一样是Node.js程序员那么正好有第三方库redlock直接使用。

我们真的需要redlock吗

关于redlock其实也有另外一种声音,Martin Kleppmann(剑桥大学的研究员,从事数据库、分布式系统和信息安全交叉领域的TRVE DATA项目)写过一篇blog发表了关于对redlock的一些看法,感兴趣的可以看看。Redis作者Salvatore也对这篇文章的疑问做出了一些回应,还挺有意思的。作者的blog主要的观点如下:

分布式锁的用途无非两种:

  • 效率:使用锁可以避免不必要地做同样的工作两次(例如一些昂贵的计算)。如果锁定失败并且两个节点最终完成相同的工作,结果是成本略有增加(您最终向 AWS 支付的费用比其他情况多 5 美分)或带来轻微的不便(例如,用户最终两次收到相同的电子邮件通知)。
  • 正确性:使用锁可以防止并发进程相互干扰并破坏系统状态。如果锁定失败并且两个节点同时处理同一条数据,则结果是文件损坏、数据丢失、永久性不一致、给患者服用的药物剂量错误或其他一些非常严重的问题。

如果是为了效率,则根本没有必要承担 Redlock 的成本和复杂性,锁丢失导致多发几次邮件和运行 5 个 Redis 服务器的成本相比,最好只使用单个 Redis 实例。如果你使用的是单个 Redis 实例,Redis 节点突然断电或者崩溃,或者出现其他问题,这个时候当然会丢失锁。但是如果你只是将锁用作效率优化,而且这种崩溃不会经常发生,那没什么大不了的。这种“没什么大不了”的场景是 也恰好是Redis优秀的地方。至少如果依赖单个 Redis 实例,那么查看系统的每个人都能够更方便的定位问题。

如果是为了正确性,那么严格来讲,redlock根本不具有强一致的严格性。举了一些例子

  • 时序和系统时钟做出了危险的假设,对每台服务器的时钟强依赖。因为有系统有GC的存在,做GC的时整个服务器是夯住的,时间也就停滞了,所以我们不能够对时钟有强依赖。

  • 没有令牌。客户端每次获取锁的时候服务端没有下发令牌,服务端应该校验每次操作的时候客户端的令牌要与服务端当前的令牌一致才难操作锁。

作者主要就是以上这些个观点,如果感兴趣的还是推荐去看看原文吧。

更多编程相关知识,请访问:编程入门!!

以上是浅析Redis中的锁,聊聊Redlock(redis分布式锁)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:掘金社区。如有侵权,请联系admin@php.cn删除
REDIS:探索其功能和功能REDIS:探索其功能和功能Apr 19, 2025 am 12:04 AM

Redis脱颖而出是因为其高速、多功能性和丰富的数据结构。1)Redis支持字符串、列表、集合、散列和有序集合等数据结构。2)它通过内存存储数据,支持RDB和AOF持久化。3)从Redis6.0开始引入多线程处理I/O操作,提升了高并发场景下的性能。

Redis是SQL还是NOSQL数据库?答案解释了Redis是SQL还是NOSQL数据库?答案解释了Apr 18, 2025 am 12:11 AM

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo

REDIS:提高应用程序性能和可扩展性REDIS:提高应用程序性能和可扩展性Apr 17, 2025 am 12:16 AM

Redis通过缓存数据、实现分布式锁和数据持久化来提升应用性能和可扩展性。1)缓存数据:使用Redis缓存频繁访问的数据,提高数据访问速度。2)分布式锁:利用Redis实现分布式锁,确保在分布式环境中操作的安全性。3)数据持久化:通过RDB和AOF机制保证数据安全性,防止数据丢失。

REDIS:探索其数据模型和结构REDIS:探索其数据模型和结构Apr 16, 2025 am 12:09 AM

Redis的数据模型和结构包括五种主要类型:1.字符串(String):用于存储文本或二进制数据,支持原子操作。2.列表(List):有序元素集合,适合队列和堆栈。3.集合(Set):无序唯一元素集合,支持集合运算。4.有序集合(SortedSet):带分数的唯一元素集合,适用于排行榜。5.哈希表(Hash):键值对集合,适合存储对象。

REDIS:对其数据库方法进行分类REDIS:对其数据库方法进行分类Apr 15, 2025 am 12:06 AM

Redis的数据库方法包括内存数据库和键值存储。1)Redis将数据存储在内存中,读写速度快。2)它使用键值对存储数据,支持复杂数据结构,如列表、集合、哈希表和有序集合,适用于缓存和NoSQL数据库。

为什么要使用redis?利益和优势为什么要使用redis?利益和优势Apr 14, 2025 am 12:07 AM

Redis是一个强大的数据库解决方案,因为它提供了极速性能、丰富的数据结构、高可用性和扩展性、持久化能力以及广泛的生态系统支持。1)极速性能:Redis的数据存储在内存中,读写速度极快,适合高并发和低延迟应用。2)丰富的数据结构:支持多种数据类型,如列表、集合等,适用于多种场景。3)高可用性和扩展性:支持主从复制和集群模式,实现高可用性和水平扩展。4)持久化和数据安全:通过RDB和AOF两种方式实现数据持久化,确保数据的完整性和可靠性。5)广泛的生态系统和社区支持:拥有庞大的生态系统和活跃社区,

了解NOSQL:Redis的关键特征了解NOSQL:Redis的关键特征Apr 13, 2025 am 12:17 AM

Redis的关键特性包括速度、灵活性和丰富的数据结构支持。1)速度:Redis作为内存数据库,读写操作几乎瞬时,适用于缓存和会话管理。2)灵活性:支持多种数据结构,如字符串、列表、集合等,适用于复杂数据处理。3)数据结构支持:提供字符串、列表、集合、哈希表等,适合不同业务需求。

REDIS:确定其主要功能REDIS:确定其主要功能Apr 12, 2025 am 12:01 AM

Redis的核心功能是高性能的内存数据存储和处理系统。1)高速数据访问:Redis将数据存储在内存中,提供微秒级别的读写速度。2)丰富的数据结构:支持字符串、列表、集合等,适应多种应用场景。3)持久化:通过RDB和AOF方式将数据持久化到磁盘。4)发布订阅:可用于消息队列或实时通信系统。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境