Redis作为分布式锁

为什么需要使用分布式锁?

因为在一个分布式系统中,存在多个进程,多个进程之间也存在访问同一个公共资源的情况,多个进程之间的执行顺序是随机性的,此时就需要通过"锁"来达到互斥控制。

比如买票的时候:

此时我们就可以引入redis作为分布式锁

在redis中设置一个特殊的key-value,完成上述买票操作,再把key-value删除,其他服务器在也想买票的时候,就需要尝试设置key-value,如果发现key-value已经存在,就认定为加锁失败(放弃/等待)。执行完之后再删除对应的key,完成解锁操作。

什么是分布式锁

所谓的分布式锁,也是一个/一组单独的服务器程序,提供"加锁"这样的服务。(redis是一种典型的可以用来实现分布式锁的方案,但不是唯一一种,业界可能也会使用mysql/zookeeper这样的组件来实现分布式锁的效果)。

刚才买票的场景,使用mysql的事务也可以批量执行 查询+修改操作,但是分布式系统中,要访问的共享资源不一定是mysql...也可能是执行一段特定的操作,是通过统一的服务器完成执行动作。

引入过期时间

对于上述的设置key-value的方法,如果服务器在执行del突然服务器宕机了,就会出现无法皆所得情况。此时就可以对用来加锁的key设置过期时间,防止服务器宕机无法解锁。

比如使用 set ex nx 命令

引入校验id

上面设置的key-value,服务器1设置了key之后,其他服务器也可以进行删除,为了解决这个问题,我们引入校验id,比如把value设置为服务器的编号,这样其他服务器在获取到value之后,就可以根据value进行判断是不是自己设置的key。

引出lua脚本

此时虽然看上去没有什么问题,但是此时如果有另外一个服务器,在线程1删除之后设置了key,此时线程2再进行删除,就会导致这个另外的服务器的加锁被错误的解锁。

归根到底还是GET和DEL操作不原子的所引起的。

使用事务,能解决上述的问题(redis的事务虽然弱,但是能保证避免插队)

但是实践中往往使用更好的方案,lua脚本

lua是一个编程语言,作为redis内嵌语言,特别轻量,可以使用lua编写一些逻辑,把这个脚本上传到redis服务器上,然后让客户端来控制redi执行上述脚本,也是原子的,相当于一条命令一样

引出看门狗

在加锁的时候给key设置多久的过期时间比较合适呢?

如果设置的短,就可能在你的业务逻辑还没执行完,就释放锁了。

如果设置的太长,就会导致"锁释放的不及时"的问题

更好的办法是"动态续约"。(往往也需要一个服务器单独的线程负责续约这个事情)

比如:初始条件下,设置一个过期时间(比如设置1s)就提前在还剩下300ms(还剩下一段时间,不一定是300ms)的时候,如果当前任务还没执行完,就把过期时间再续上1s.等到时间又快到了,如果没执行完,再续....

如果服务器中途崩溃了,自然就没人负责续约了,此时,锁也就能够在较短的时间里释放了。

引出Redlock算法

使用redis作为分布式锁,redis自身也是有可能挂的,所以必需要保证redis本身的高可用性

redis可以使用集群(主要是解决内存问题)或者哨兵的方式保证高可用性

但是主节点和从节点之间的数据同步是存在延时的,可能主节点收到set请求之后,还没来得及给从节点同步,主节点就挂了,就会导致这次set的数据丢失。

redlock算法(作者给出的一个解决方案) 通过存放冗余的数据来保证数据不丢失

此处加锁,就是按照一定的顺序,针对这些组redis都进行加锁,如果某个节点挂了,继续给下一个节点加锁即可,如果写入key成功的节点个数超过总数的一半,就视为加锁成功。同时解锁也是相同的操作

上述介绍的只是一个简单的"互斥锁"

redis也是可以实现以下这些锁的

1.读写锁

2.公平锁

3.可重入锁

相关推荐
倔强的石头_1 天前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou643 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤3 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
初次攀爬者4 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
爱可生开源社区4 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1775 天前
《从零搭建NestJS项目》
数据库·typescript
加号35 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏5 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐5 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
百锦再5 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip