分布式锁
非分布式场景下,正常线程进程同步的机制有哪些?
互斥:互斥的机制,保证同一时间只有一个线程可以操作共享资源 synchronized,Lock等
临界值:让多线程串行话去访问资源
事件通知:通过事件的通知去保证大家都有序访问共享资源
信号量:多个任务同时访问,同时限制数量,比如发令枪CDL,Semaphore等
分布式锁实现方式
基于Zookeeper
主要是使用节点唯一的特性来实现,创建失败后丢到队列中去排队
释放锁就是删除节点,删除后然后通知其他人过来创建节点,即加锁
如果机器宕机了,没有删除掉,资源就会一直被占着,怎么处理呢? 创建临时节点就好,客户端断开,节点就自动删除了
使用zk可能会造成的问题
羊群效应,导致占用服务器资源。 处理方法:临时顺序节点,只监听前一个节点,以此类推,只关注自己前后,就不会出现羊群效应
使用zk实现分布式锁的缺点
性能没有缓存服务高。因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同步到所有的Follower机器上。
可能带来并发问题。 由于网络抖动,客户端ZK集群的session连接断了,那么zk以为客户端挂了,就会删除临时节点,这时候其他客户端就可以获取到分布式锁了。就可能产生并发问题了。
这个问题不常见是因为zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,Curator客户端支持多种重试策略。
多次重试之后还不行的话才会删除临时节点。
Tip:所以,选择一个合适的重试策略也比较重要,要在锁的粒度和并发之间找一个平衡。
基于Redis
关键命令:
setnx : 如果不存在,则 SET
setex: 不存在则set,存在则覆写。 它是一个原子性(atomic)操作,关联值和设置生存时间两个动作会在同一时间内完成
实现:
setnx如果加锁成功,但是没有释放,就会出现死锁;所以使用setex更合理
还有一个px,过期时间,兜底
还遇到一个问题,就是Redis加锁,内部的业务时间超过锁的时间,怎么办?可以使用守护进程来续期。(Redission有相关的实现)
基于MySQL实现
这个简单,就是维护DB数据就行
CAP定理
一致性Consistency
可用性Availability
分区容错性Partition tolerance