一、分布式锁
1、什么是分布式锁
分布式锁是一种用于在分布式系统中实现互斥访问的机制。在分布式系统中,多个节点可能同时访问共享资源,为了避免冲突和数据不一致性的问题,需要使用分布式锁来保证在同一时间只有一个节点能够对共享资源进行操作
2、常见分布式锁有哪些
分布式锁:MySQL,Redis,Zk,Etcd
3、为什么要使用分布式锁
1)使用第三方锁相比单机JVM锁性能必定降低
2)多个主机竞争一个商品,性能比单机低,为什么分布式锁性能会降低还要用呢?
- 一个概念,分布式可以提高吞吐量,A商品和B商品的锁是可以并行的,分布式锁是解决分布式的方案实现过程多机竞争商品A的问题,不是为了提高性能
分布式锁和MapReduce就是一个类似的思想,单机分别处理结果汇总,最后竞争一把锁
4、分布式锁还需要JVM锁吗?
- JVM锁是先保证一个主机内部竞争最后只有一个胜出,最后多主机的竞争数就是主机数,可减少IO,资源浪费
二、两大类分布式锁
1、类JVM的CAS自旋的方式获取锁
1)代表锁:MySQL,Redis
2)Redis问题:
- 如果C1运行一段时间挂了,会死锁
可通过设置超时时间解决问题 - C1拿到偏向锁或轻量级锁之后,C2通过IO发送setnx指令,在做自旋
如果C1迟迟不释放锁,C2就会长时间的自旋,浪费资源 - 如果有大量主机想获取锁,那么会产生大量请求
配置Redis集群,解决单点挂掉问题,分担大量请求 - C1没有挂掉,但是执行超时了
增加额外线程进行续时 - 释放错锁怎么办
锁上加标识UUID - Redis挂了怎么办
配置集群,多机部署或单机保证不挂(有大厂这么用) - 分布式锁主从模式数据同步不及时怎么办
(1)消息队列,发布订阅 + 超时设置+ 额外线程进行超时续时处理(实现很麻烦)
(2)使用RedLock不区分主从节点。每次线程获取锁都要向每个节点发送请求,Redis节点响应过半才能获取锁,这样就不存在数据同步的问题了,同时某个节点挂掉,也不会影响锁的获取 - 如果每个redis节点分别响应一个单独的线程怎么办?
随机重试,再抢一轮,再抢一轮
2、Event通知锁的状态,轮询向外
1)代表锁:Zk,Etcd
2)ZK问题:
- zookeeper的leader节点挂掉怎么办?
选举机制,谁数据新,数据一样看serverid谁大,过半通过 - zookeeper一个节点挂了,会不会丢失锁?
zookeeper存在一个session的概念,哪怕一个节点挂了,其他的节点也会和client快速连接 - 存在临时节点和永久节点
客户端创建path node节点(永久节点)
临时node和session绑定,只要session在,节点就不会删除(断开连接会删除,还有其他情形) - 创建锁会不会重?
获取锁时,C1和C2都会访问leader,有顺序关系,所以像Redis只会获取一个锁 - 如果C1获取锁,C2怎么获取?
zookeeper的watch机制,存在回调函数监测锁,释放就通知客户端,这样就避免了轮询,节省了资源。
创建锁,zookeeper比Redis多了一个同步,两阶段提交的过程,还有一个watch机制,避免了客户端的不断轮询,可理解为Redis的升级版
3) ZK特点:
- 也无法保证完全一致,但是正常运行的一致性要高于redis
- 比较稳定,响应时间波动小
- 性能会随着并发量上升而下降
- 每次进行锁操作都要创建若干节点,完成后释放节点,浪费时间
3、Redis与ZK各自特点
1)Redis: 红锁,轮询,超时设置,续期
2)Zookeeper:选举机制,session同步,watch机制
Zookeeper比Redis最强的点在于watch机制,它可以进行超时通知,锁释放通知等,不用像redis一样类CAS自旋不断重试,减少了资源消耗