CAP
remind
- 分布式事务怎么解决,我说的消息最终一致性,异步?有没有更好的方案?
- 同步TCC方式,TCC方式原理?(三个阶段的具体实现)
- 分布式事务解决的数据一致性问题,分布式锁解决的是线程同步,资源竞争问题.
keywords
ACID单机事务理论; => 2PC实现;
CAP,BASE分布式事务理论; =>3PC/TCC实现/XA
ACID
单机事务的理论基础
CAP
CAP定理,分布式事务的理论基础,分布式系统的三个指标 => CAP定理:P是一个基本要求(网络通信),CAP三者中,只能根据系统要求在C和A两者之间做权衡,并且要想尽办法提升P.(CA是一对悖论..自己的理解)
- Consistency(数据一致性):一般指
数据的强一致性,因为存在一直存在P,所以写操作时C难以满足,区块链是保证最终一致性。 - Availability(服务可用): 服务可用,访问服务成功;
C处理阶段写操作需要加锁保证强一致性,此时服务不可用,A不能保证。 - Partition Tolerance(允许分区容错,允许网络通信失败):因为2台机器可能存在通信失败,所以P无法避免
P一定存在的,分布式事务一般会在C/A之间做取舍;
注册中心偏重:PA,强调服务可用; 分布式数据库偏重PC,强调数据一致性:
zookeeper,cnosul实现CP;
etced,euraka实现AP; 对于注册中心AP更适合,只要节点可用就可以,不需要强一致性,微服务是集群部署的自己做failover.
微服务框架实现注册中心监控和failover; 则选择PA; 微服务框架不支持failover和监控则选择PC;
BASE
BA-SE理论,对比cap(A->BA,C->EC,P->S),是cap的一种选择
- BA:Basically Available,基本可用
- S:Soft State,软状态,状态可以有一段时间不同步
- E:Eventually Consistent,最终一致,最终数据是一致的就可以了,而不是时时保持强一致
2PC
2PC,2段提交:2-Phrase-Commit,
- prepare(准备): leader向follower发送prepare消息,Fllower执行事务,把数据写入日志(redo),但是不提交;把结果反馈给leader
- commit(提交):leader根据反馈的结果决定commit还是rollback;(全部ack通过则commit)
可能存在的问题:
- 同步阻塞:在一次事务过程中,主节点一直阻塞直到其他节点ACK,(期间服务可能不可用,cap的A问题)
- 单点故障: leader失败,会出现瘫痪
- 脑裂:多个节点P(网络)失败,信息不一致
分析zk....
适合单机事务ACID,比如mysql的事务实现方式。其他的是分布式事务实现方式,zookeeper数据同步好想也是
3PC
3PC,3 Phrase Commit: ask,prepare,commit
改动:
- 加入了超时机制(解决prepare阶段可能长时间阻塞的问题)
- 把
prepare准备阶段分成2段执行
执行:
- ask(询问):询问是否可以提交(能不能干,fast-fail的想法???)
- prepare(预提交):leader执行/中断事务(先干干试试,增加了默认超时成功)
- commit(确认):通知follower提交,等待follower提交结果的反馈(干他了/撤销)
TCC
TCC,阿里巴巴提出了新的TCC协议,TCC协议将一个任务拆分成Try、Confirm、Cancel。正常的流程会先执行Try,如果执行没有问题,再执行Confirm,如果执行过程中出了问题,则执行操作的逆操Cancel。
TCC的实际案例,在秒杀的场景,用户发起下单请求,应用层先查询库存,确认商品库存还有余量,则锁定库存,此时订单状态为待支付,然后指引用户去支付,由于某种原因用户支付失败,或者支付超时,系统会自动将锁定的库存解锁供其他用户秒杀。。。。。(网络的例子,实现细节不是清晰的)
zookeeper
zk是分布式协调服务,实现强一致性,主要用于服务发现,分布式锁,配置管理;每个节点提供了监控和通知机制
类似的服务,nacos,etcd,consul
node-type
- PERSISTENT:持久的节点。
- EPHEMERAL:暂时的节点。
- PERSISTENT_SEQUENTIAL: 持久化顺序编号目录节点
- EPHEMERAL_SEQUENTIAL : 暂时化顺序编号目录节点
zab
工作原理,基于主从复制的强一直性集群,实现HA(高可用:high avaliable),强一致性.
ZAB(ZooKeeper Atomic Broadcast),ZooKeeper 原子消息广播协议,是zk实现的核心协议,工作模式分为2个恢复模式,广播模式。
恢复模式
zk机器启动或者leader宕机等需要选举新的leader时处于恢复模式; 等到leader选举成功且所有的follower与leader状态同步完成,进入广播模式;
主要的工作就是 选举leader 和 状态同步;
投票选举leader的规则:
- 每个 Server节点询问其他节点的Server投票信息;其他节点会返回自己推荐的leader_id和最大的zxid(刚启动的节点推荐自己,即leader_id是自己,zxid当前节点处理的事务Id,投票信息->
[leaderId,tid]) - 收到回复后 根据zxid,计算得到zxid最大的节点,这个节点作为下次投票推荐的节点;(zxid高32位是机器id,低32位是事务id)
- 循环直到某个节点得票超过一半;成为新leader
- 其他follwoer节点向leader节点发送txid,完成状态同步.
节点的角色(只有主节点负责写)
- leader: 监听集群的心跳;完成写操作,并同步所有节点
- follower:响应心跳; 完成读操作;写操作都转发给leader;
- observer:无投票权的follower,不参与选举; 处理读操作,转发写操作;这样做的目的是提高了集群的吞吐能力,又不会提高选举的复杂度.
广播模式
主要完成消息广播和数据一致性;
每个消息分配zxid(zk事务Id),保证消息能顺序处理; zxid是64bit,高32位是epoch,用来标记leader的更新,每次新选举成功则+1; 低32位是proposal(更新操作消息)的id;每次新选举机器X成为leader,则从X获取最大的zxid,高32的epoch加1,低32位清零重新记数;
source-code
- Leader election(leader选举):根据 投票规则 选举新的leader节点
- Discovery(发现):follower通信leader节点,准备同步数据
- Sync(同步):flowser节点同步leader数据;根据txid
- Brodcast(广播):顺序处理客户端的消息;类似2PC(不过只需要超过半数节点ack就可以commit)
Java实现: 源码分为3个阶段(Leader election:选举, recovery phase:恢复, brodcast phase:广播); recovery phase 是完成状态同步工作,是2+3的工作
// ZAB 实现
随着 zookeeper 的集群机器增多,读请求的吞吐会高但是写请求的吞吐会下降(数据强一致性消耗)
register-center
注册中心的选择(CP-VS-AP)
AP:高可用性,数据不一致时,可能会导致不同的节点loadbalance不一致,不影响分布式服务。etcd,consul
CP:强一致性;节点维持C时会牺牲A;
- zookeeper集群发生脑裂或数据同步时,集群不可用,会在分布式服务中出现单点故障,导致服务宕机;
- zookeeper只有leader可写,不适合集群扩容。
- 没有本地缓存
zookeeper数据同步时好想跟数据库一样使用的时2PC.
一致性算法
- paxos
- zab
- Raft
- nwr
- gossip
- 一致性hash算法
paxos
zab
是paxos算法的一种实现,参看上面
Raft
nwr
gossip
一致性hash算法
应用:load-balance算法
一般散列函数index=hsahcode & (length-1)。这样的Hash只要集群的数量lenght发生变化,之前的所有Hash映射就会全部失效。如果集群中的每个机器提供的服务没有差别,倒不会产生什么影响,但对于分布式缓存这样的系统而言,映射全部失效就意味着之前的缓存全部失效,后果将会是灾难性的.
一致性Hash通过构建环状的Hash空间代替线性Hash空间解决节点失效导致的缓存失效的问题。
环形空间: 解决节点失效(增/删)问题虚拟节点: 解决节点分布不均的问题
对比HashSlot
slot是redis定义的一个存储单元。
Redis Cluster采用HashSlot来实现Key值的均匀分布和实例的增删管理,映射表 + 内部转发。
TCC
[TCC-github]github.com/changmingxi…