浅谈“分布式锁”

政采云技术团队.png

云枫.png

序言

在单机时代,虽然不存在分布式锁,但也会面临资源互斥的情况,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制,即当某个线程获取到这个资源后,就需要对这个资源进行加锁,当使用完资源之后,再解锁,其它线程就可以接着使用了。例如,在 Java 中 synchronize/Lock 等。

但是到了分布式系统的时代,这种线程之间的锁机制,就没作用了,系统可能会有多份并且部署在不同的机器上,这些资源已经不是在线程之间共享了,而是属于进程之间共享的资源。因此,为了解决这个问题,「分布式锁」就出现了。

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

分布式锁特性

分布式锁特性

常用实现方案

常用实现方案

基于数据库实现

基于数据库实现-乐观锁

乐观锁的特点先进行业务操作,不到万不得已不去拿锁。“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。

乐观锁机制是在数据库表中引入一个版本号(version)字段来实现

当我们要从数据库中读取数据的时候,同时把这个 version 字段也读出来,如果要对读出来的数据进行更新后写回数据库,则需要将 version 加 1,同时将新的数据与新的 version 更新到数据表中,且必须在更新的时候同时检查目前数据库里 version 值是不是之前的那个 version ,如果是,则正常更新。如果不是,则更新失败,说明在这个过程中有其它的进程去更新过数据了

乐观锁遵循的两点法则:

  • 锁服务要有递增的版本号 version
  • 每次更新数据的时候都必须先判断版本号对不对,然后再写入新的版本号

image-20230210180953346

基于数据库实现-悲观锁

悲观锁的特点是先获取锁,再进行业务操作,即*“悲观”*的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作

通常所说的“一锁二查三更新”即指的是使用悲观锁。

当数据库执行 select for update 时会获取被 select 中的数据行的行锁

并发执行的 select for update 选中同一行则会发生排斥(需要等待行锁被释放),以此达到锁的效果

select for update 获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用

image-20230210181155988

基于数据库实现-总结

image-20230210181223422

基于redis实现

基于 Redis 实现的锁机制,主要是依赖 Redis 自身的原子操作

实现思想

  1. 获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的 value 值为一个随机生成的 UUID ,通过此在释放锁的时候进行判断
  2. 获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁
  3. 释放锁的时候,通过 UUID 判断是不是该锁,若是该锁,则执行del进行锁释放

基于redis实现-原理

image-20230210181345157

基于redis实现-总结

image-20230210181445893

基于 ZooKeeper 实现

基于 ZooKeeper ,就是使用它的临时有序节点来实现的分布式锁。

实现思想:

(1)创建一个目录 mylock;

(2)线程A想获取锁就在 mylock 目录下创建临时顺序节点;

(3)获取 mylock 目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;

(4)线程 B 获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;

(5)线程 A 处理完,删除自己的节点,线程 B 监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。

基于 ZooKeeper 实现-原理

image-20230210181554689

基于ZooKeeper实现-curator

lQDPJxWUHm3G56DNAgrNBACwX-ADj2i2bdgEFBNEMwB1AA_1024_522.jpg

基于ZooKeeper实现-总结

image-20230210181628461

总结

分布式锁有很多种,”相对主流的有三种”只是个人愚见。

分布式锁千变万化,具体的实现方案按照自己的场景及条件实现。

本质还是针对同步资源的合理占用,最理想的方式就是不用加锁就可以避免并发操作

推荐阅读

浅析基于Spring Security 的身份认证流程

MySQL - InnoDB 内存结构解析

浅谈AI目标检测技术发展史

数据仓库模型重构实践

从源码看Lucene的两阶段提交

招贤纳士

政采云技术团队(Zero),一个富有激情、创造力和执行力的团队,Base 在风景如画的杭州。团队现有 500 多名研发小伙伴,既有来自阿里、华为、网易的“老”兵,也有来自浙大、中科大、杭电等校的新人。团队在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊……如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com

微信公众号

文章同步发布,政采云技术团队公众号,欢迎关注

政采云技术团队.png