标签:code 处理 统一 释放 事件 线程 l数据库 官方 问题
分布式锁目前实现大部分方式
基于此,成熟的案例有比如redisson 这种官方比较推荐的方案,为了深入研究,准备在这个项目中复现这3种形式的锁
分布式锁主要可以独立于服务之外,主要的目的是在集群中保证同一时刻只能由锁的持有者对资源处理,释放锁的时候需要考虑到重入对资源的影响,串行化实现中,该项目使用了spring-retry
的相关功能,将多个请求共同编排,
实现全局的锁需要依赖一个第三方系统,此系统需要满足高可用、一致性比较强同时能应付高并发的请求。
该项目中所有的锁实现都放入了统一枚举,目前是采用的非公平锁来实现串行化执行的目的。
me.fulln.lock.enums.LockEnum
数据库非重入锁,依赖于数据库主键唯一冲突,在多个请求过来的时候,让最先访问到的请求,直接插入值来拿到锁,其他的则不断重试,直到失败,如果需要释放锁的话,直接将该锁逻辑删除即可
数据库可重入锁,需要在表新增一个标识,来区分是本身线程的重试还是其他线程的重试,只有允许该标识下的请求进入,并成功获取锁,多次进入时,会在次数上+1,
释放锁的时候,需要判断该锁的次数是否完全达到释放的次数,每次释放将该锁的次数-1,直到0
整体来说mysql数据库来做分布式锁是比较少的,大量时间耗费在数据库连接和数据传输上了,整体感还是比较重,而且mysql使用主键冲突来判断是否获取成功,实现的不算优雅,而且在集群下,由于主从同步的的时间差,容易出现误判的情况
redis锁主要是有setnx
可进行唯一key的设置和获取,redis的setnx
是redis的一个原子操作,如果key存在则set失败,如果不存在则set成功
目前大部分分布式锁的实现都是由redis进行实现的,其实现简单,吞吐量不低,但是在集群模式下,主从复制,会遇见master锁成功后节点下线,未同步锁到其他节点,导致slave节点又一次锁成功,从而产生问题
重试获取的在redission
中也有很好的实践
zk锁是通过往zk中最先写入key节点,发现自己创建的节点是最小的节点,就认为这个客户端获取到了锁.其他的客户端再进行写入的时候,发现key已经存在或者在自己创建的节点的children不是最小的,就进行等待,直到下次锁被释放的时候,再去获取锁.
zk实现的锁有个问题在于分布式锁会有羊群效应,即其他所有客户端在判断自己创建的节点是不是最小的时候,大部分都算出来不是最小的.大部分客户端都获取到了和自己不相干的通知,在集群下,对service的性能影响很大,并且如果一旦同一时间有多个节点的客户端断开连接,这个时候,服务器就会像其余客户端发送大量的事件通知,也是属于比较重的一种实现
ps: 最好使用
curator
来实现zk客户端连接
标签:code 处理 统一 释放 事件 线程 l数据库 官方 问题
原文地址:https://www.cnblogs.com/wzqshb/p/14856569.html