分布式锁

深入理解
误删除
redisson中的看门狗机制总结
etcd等实现

序言

在单机时代,虽然不存在分布式锁,但也会面临资源互斥的情况,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制,即当某个线程获取到这个资源后,就需要对这个资源进行加锁,当使用完资源之后,再解锁,其它线程就可以接着使用了。例如,在 Java 中 synchronize/Lock 等。
但是到了分布式系统的时代,这种线程之间的锁机制,就没作用了,系统可能会有多份并且部署在不同的机器上,这些资源已经不是在线程之间共享了,而是属于进程之间共享的资源。因此,为了解决这个问题,「分布式锁」就出现了。
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

分布式锁特性

notion image

常用实现方案

notion image

基于数据库实现

基于数据库实现-乐观锁

乐观锁的特点先进行业务操作,不到万不得已不去拿锁。“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
乐观锁机制是在数据库表中引入一个版本号(version)字段来实现
当我们要从数据库中读取数据的时候,同时把这个 version 字段也读出来,如果要对读出来的数据进行更新后写回数据库,则需要将 version 加 1,同时将新的数据与新的 version 更新到数据表中,且必须在更新的时候同时检查目前数据库里 version 值是不是之前的那个 version ,如果是,则正常更新。如果不是,则更新失败,说明在这个过程中有其它的进程去更新过数据了
乐观锁遵循的两点法则:
  • 锁服务要有递增的版本号 version
  • 每次更新数据的时候都必须先判断版本号对不对,然后再写入新的版本号
notion image

基于数据库实现-悲观锁

悲观锁的特点是先获取锁,再进行业务操作,即*“悲观”*的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作
通常所说的“一锁二查三更新”即指的是使用悲观锁。
当数据库执行 select for update 时会获取被 select 中的数据行的行锁
并发执行的 select for update 选中同一行则会发生排斥(需要等待行锁被释放),以此达到锁的效果
select for update 获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用
notion image

基于数据库实现-总结

notion image

基于redis实现

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

实现思想

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

基于redis实现-原理

notion image

基于redis实现-总结

notion image

基于 ZooKeeper 实现

基于 ZooKeeper ,就是使用它的临时有序节点来实现的分布式锁。
实现思想:
(1)创建一个目录 mylock;
(2)线程A想获取锁就在 mylock 目录下创建临时顺序节点;
(3)获取 mylock 目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
(4)线程 B 获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
(5)线程 A 处理完,删除自己的节点,线程 B 监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。

基于 ZooKeeper 实现-原理

notion image

基于ZooKeeper实现-curator

notion image

基于ZooKeeper实现-总结

notion image

总结

分布式锁有很多种,”相对主流的有三种”只是个人愚见。
分布式锁千变万化,具体的实现方案按照自己的场景及条件实现。
本质还是针对同步资源的合理占用,最理想的方式就是不用加锁就可以避免并发操作

来源

Loading...
目录
文章列表
王小扬博客
产品
Think
Git
软件开发
计算机网络
CI
DB
设计
缓存
Docker
Node
操作系统
Java
大前端
Nestjs
其他
PHP