分布式事务

分布式事务 PPT 演示

  • Paxos 中两种场景
【分布式事务】
为什么需要多数派读写:首先分布式环境中 , 为了数据安全都会冗余备份到多个节点 , 多节点就涉及到数据同步问题 。如果客户端发给分布式系统某个节点一个写请求 , 如果必须其他所有的节点都写入成功才给返回客户端成功 , 则保证了一致性 , 但是如果其中一台节点挂掉 , 整个请求就不会返回成功而堵塞 , 丢失了可用性 。那如果我接收到客户端请求节点立刻返回成功 , 则保证了可用性 , 丢失了一致性 。这就是著名的cap理论 。有个折中的方案是并不用所有节点同步成功 , 只需要大多数节点成功就给客户端返回成功 , 然后读的时候进行多数派读即可 。
为什么要两阶段:为什么两阶段 , 提议者通过第一阶段学习到整个环境中是否有已经多数派的议案 , 如果没有 , 那就认为自己的议案是多数派 , 让其他第一阶段提议者学习或者让第二阶段提议者值、提交议案失败 。如果只有第一阶段 , 就没有了学习多数派的过程 , 每个议案的提议者都可能认为自己是多数派 , 那就达不成一致 。
  • 相关理论:
1. 分布式系统首先数据要进行多节点备份来容忍某节点机器磁盘损坏或者网络分区 , 使得整体服务还可用;在这种情况下假设A,B两个节点之间发生网络分区 , 客户端的更新请求打到A节点 , A节点更新了数据 , B节点因分区未更新 , 现在请求B:如果保持一致性 , B只好返回没有最新数据或者超时 , 丢失了可用性;如果保持B的可用性 , 返回旧的老数据 , 这丢失一致性;
2. 因果一致性:只要保证有因果顺序的更新请求在其他线程里可见顺序一致即可 , 而强一致性完全按照全局始终顺序 , 所以性能较低 , 这也是强一致性中间件的弱势;
3. 两阶段提交:第一阶段协调者广播更新日志 , 参与者持久化日志并反馈 , 协调者收到所有的反馈中有一个不同意则回滚 , 如果都是yes则进行第二阶段;第二阶段协调者广播提交日志(既将日志应用到本地状态机) , 参与者反馈提交结果 , 如果有失败和超时则回滚提交 。主要目的是 :持久化日志和提交日志分离 , 如果持久化都持久不了 , 就都不用进行提交的操作;既然所有的服务器存储了第一阶段的值 , 然后第二阶段就可以认为可以应用他(以后即使协调者宕机了 , 可以从参与者中恢复) 。两个问题:第一阶段就需要持久化日志锁住本地资源 , 如果其中一个参与者返回不同意 , 所有的参与者都要回滚 , 浪费资源;第二阶段协调者广播提交日志但是广播了一半宕机了 。三阶段对此的优化:第一阶段广播能不能提交(CanComment);第二阶段广播持久化日志;第三阶段广播提交日志;相应的解决:第一阶段不持久化日志;即使第三阶段广播提交日志到了一半 , 未收到提交日志的参与者超时后认为 , 既然大家第一阶段大家都同意提交了(第二阶段回滚概率很小) , 那我就提交吧 , 不断的确认当然会提高数据一致性;paxos:大多数同意就行 , 不用所有的都同意;
4. 经典paxos也是两阶段:一阶段提议者选择最新的编号和值广播所有接收者 , 接收者接收后如果本地没有同意过编号就返回同意他 , 如果本地已经有同意的则将自己的编号取两者大的(使得每个接受者尽可能知道正在进行的几个议案的最大编号) , 并返回自己同意的编号对应的值 , 如果提议者发现有人返回已经同意了另一个编号的值 , 则将自己的值改为此值 , 但是编号是不会变的(目的是尽快让值形成大多数);第二阶段提议者广播编号和值 , 接收者这次会判断编号大小 , 如果编号比本地的大则返回同意 , 反之不同意 , 提议者如果发现是大多数同意则提议完成 , 如果没有重新进行第一阶段;
5. raft相比于经典paxos , 选出leader , 所有的更新请求经过leader , 不用每次更新都发起广播共识;并且简化成leader选举和日志复制两个模块;leader选举的精髓在于leader与follower都有心跳 , 如果leader挂掉 , follower收不到leader宣示心跳超时后 , 会发起新一轮的投票 , 接收拉票请求的follower如果发现没有同意过更大的任期且日志比他少则返回同意(否则不同意) , 获得大多数同意的leader获胜 , 这里是随机过期时间 , 可以尽可能避免所有节点同时发起选举;而日志复制是一个两阶段提交 , 如果leader第一阶段广播持久化日志大多数follower都同意 , 则leader将在本地提交这条日志 , 再广播提交这条日志;raft保证leader已提交的日志所有节点一定会持久化并应用到状态机(在以后所有任期) , 因此不能去提交之前任期的日志(即使大多数节点都持久化了) , 因为这条日志可能因为term太小而被覆盖掉(丢失了持久化)违反了这条保证;对于保证的证明 , 这个任期leader提交了这条日志 , 则大多数节点都进行了持久化 , 下个任期只可能拥有这个任期的节点被选为leader(投票给日志大的节点) , 没有这条日志的是少部分 , 最多获得的支持也是少部分的 , 不可能当选leader;
6.paxos需要保证即使当前的proposer发生宕机 , 一旦某个值被chosen , 这个值最终仍然能被后续的proposer学习到 。选主算法则不同 , 选定某个节点为主后(这个值被chosen) , 如果主挂掉 , 我们就得重新选主 , 并不需要维护之前被chosen的值 , 即之前的主 。再者一个proposer想要发起决议时 , 首先要先learn系统的状态而不能自己想提议什么值就提议什么值 , 是以需要两个阶段 。https://www.zhihu.com/question/57245053/answer/422583147
  • raft题目

一致性:要么返回最新数据 , 要么返回error 。可用性:不能返回error , 但可返回旧数据 。首先 , 分布式系统一定会分区所以一定要有容忍分区的能力 , 设场景:两个节点A,B在自己分区里断开连接 , A被更新了数据x , 现在请求B , 如果保一致性 , B只好返回error(或超时) , 丢可用性;如果保可用性 , B不能返回error , 只好返回不是最新的x , 丢一致性 。
一个分布式系统里面 , 节点组成的网络本来应该是连通的 。然而可能因为一些故障 , 使得有些节点之间不连通了 , 整个网络就分成了几块区域 。数据就散布在了这些不连通的区域中 。这就叫分区 。当你一个数据项只在一个节点中保存 , 那么分区出现后 , 和这个节点不连通的部分就访问不到这个数据了 。这时分区就是无法容忍的 。提高分区容忍性(the system continues to operate despite arbitrary message loss or failure of part of the system)的办法就是一个数据项复制到多个节点上 , 那么出现分区之后 , 这一数据项就可能分布到各个区里 。容忍性就提高了 。然而 , 要把数据复制到多个节点 , 就会带来一致性的问题(all nodes see the same data at the same time) , 就是多个节点上面的数据可能是不一致的 。要保证一致 , 每次写操作就都要等待全部节点写成功 , 而这等待又会带来可用性的问题(Reads and writes always succeed —> 不会超时或失败 , 但可以是错误的) 。总的来说就是 , 数据存在的节点越多 , 分区容忍性越高 , 但要复制更新的数据就越多 , 一致性就越难保证 。为了保证一致性 , 更新所有节点数据所需要的时间就越长 , 可用性就会降低 。
? 强一致性 , 完全按照全局时钟顺序; 顺序一致性:保证同一个线程里的写操作们在其他的线程里可见顺序一样即可;因果一致性:只保证只有因果的写操作们在其他的线程里可见顺序一样即可 。
? 分布式事务:2PC就是协调者广播指令 , 参与者执行返回执行结果(Propose阶段);协调者统计结果发现都成功则确定为提交然后广播提交此指令 , 否者广播回滚指令(Commit阶段) 。它无法解决协调者和参与者都崩溃的情况 , 详情 。3PC就是把2PC的Commit阶段拆成了PreCommit和Commit两个阶段. 通过进入增加的这一个PreCommit阶段, voter可以得到Propose阶段的投票结果, 但不会commit; 而通过进入Commit阶段, voter可以盘出其他每个voter也都打算commit了, 从而可以放心的commit 。
? paxos算法 解读
1)“Proposer a”贿赂了3个“Acceptor” , 金额均为1¥(提交编号 , 是递增的) 。¥1是此时最高出价 , 3个Acceptor都接受 , 返回之前未接受过提议且贿赂成功
2)Proposer a向Acceptor 1提出了1号提议(到A2A3的提议因未知网络原因堵塞了) , 并告知自己之前已贿赂¥1 。Acceptor 1检查目前记录的贿赂金额就是¥1 , A1便接受Pa的提议并把此提议记录在案 。
3)在P a向A 2,A 3发起提议前 , 土豪P b”出现 , 他开始用¥2贿赂A 1与A 2(A3因某些原因不可达) 。A 1与A 2立刻被收买返回贿赂成功 , 将贿赂金额改为¥2 。但是不同的是:A 1告诉P b之前我已经接受过1号提议了且更早之前受贿1¥(发生冲突) , 而A 2告诉P 2 , 之前没有接受过提议 。
4)P a终于回过神来向A 2和A 3发起1号提议 , 并带着信息“我前期已经贿赂过¥1 。A 2 A 3开始答复P a:A 2表示P2已经出价到¥2 , 你原先才出价¥1 , A2不接受Pa提议 , 再见 。但A3检查一下贿赂最高是¥1 , A 3接受了Pa的提议 。
---- 到这里 , P a的提议已经得到两个接受者的赞同(大于一半) , 已经得到了多数“接受者”的赞同 。P a确定1号提议最终通过 。
5)从3)开始 , 这时Pb拿到A1信息后判断一下目前A1接受了Pa的1号提议 , 所以Pb默默的把自己的提议改为与1号提议一致(这样 , 在谋求尽早形成多数派的路上 , 又前进了一步) , 然后开始向A1A2发起提议(提议内容仍然是1号提议)并带着信息之前自己已贿赂过$2 。
这时A1A2收到Pb的提议后 , 照例先比对一下贿赂金额 , 比对发现Pb之前已贿赂¥2 , 并且自己记录的贿赂金额也是¥2 , 所以接受他的提议 , 也就是都接受1号提议 。而Pb也拿到了多数派的意见 , 最终通过的也是1号提议(成为Leader) 。
如果P b第一次先去贿赂A 2 A3 , 那很可能1号提议就不会成为最终选出的提议 。
? 论文
If any acceptedValues returned, replace value with acceptedValue for highest acceptedProposal
保存最高acceptedProposal编号的acceptedValue到本地。
Any rejections (result > n)? goto (1) Otherwise, value is chosen
提议者接收到过半数请求后 , 如果发现有返回值>n , 表示有更新的提议 , 跳转1(重新发起提议);否则value达成一致 。
? paxos 与 raft 比较 WPaxos 比较2
? wmb的集群消费模式为同一个subject下相同clientID 的多客户端共消费一份完整的消息 , 广播消费是指每个客户端都可以消费一份完整消息 。不一定只向master学习 , 比他大的Follower也可以 。只有master进行消费操作(其余Follower只是进行备份) , master挂掉影响消费所以一开始把消息负载到多个master集群(虚拟分组group) , 到时候4个master集群1个挂掉只有1/4不能消费而已 。虚拟分组group , server1为group1的master(s2 , s3作为Follower) , s2为group2的master(s1 , s3作为Follower) 。再一个每台server上都有master提高每台机器的利用率 。参考1 参考2
wpaxos相关case 开源 | WPaxos:生产级Paxos算法实现解析
一致性算法一个很重要的就是数据持久化:沙龙干货 | 58分布式存储系列专题直播回顾集锦
? ETCD相关的raft算法(毕业论文就做的这个哈哈哈):
针对Paxos的优化:选出Leader , 使其Only one proposer at a time ;将其分为两阶段;通过一些约定保证安全;
选举的过程:
每个节点有个随机的timeout , 到了timeout的Follower节点A变成Candid ater广播requestVote , 没选过Leader的节点发送回选你的信息(并且重置自己timeout重新开始) , 已选Leader的节点和其他为Candidater的节点都返回不选你的信息 , 然后节点A算一算 选我的/发回的信息总数 是否大于一半 , 大于就认为自己为Leader(然后全网广播) , 如果不是就再重新一次timeout(这个期间大概率会接到已为leader节点的广播信息了) 。还有两种情况:1. 如果Leader挂掉 , 其他节点到了timeout(随机)会发送requestVote请求 2. 如果分区的两Leader合到一区中时 , 其中一Leader发现另一Leader版本更高就放弃Leader权
日志复制过程:
当leader接收到新的指令后进行广播 , 如果大多数Follower将此指令添加到日志并返回成功 , 那么Leader判断此指令为被提交状态 -> 记录到leaderCommit(然后进入到commit阶段) 。一旦跟随者知道一条日志条目已经被提交 , 那么他也会将这个日志条目应用到本地的状态机中(按照日志的顺序) 。raft保证已commit指令一定会被所有节点添加到日志 。但是不要通过这种方式提交之前任期的指令 , 原因 —> 图中(c)如果提交之前任期的index=2(value=https://tazarkount.com/read/2) , 按流程(d)中会被覆盖 , 已经提交的被覆盖是不可忍受的 , 因此需要这样的规则约定(提交的为什么也会被覆盖掉 , 因为我term比你大) 。leader里的 matchindex[](已经同步给各个Follower的最高索引) , nextindex[](下一个要同步给各个Follower的索引 , 可能成功 , 也可能因为Follower中间日志确实太多而失败) 。
任期 T 的领导人在任期内提交了一条日志条目 , 这条日志条目一定被存储到未来某个任期的领导人的日志中 , 详细证明见
如图所示 , N1作为前一任期的Leader , 提交了一条新日志(既然是提交说明大多数节点N1、N2、N3已经将指令添加到本地日志并执行) , 然后 N5 在之后的下一任期里被选举为Leader(那么说明得到了大多数N3、N4、N5的投票) , 这里会出现至少一个节点像N3一样 , 有前一任期里的日志 , 却投票给了N5这个缺少前一任期里新提交日志的节点 。N3将选票投给了U的领导人说明它有N3本地所有的日志 , 但是N3有领导人U没有的日志 , 按理说不会投票U了 , 所以产生矛盾 。
? etcd内存优化问题 , 寻找n个连续的内存页 , 当一个页面被释放时 , 他通过查询 backwardMap 尝试与前面的页面合并 , 通过查询 forwardMap 尝试与后面的页面合并 。优化1 优化2 优化3
使用 key不存在 key存在
put 创建 不报错 , ttl更新
putdir 创建 报错 , ttl不更新
key过期路径不会丢失 put 的时候 key过期路径不会丢失
? Zookeeper相关的ZAB协议:也是选出Leader 。分为两种模式:
崩溃恢复(选Leader阶段):每个节点进入LOOKING状态 , 每个节点发出投票(myid, ZXID) , 然后每个节点接收到投票后与自己的投票比较(先看ZXID , 再看myid)并变更 , 然后再次投票 , 然后每个节点再次处理接收到的投票 , 如果一台机器收到了超过半数的投票就认为是Leader(然后广播全网), 否则继续 。
(这样选取的Leader有最大的ZXIDà一定有全部已提交提案 , 确保原Leader 提交的事务最终会被所有服务器提交 , 丢弃那些只在 Leader 提出 , 但没有提交的事务 。)
消息广播(已有Leader阶段):对于客户端发送的写请求 , 全部由 Leader 接收 , Leader 将请求封装成一个事务 Proposal , 将其发送给所有 Follwer  , 然后 , 根据所有 Follwer 的反馈 , 如果超过半数成功响应 , 则执行 commit 操作(先提交自己 , 再发送 commit 给所有 Follwer)-> 两阶段提交 参考1,参考2,参考3
以一个简单的例子来说明整个选举的过程.假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序启动
1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING
2) 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出(服务器1更新自己的投票为2--> 尽早形成多数派),但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态.
3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader.
4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了.
5) 服务器5启动,同4一样,当小弟.
使该框架保证了分布式环境中数据的强一致性(解决不同客户端同时写一个数据时产生的共享问题--> 尽早形成多数派) , 主要解决1.分布式文件系统:有心跳来检测各个客户端的连接2.通知系统:当客户端发生变化时会通知感兴趣的人 。--->Zookeeper分布式锁:将zookeeper上的一个znode看作是一把锁 , 通过createznode的方式来实现 。所有客户端都去创建 /distribute_lock 节点 , 最终成功创建的那个客户端也即拥有了这把锁 。用完删除掉自己创建的distribute_lock 节点就释放出锁
? 对于微服务的理解(是n重的生产者模型):首先延迟来自于本该有的网络多级链路延迟 , 再一个等待队列等待延迟 , 微服务拆分后 , 链路增加了网络延迟增加了 , 但是微服务模块化后可以针对瓶颈(相比所有代码放到一台机器然后部署好多台)进行水平扩展 , 所以吞吐量高了之后等待队列等待延迟会降低。
美团万亿级 KV 存储架构与实践 MySQL事务隔离级别和MVCC (绝对看得懂)_wust_zwl的博客-CSDN博客_mysql事务隔离级别