分布式锁
在单机的时候,可以使用语言内置的锁实现进程同步,对于分布式场景,需要同步的进程在不同的节点上,可以使用分布式锁。
阻塞锁需要使用互斥量来实现:
互斥量为0表示锁定
互斥量为1表示未锁定
数据库的唯一索引
获取锁的时候插入一条记录,释放锁时删除该条记录。使用这条记录表示是否处于锁定。
锁没有失效时间,有可能造成解锁失败时其他进程无法获取锁
只能是费阻塞锁,无法重试。
不可重入。
Redis 的 SETNX
类似于数据库的唯一索引,使用SetNX插入键值对,已经存在返回false,不存在插入成功返回true,根据是否存在判断是否锁定。
不同的是Redis可以设置过期时间,可以解决数据库唯一索引潜在的锁释放失败的问题。
Redis的RedLock算法
使用多个Redis实例实现分布式锁,防止单个节点宕机造成的服务不可用。
尝试从N个相互独立的Redis实例获取锁
计算获取锁需要的时间,如果时间小于锁的过期时间,并且在超过一半的实例上获取了锁,说明锁获取成功。
如果锁获取失败,就到各个实例上释放锁。
ZooKeeper有序节点
采用树模型
节点类型包含三种:
永久节点:不会因为会话结束或超时而消失
临时节点:会话结束或超时就消失
有序节点:会在节点名称后面添加数字后缀,并且是有序的。
监听器
为节点注册监听器可以检测节点的状态,状态发生改变会发送通知到客户端
分布式锁的实现
1. 创建一个/lock目录
2. 当一个客户端需要获取锁时,在/lock下创建临时有序节点
3. 客户端获取/lock下的子节点列表,如果自己创建的节点是当前列表中序号最小的子节点,就认为获得锁。否则,监听前一个节点的状态,获得状态变化通知,直至获得锁。
4. 业务完成后,删除本节点
会话超时
会话超时的时候,因为都是临时子节点,会自动释放锁。
羊群效应
一个节点未获得锁,只需要监听自己的前一个节点,这是因为如果监听所有节点,任意一个节点的状态发生变化都会发送通知到其他子节点,这就是羊群效应。
所以,我们只让他监听前一个节点。
分布式事务
事务操作不在同一个节点上,还需要保证ACID特性
两段提交(2PC)
Two - Phase Commit
通过引入协调者协调参与者的行为,最终决定是否要真的执行事务。
准备阶段
协调者询问参与者事务是否执行成功,参与者发送回执。
提交阶段
如果每个参与者上都执行成功,事务协调者发送通知让事务参与者提交事务,否则,通知回滚
两段式提交存在的问题
1. 同步阻塞
各个参与者需要等待其他参与者全部执行完毕,这个时候是阻塞的
2.单点问题
协调者是核心,一旦发生故障造成很大的影响。
3.数据不一致
在阶段二,如果消息通知没有完全送达,会造成数据的一致性问题。
4. 过于保守
任意一个节点失败都会导致整个事务的失败,没有容错机制
本地消息表
借助于本地事务表单独维护分布式事务。
1. 分布式事务操作的一方完成数据写入后,向本地消息表写入消息(由本地事务保证可靠性)
2. 本地消息表将消息转发至消息队列,转发成功则删除,否则重试。
3. 分布式事务另一方从消息队列中读取一个消息执行消息中的操作。
CAP
(Consistency,Availability,Partition-Tolerance)分布式系统只能满足其中两个
C:
对数据更新成功后,所有用户能够读取到最新的值,该系统被认为具有强一致性。
A:
面对各种异常情况都是可用的。99.99%的时间是可用的。
P:
网络分区指的是分布式系统的节点划分为多个区域,区域内部可以通信,区域之间无法通信。
任何分区出现故障,仍然需要提供一致性和可用性服务。
BASE
Basically Available基本可用
Soft State软状态
Eventually Consistent最终一致性
基本可用:分布式系统出现故障时,保证核心可用,允许损失部分可用性。
软状态:允许数据存在中间状态,并认为中间状态不会影响系统整体可用性。允许不同节点之间的数据存在同步时延。
最终一致性:不同节点的数据最终能够达到一致性。
Paxo
多个节点产生的值,选出唯一的一个。
三类节点:
提议者:提议一个值
接受者:对每个提议投票
告知者:被告知投票的结果,不参与投票过程
提议包含两个字段:[n,v]
1. Prepare
提议者向接受者发送提议
如果一个接受者收到提议,并且之前没有收到过提议,将返回prepare response【No Previous】
如果之前收到过提议,并且当前协议序号更大,那么新接收的提议将丢弃,否则,返回当前协议,保存新协议。
提议者接收到一半以上的响应后发起accept请求
发送内容为提议者接收到的最大序号和最大值。接受者根据最大序号判断是否接受。
接受者接受大于等于当前存储的提议版本号的提议请求,然后将接受请求结果转发到告知者。
通过表决,选择大多数接受者接受的值。
Raft
Raft是分布式一致性协议,竞选主节点。
单个candidate
存在三种节点:
leader
follower
candidate
leader定时发送心跳包给follower,follower随机产生竞选超时时间,该时间范围内没有收到心跳包就进入candidate
假设Node A称为竞选者,他开始发送投票请求给其他所有节点:
其他节点发送投票结果:
如果超过一半节点回复了,该candidate成为leader
多个candidate
当多个候选者投票数一致,再次发起投票。
这时再次重复票数的可能性较小。
数据同步
来自客户端的数据修改会传至leader,leader将值复制给follower
等大多数follower也进行了修改,才将修改提交
此时,leader通知follower也开始提交,所有节点的值达成一致。