共计 2180 个字符,预计需要花费 6 分钟才能阅读完成。
今天丸趣 TV 小编给大家分享一下 Redis 常见分布锁的原理是什么和怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
常见的分布式锁的实现如下图:
基于数据库悲观锁
悲观锁(Pessimistic Lock)顾名思义为很悲观的锁,每次在拿数据的时候都会上锁。这样别人想拿数据就被挡住,直到悲观锁被释放,悲观锁中的共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程,但是在效率方面,处理加锁的机制会产生额外的开销,且容易产生死锁。
实现原理
悲观并发控制实际上是 先取锁再访问 的保守策略,为数据处理的安全提供了保证.
具体实现
例如通过悲观锁来实现库存扣减的伪代码如下:
// 对于库存记录进行行锁
SELECT *FROM sys_goods s WHERE s.Id= 1 FOR UPDATE;
// 执行库存扣减
update sys_stock s set s.stockQty=s.stockQty-#{number} where s.goodId=1 and s.stockQty 0;// 提交事务, 自动释放悲观锁。
乐观锁简介
乐观锁是基于数据版本号 (version) 的机制来实现的。数据库表添加 version 字段, 读取出数据时,将此版本号读出,在更新过程中,会对版本号进行比较,如果是一致的,则会成功执行本次操作, 且版本号加 1,如果版本号不一致,则会更新失败。
实现原理
相对悲观锁,乐观锁的实现不会使用到数据库的锁机制,乐观锁的原理使用的 CAS 的机制来实现的,CAS(Compare-and-Swap)即比较并替换.
1、比较:读取到了一个值 A,在将其更新为 B 之前,检查原值是否仍为 A(未被其他线程改动).
2、设置:如果是未发送变化,则将 A 更新为 B 结束。如果发生变化,则什么都不做。
具体实现
例如乐观锁来实现库存扣减的伪代码如下:
// 查询库存记录,获取版本号
SELECT stockQty,version FROM sys_goods s WHERE s.Id= 1
// 执行库存扣减,防止出现超卖
update sys_stock s set
s.stockQty=s.stockQty-#{number},
s.version=version+1
where s.goodId=1 and s.stockQty 0 and version=#{version};
Redis 实现分布式锁
关于 Redis 分布式锁的实现,已经在前期的文章中进行了讲解,大家可以参考如下文章
Spring Boot 实现 Redis 分布式锁原理
Spring Boot 集成 Redisson 实现分布式锁详细案例
Zooker 实现分布式锁
Zookper 实现分布式锁,主要是应用 zookeeper 节点的临时和有序性来实现。
加锁过程
当客户端 1 请求时,Zookeeper 客户端会创建一个持久节点 Locks 节点,如果客户端 1 想获取锁, 会在 locks 节点下创建临时节点 /node_000000,如果查找 Locks 下面所有临时有序子节点,当自己为最小的节点是则获取锁成功。
当客户端 2 尝试获取锁时,也会查看 locks 下面的临时节点,判断自己的节点 /node_000001 是不是最小,如果不是最小则获取锁失败,客户端 2 会向它排序靠前的节点 node_000000 注册 watch 事件,用来监听 node_000000 是否存在,虽然抢锁失败,但是 node_000001 进入等待状态。
释放锁的过程
Zookeeper 的客户端业务完成或者客户端发生故障,都会删除临时节点并且释放锁。如果是任务完成,客户端 1 还会显式调用删除 node_000000 的指令。
例如上述图,客户端 1 断开,临时节点 node_000000 已被删除,而此时 node_000001 通过 watcher 监听发现自己为为最小的临时节点,所以获取锁成功。
异常场景分析
客户端 1 创建临时节点后,会与 Zookeeper 服务器维护一个 Session,这个 Session 会依赖客户端 定时心跳来维持连接。由于网路异常原因,Zookeeper 长时间收不到客户端 1 的心跳,就认为这个 Session 过期了,也会把这个临时节点删除,此时客户端 2 创建临时节点能够获取锁成功。当客户端网络恢复正常后,它仍然认为持有锁,此时就会造成锁冲突。
具体实现
Zookeeper 实现分布式锁,可以采用 Curator 实现分布式锁,关于 SpringBoot 如何集成 Curator,大家可以参考如下文章:
Java Spring Boot 集成 Zookeeper
Zookpeer 实现分布式锁实现库存扣减
@RequestMapping(/lockStock)
public void lockStock()
{ zooKeeperUtil.lock( /Locks , 1000, TimeUnit.SECONDS, ()- {
// 业务逻辑
});
}
小结:
关于分布式锁的实现的对比,详情请查看下图:
以上就是“Redis 常见分布锁的原理是什么和怎么实现”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,丸趣 TV 小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注丸趣 TV 行业资讯频道。