共计 4039 个字符,预计需要花费 11 分钟才能阅读完成。
1. 一致性协议
1.1 两阶段提交 2PC:
本身是一致强一致性算法,所以很适合用作数据库的分布式事务。其实数据库的经常用到的 TCC 本身就是一种 2PC。
数据库事务:回顾下数据库的事务,对一条数据的修改操作首先写 undo 日志,记录的数据原来的样子,接下来执行事务修改操作,把数据写到 redo 日志里面,万一捅娄子,事务失败了,可从 undo 里面回复数据。
数据库通过 undo 与 redo 能保证数据的强一致性,要解决分布式事务的前提就是当个节点是支持事务的。在这个前提下,2PC 将整个分布式事务分两节点:
- 1. 第一阶段:为准备节点,事务的请求都发送给一个个资源,资源可以是数据库,也可以是其他支持事务的框架(比如 zookeeper),他们会分别执行自己的事务,写日志到 undo 与 redo,但不提交事务。
- 2. 第二阶段:当事务管理器收到了所以资源的反馈,事务都执行没报错后,事务管理器再发送 commit 指令让资源把事务提交,一旦发现任何一个资源在准备阶段没有执行成功,事务管理器会发送 rollback,让所有的资源都回滚。
强一致性是指:保证每个资源都成功, 整个分布式事务才成功.
缺点:
- 1. 同步阻塞.———- 所有的节点都在等待其他节点的响应,无法进行其他操作。这种同步阻塞极大的限制了分布式系统的性能。
- 2. 单点问题.———- 如果协调者在提交 (commit) 阶段出现问题,那么整个流程将无法运转。更重要的是,其他参与者将会处于一直锁定事务资源的状态中,而无法继续完成事务操作.
- 3. 数据不一致.——- 若协调者即事务管理器未发送完所有 commit 请求自身崩溃,则导致一部分参与者未收到 commit 请求,导致数据不一致.
- 4. 容错性不好.—- 任何一个节点失败都会导致整个事务失败.
1.2. 三阶段提交 three-phase commit (3PC)
- 第一阶段:协调者向参与者发送 commit 请求,参与者如果可以提交就返回 Yes 响应,否则返回 No 响应。
- 第二阶段:如果所有服务都 ok,可以接收事务请求,这一阶段就可以执行事务了,这时候也是每个资源都回写 redo 与 undo 日志,事务执行成功,返回 ack(yes), 否则返回 no
- 第三阶段:这阶段和前面说的 2 阶段提交大同小异,这个时候协调者发现所有提交者事务提交者事务都正常执行后,给所有资源发送 commit 指令。
与 2PC 区别:
第二阶段才写 undo 和 redo 事务日志
第三阶段协调者出现异常或网络超时参与者也会 commit
三阶段 3PC 优点:
相对于 2PC,3PC 主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,会默认执行 commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,比如由于网络原因,协调者发送的 abort 响应没有及时被参与者接收到,那么参与者在等待超时之后执行了 commit 操作。这样就和其他接到 abort 命令并执行回滚的参与者之间存在数据不一致的情况。
但回顾整个过程,不管是 2pc, 还是 3pc,同步阻塞,单点故障,容错机制不完善这些问题都没本质上得到解决,尤其是前面说得数据一致性问题,反而更糟糕了。
所有数据库的分布式事务一般都是二阶段提交,而者三阶段的思想更多的被借鉴扩散成其他的算法
1.3.Paxos 算法
paxos 算法分为两个阶段,有 2 个角色,提议者和接受者。
关键是:
1. 少数服从多数
2. 角色轮换避免单点故障
具体流程也没搞清楚~~ 先知道核心思想即可
2 zookeeper 集群
2.1 zookeeper 集群特点
- 顺序一致性:客户端的更新顺序与它们被发送的顺序相一致。
- 原子性:更新操作要么成功要么失败,没有第三种结果。
- 单一视图:无论客户端连接到哪一个服务器,客户端将看到相同的 ZooKeeper 视图。
- 可靠性:一旦一个更新操作被应用,那么在客户端再次更新它之前,它的值将不会改变。
- 实时性:连接上一个服务端数据修改,所以其他的服务端都会实时的跟新,不算完全的实时,有一点延时的
- 角色轮换避免单点故障:当 leader 出现问题的时候,会选举从 follower 中选举一个新的 leader
集群中的角色
- Leader:集群工作机制中的核心 事务请求的唯一调度和处理者,保证集群事务处理的顺序性,
集群内部个服务器的调度者(管理 follower, 数据同步) - Follower:集群工作机制中的跟随者处理非事务请求,转发事务请求给 Leader, 参与事务请求 proposal 投票,参与 leader 选举投票
- Observer:观察者 3.30 以上版本提供,和 follower 功能相同,但不参与任何形式投票 处理非事务请求,转发事务请求给 Leader 提高集群非事务处理能力
2.1 zookeeper 集群搭建
1.安装 JDK,zookeeper。
2.配置环境变量
vi /etc/profile
export JAVA_HOME=/usr/local/jdk1.8.0_211
export ZOOKEEPER_HOME=/usr/local/zookeeper
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin:$PATH
刷新 profile 文件
source /etc/profile
关闭防火墙(命令视不同系统情况而定)
3.修改 zk 配置文件
mv zoo_sample.cfg zoo.cfg
修改 conf: vi zoo.cfg 修改两处
(1)dataDir=/usr/local/zookeeper/data(注意同时在 zookeeper 创建 data 目录)
dataDirLog=/usr/local/zookeeper/log 日志目录,并创建目录
(2)最后面添加
server.0=192.168.64.128:2888:3888(2888 是集群内机器通讯端口,3888 是选举 leader 使用)
server.1=192.168.64.129:2888:3888
server.2=192.168.64.130:2888:3888
注意:server.0,server.1 中,0 和 1 就是服务器标识
4. 创建服务器标识
在 dataDir 路径下 data 目录下创建 myid 文件,内容即为 0 /1/2,即上述配置的。
5.复制 /usr/local/zookeeper 下所有文件到另外 2 个服务器上面,只修改 myid 的服务器标识即可。
启动三台机器的 zk,./zkServer.sh start
./zkServer.sh start 查看状态即可查看角色是 leader 还是 follower。
启动失败的时候查看 bin 目录下 zookeeper.out 日志
2.2 Zookeeper 集群一致性协议 ZAB
zab 其实是 paxos 的一个简化实现。zookeeper 就是根据 zab 协议建立了主备模型完成集群的数据同步(保证数据的一致性).
zab 协议是分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性。
zab 协议核心:
整个 zookeeper 集群中只有一个节点 leader 将所有客户端的写操作转化为事务(提议 proposal).leader 节点在数据写完之后,将向所有的 follower 节点发送数据广播请求(数据复制), 等所有的 follower 节点的反馈,在 zab 协议中,只要超过半数 follower 节点反馈 ok,leader 节点会向所有 follower 服务器发送 commit 消息,既将 leader 节点上的数据同步到 follower 节点之上
ZAB 协议两种模式:消息广播和崩溃恢复
消息广播:
- Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,叫做:zxid。
- Leader 通过先进先出队列 (通过 TCP 协议来实现,以此实现了全局有序这一特性) 将带有 zxid 的消息作为一个提案 (proposal) 分发给所有 follower。
- 当 follower 接收到 proposal,先将 proposal 写到硬盘(事务日志),写硬盘成功后再向 leader 回一个 ACK。
- 当 leader 接收到合法数量的 ACKs 后,leader 就向所有 follower 发送 COMMIT 命令,会在本地执行该消息。
- 当 follower 收到消息的 COMMIT 命令时,就会执行该消息
为了进一步防止阻塞,leader 服务器与每个 follower 之间都有一个单独的队列进行收发消息,使用队列消息可以做到异步解耦。leader 和 follower 之间只要往队列中发送了消息即可。如果使用同步方式容易引起阻塞。性能上要下降很多
崩溃恢复:tips:集群机器的数量必须是奇数
zookeeper 集群中为保证任何所有进程能够有序的顺序执行,只能是 leader 服务器接受写请求,即使是 follower 服务器接受到客户端的请求,也会转发到 leader 服务器进行处理。
如果 leader 服务器发生崩溃(重启是一种特殊的奔溃,这时候也没 leader),则 zab 协议要求 zookeeper 集群进行崩溃恢复和 leader 服务器选举。
- 每个 Server 会发出一个投票, 第一次都是投自己。投票信息:(myid,ZXID)
- 收集来自各个服务器的投票
- 处理投票并重新投票,处理逻辑:优先比较 ZXID, 然后比较 myid
- 统计投票,只要超过半数的机器接收到同样的投票信息,就可以确定 leader
- 改变服务器状态
新选举出来的 leader 不能包含未提交的 proposal(事务),即新选举的 leader 必须都是已经提交了的 proposal 的 follower 服务器节点。同时,新选举的 leader 节点中含有最高的 ZXID。这样做的好处就是可以避免了 leader 服务器检查 proposal 的提交和丢弃工作。
这也是为什么优先选择大的 zxid 的原因。