分布式事务理论
ACID
事务具有四个特征,分别是:
- 原子性 事务中包括的各项操作要么全部执行成功,要么全部不执行。
- 一致性 数据库在事务执行前和执行后都处于一致性的状态。避免执行过程中的故障导致数据的不一致
- 隔离性 并发的事务不能彼此干扰。在标准的sql规范中定义了4个事务隔离级别
- 持久性 事务一旦提交,修改就有永久的。
CAP
由于在分布式系统中,一个事务可能有多个分布式操作构成,要保证ACID就比较复杂。特别是在高并发的系统中,要保证一致性可能就要牺牲一定的性能,影响系统的可用性。
CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
分区容错性指遇到任何网络分区故障时,保证对外提供一致性和可用性的服务。分区容错性不可放弃。
对cap的解决通常是在一致性和可用性之间找到一个平衡点。
BASE
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写。
其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)
Paxos
Paxos主要用于保证分布式存储中副本(或者状态)的一致性。
其一致性问题利用的是选举,少数服从多数的思想,只要2N+1个节点中,有N个以上同意了某个决定,则认为系统达到了一致,并且按照Paxos原则,最终理论上也达到了一致,不会再改变。这样的话,客户端不必与所有服务器通信,选择与大部分通信即可;也无需服务器都全部处于工作状态,有一些服务器挂掉,只有保证半数以上存活着,整个过程也能持续下去,容错性相当好。
zookeeper
ZooKeeper是一个分布式应用程序协调服务,是分布式数据一致性的解决方案。分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协
调/通知、集群管理、Master 选举、配置维护,名字服务、分布式同步、分布式锁和分布式队列等功能。
基本概念
角色
zookeeper没有使用Master/Slave,而是引入Leader,Follower和Observer三种角色。一个 ZooKeeper 集群同一时刻只会有一个 Leader,其他都是 Follower 或 Observer。
ZooKeeper 集群的所有机器通过一个 Leader 选举过程来选定一台被称为『Leader』
的机器,Leader服务器为客户端提供读和写服务。
Follower 和 Observer 都能提供读服务,不能提供写服务。两者唯一的区别在于,
Observer机器不参与 Leader 选举过程,也不参与写操作的『过半写成功』策略,因
此 Observer 可以在不影响写性能的情况下提升集群的读性能。
数据节点
zookeeper的结构其实就是一个树形结构,leader就相当于其中的根结点,其它节点就相当于follow节点,每个节点都保留自己的内容。
zookeeper的节点分两类:持久节点和临时节点
- 持久节点: 所谓持久节点是指一旦这个 树形结构上被创建了,除非主动进行对树节点的移除操作,否则这个 节点将一直保存在 ZooKeeper 上。
- 临时节点:临时节点的生命周期跟客户端会话绑定,一旦客户端会话失效,那么这个客户端创
建的所有临时节点都会被移除。
Watcher
ZooKeeper允许用户在指定节点上注册一些 Watcher,
并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去。
ZAB协议
zookeeper并没有完全采用Paxos协议,而是使用了zab协议。
zab协议定义所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 Leader服务器,而余下的其他服务器则成为 Follower 服务器。 Leader 服务器负责将一个客户端事务请求转换成一个事务proposal(提议),并将该 Proposal分发给集群中所有的Follower服务器。之后 Leader 服务器需要等待所有Follower 服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈后,那么 Leader 就会再次向所有的 Follower服务器分发Commit消息,要求其将前一个proposal进行提交。
在 ZAB 协议的事务编号 ZXID 设计中, ZXID 是一个 64 位的数字,低 32 位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求, Leader 服务器在产生一个新的事务 Proposal 的时候,都会对该计数器进行加1操作;高 32 位代表了 Leader 周期 epoch 的编号,每当选举产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务 Proposal 的 ZXID ,并从该 ZXID 中解析出对应的 epoch 值,然后再对其进行加1操作,之后就会以此编号作为新的 epoch, 并将低 32 位置0来开始生成新的 ZXID 。
消息广播
广播模式的工作流程:
1leader从客户端收到一个写请求
client可以在任何一个server节点上发起写请求,非leader节点会把此次写请求转发到leader节点上。由leader节点执行
2leader生成一个新的事务并为这个事务生成一个唯一的ZXID
ZooKeeper会为每一个事务生成一个唯一且递增长度为64位的ZXID,ZXID由两部分组成:低32位表示当前leader下执行的事务递增id,高32位当有新的Leader选举产生后会加1
3leader将这个事务发送给所有的follows节点
Leader 服务器会为每一个 Follower 服务器都各自分配一个单独的队列,然后将需要广播的事务 Proposal 依次放入这些队列中去,并且根据 FIFO策略进行消息发送。
4follower节点将收到的事务请求加入到历史队列(history queue)中,并发送ack给ack给leader
每一个 Follower 服务器在接收到这个事务 Proposal 之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在成功写入后反馈给 Leader 服务器一个 Ack 响应。
5 当leader收到大多数follower(超过法定数量)的ack消息,leader会发送commit请求
6 当follower收到commit请求时,会判断该事务的ZXID是不是比历史队列中的任何事务的ZXID都小,如果是则提交,如果不是则等待比它更小的事务的commit
崩溃恢复
两种崩溃恢复中的场景和zab协议需要保证的特性:
1.ZAB 协议需要确保那些已经在 Leader 服务器上提交的事务最终被所有服务器都提交
假设一个事务在 Leader 服务器上被提交了,并且已经得到过半 Follower 服务器的Ack 反馈,但是在它将 Commit 消息发送给所有 Follower 机器之前, Leader 服务器挂了,针对这种情况, ZAB 协议就需要确保该事务最终能够在所有的服务器上都被提交成功,否则将出现不一致。
2.ZAB协议需要确保丢弃那些只在 Leader 服务器上被提出的事务
假设初始的 Leader 服务器 在提出了一个事务之后就崩溃退出了,导致集群中的其他服务器都没有收到这个事务,当该服务器恢复过来再次加入到集群中的时候 ,ZAB协议需要确保丢弃这个事务。
针对以上两点需求,zab协议需要设计的选举算法应该满足:确保提交已经被 Leader 提交的事务 Proposal,同时丢弃已经被跳过的事务 Proposal 。
如果让 Leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高编号(即 ZXID 最大)的事务 Proposal,那么就可以保证这个新选举出来的 Leader —定具有所有已经提交的提案。同时,如果让具有最高编号事务 Proposal 的机器来成为 Leader, 就可以省去 Leader 服务器检查 Proposal 的提交和丢弃工作的这一步操作。