分布式锁
没有图形,只通过大量文字进行说明。分布式锁:redis分布式锁, zk分布式锁, 数据库做分布式锁
多台服务器 去竞争 资源, synchronized是jvm级别的锁不能支持,现在就需要分布式锁
redis分布式锁
-
setnx key value ex 10 原子操作
-
AB两个线程减库存业务,假设库存是10
-
A线程获取锁,B线程等待,此时A线程释放锁,程序还未执行完成。此时B线程获取锁,此时A,B都将库存减到9,与业务不符。
**解决办法:锁续期。**定时查看A程序是否已经执行完毕,没有,增加锁时间 -
为了解决单机redis瓶进,采用redis集群。一主一从,线程A从主机获取锁,此时主宕机,线程B从从机也获取了锁
解决办法:使用红锁 5(奇数)台redis集群,没有主从概念,假设编号为B1 B2 B3 B4 B5。请求依次执行,当一半以上加锁成功才算加锁成功,此时A线程依次加锁成功B1 B2 B3即获取锁成功。 线程B 加锁B4 B5成功,没有获取锁。此时还存在一个问题,如果B3宕机,马上重启成功。此时线程B 加锁B3 B4 B5成功,也获取了锁,这是红锁存在的问题。解决办法:故障延时重启其实实际中采用单机redis做分布式锁即可,使用分布式框架redisson。
5.线程A获取锁,此时 如果程序jvm线程stw, 如果没有进行锁续期,会导致锁丢失。仍然想获取锁可以使用 zk(节点)+数据库。线程A获取锁,返回将锁存放在数据库中,此时JVM stw, 线程b去获取锁,修改锁,与数据库已经存在的锁标识进行对比。
zk临时节点和有序节点分别存放什么数据?
·永久节点:
·存储集群的配置信息,如数据库连接字符串、默认参数等。
·存储分布式应用程序的元数据,例如节点的角色和功能。
·存储静态资源,例如路由表、服务发现信息等。
·临时节点:
·在分布式锁中,用于表示客户端的锁定状态,其他客户端可以监测这些节点以等待锁的释放。
·在选主操作中,用于表示当前主节点的在线状态,如果主节点失效,其他节点可以尝试争夺主节点的位置。
·用于实时监控,例如检测服务器节点的健康状态。
分析 对比:
redis 做分布式锁,命令执行是单线程命令,获取数据时不会有并发问题,并且redission客户端对于分布式锁进行了很好的包装,redission分布式锁主要基于lua脚本加上hash来实现加速逻辑,利用redis的发布与订阅,以及seaphore来实现锁的等待,并且增加锁的续期这一功能,
zk分布式锁是基于zk临时有序节点以及watch机制来实现的。每个线程在尝试加速时候,都会创建一个临时有序节点,拿锁的时候去判断,我当前这个线程是否是临时有序节点里面最小的那几个节点。如果不是就线程安全的监听上一个节点,然后进行wait
区别:
zk 临时有序节点去获取锁,每个线程去获取锁时候,都会创建一个临时节点,当抢占线程比较多时,对集群压力比较大。
redis判断这个key是否存在去获取锁,对于redis内存没什么压力
第二点:redis属于cap里面ap模型,优先高可用,在某些场景下,比如主从切换,可能数据丢失,锁丢失。zk使用zap协议来保证一致性的,所以安全性方面redis比zk低很多,但是也有通过连锁方式来提升可靠性。性能方面,redis基于内存比zk要高
数据库做分布式锁
锁的id作为主键索引或者唯一索引
分布式事务
-----------程序A---------->程序B----->----------
| |
|
|
DB DB
AB两个串行执行的程序都有数据库操作,程序A执行后,程序B出现异常时,数据库如何进行回滚
采用了协调者角色,框架 iso,seateAT
两段式提交
- 参与者投票阶段
- 提交/回滚阶段
扩展:三段式提交
TCC
saga事务
本地消息表
mq消息
提高高并发设计
串行还行很多服务时(比如购物,下单系统,库存系统,积分系统等等),程序请求下单系统后直接返回,
自己手写mq监控程序(定时任务+web)请求mq和操作数据库。然后通过消息队列继续执行后续系统操作