事务|干货放送 细说分布式事务两阶段提交
在分布式系统中 , 读写位于多个节点的数据 , 如果依旧想保证ACID特性 , 就必须实现分布式事务 。 而其实现关键则是适当的提交协议 , 目前最简洁 , 且使用最广泛的无疑是两阶段提交协议(2PC) 。
实现分布式事务关键组件
单机系统通过事务管理器(transaction manager , TM)实现本地事务 。 分布式系统中 , 需要协调多个节点的事务管理器 , 共同提交成功或失败 , 因此需要事务协调者(transaction coordinator , TC) 。 一个分布式事务管理器 , 可以粗略地划分为这两个子系统 。 这两个子系统根据自己在事务执行中扮演的角色 , 也可称之为参与者与协调者 。
本地事务管理器负责本机事务并发控制和异常恢复等功能 , 事务协调者负责开启事务 , 将事务划分为多个子事务分发到相应的节点执行 , 并协调事务完成(一起提交成功或失败) 。 在实现中 , TM和TC可以实现在同一个进程中 , 也可以部署在不同的节点 。
经典两阶段提交协议
两阶段提交的流程比较简单 。 当分布式事务T执行完成进入提交阶段 , TC便开启两阶段提交流程 。
本文插图
Phase 1 Prepare:
1.TC写本地日志 , 并持久化 。 TC向所有参与者发送Prepare T消息 。
2.各参与者TM收到Prepare T消息 , 根据自身情况 , 决定是否提交事务 。
如果决定提交 , TM写日志并持久化 , 向TC发送Ready T消息 。
如果决定不提交 , TM写日志并持久化 , 向TC发送Abort T消息 , 本地也进入事务abort流程 。
Phase 2 Commit :
1.当TC收到所有节点的回应 , 或者等待超时 , 决定事务commit或abort 。
如果所有参与者回应Ready T , 则TC先写日志并持久化 , 再向所有参与者发送Commit T消息 。
如果收到至少一个参与者Abort T回应 , 或者在超时时间内有参与者未回应 , 则TC先写日志 , 再向所有参与者发送Abort T消息 。
2.参与者收到TC的消息后 , 写或日志并持久化 。
两阶段提交协议可以保证分布式事务执行的一个关键点:参与者在向协调者发生Ready T消息前 , 随时都可以自己决定是否abort , 一旦这个消息发送 , 那么这个事务就进入ready状态 , commit和abort完全由协调者控制 。 Ready T消息本质上是参与者向协调者发送的一个郑重的、不可逆的承诺 。
为了保证这一个承诺 , 参与者需要在发送Ready T消息前将所有必要的信息持久化 , 否则如果参与者在发送Ready T后异常宕机 , 重启后可能无法遵守以上承诺 。 在第二阶段 , 当协调者写了或日志 , 整个事务的命运就被决定了 , 不会再发生变化了 。
为了优化2PC性能 , 减少关键路径的持久化和RPC次数是关键 , 一种对经典2PC的优化思路如下:
协调者无状态 , 不再持久化日志 , 但是为了方便宕机重启后恢复事务状态 , 需要向每个参与者发送事务的参与者名单并持久化 。 这样即使协调者宕机 , 参与者也可以方便地询问其他参与者事务状态了 。 该思路相当于参与者在协调者宕机时 , 自己担当起协调者询问事务状态的任务 。
只要所有参与者prepare成功 , 事务一定会成功提交 。 因此为了减少提交延时 , 协调者可以在收到所有参与者prepare成功后就返回客户端成功 , 但如此 , 读请求可能会因为提交未完成而等待 , 从而增大读请求的延时 。 反过来 , 如果协调者确认所有参与者都提交成功才返回客户端成功 , 提交延时比较长 , 但会减少读请求延时 。
两阶段提交协议异常处理
两阶段提交协议的正常流程较为简单 , 但它还需要考虑分布式系统中各种异常问题(节点失败 , 网络分区等) 。
1.如果协调者检测到参与者失败:
如果参与者在发送Ready T前失败 , 则协调者认为该节点事务Abort , 并开始abort流程 。
如果参与者在发送Ready T后失败 , 证明参与者本地事务已经持久化 , 协调者忽视参与者失败 , 继续事务流程 。
2.如果参与者在事务提交过程中失败 , 其恢复过程 , 需要根据参与者日志内容 , 决定本地事务状态 。
如果日志中包含日志 , 证明事务已经成功提交 , REDO(T) 。
如果日志中包含日志 , 证明事务已经失败 , UNDO(T) 。
如果日志中包含日志 , 参与者P需向其它节点咨询当前事务状态 。
如果协调者正常 , 则向告知参与者P , 事务已经commit或是abort , 参与者依此REDO(T)或UNDO(T) 。
如果协调者异常 , 则向其它参与者询问事务状态 。
a.如果其他参与者收到信息 , 并已知事务是commit还是abort状态 , 需回复参与者P事务状态 。
b.如果所有的参与者现在都不知道该事务的状态(事务上下文销毁了 , 或者自己也处于未决状态) , 那么该事务处于暂时既不能commit也不能abort 。 需要定期向其它节点问询事务状态 , 直到得到答案 。 (这是2PC最不想遇到的一个场景)
c.如果日志中不包含上述几种日志 , 说明该参与者在向协调者发送Ready T消息前就失败了 。 由于协调者没有收到参与者的回应 , 会超时Abort , 因此该参与者在恢复过程中 , 遇到这种情况也需要abort 。
3.如果协调者在事务提交过程中失败 。 参与者需要根据全局事务状态(通过与其它参与者通信)决定本地行为 。
事务状态已经形成决议:
如果至少有一个参与者中事务T已经提交(参与者包含日志) , 说明T必须要提交 。
如果至少有一个参与者中事务T已经Abort(参与者包含日志) , 说明T必须要Abort 。
事务状态未形成决议:
如果至少有一个参与者没有进入Ready状态(参与者不包含日志) 。 说明全局还未就提交与否达成协议 。 有两种选择:(1)等待协调者恢复 。 (2)参与者自行abort 。 为了减少资源占用时间 , 选择后者居多 。
如果所有参与者都进入了Ready状态 , 且都没有或日志(事实上 , 即使有这些日志 , 查日志也是一种比较费的操作 , 还需要考虑日志回收的问题) , 这种情况下 , 参与者谁都不知道现在事务的状态 , 只能死等协调者恢复 。 (又到了这个最不想遇到的场景)
当参与者均进入ready状态 , 等待协调者的下一步指令 , 协调者在这个时候出现异常 , 那么参与者将一直持有系统资源 , 如果基于锁实现的并发控制 , 还会一直持有锁 , 导致其他事务等待 。
【事务|干货放送 细说分布式事务两阶段提交】
这种情况如果持续较旧 , 会对系统产生巨大的影响 。 因此2PC最大的问题就是协调者失败 , 可能会导致事务阻塞 , 未决事务的最终状态 , 只能等待协调者恢复后才确定 。 同时在这种情况下 , 参与者宕机重启 , 回放到这类未决事务 , 重启回放完本地WAL , 还是会有一个未决的事务不知道怎么处理 , 事务持有的资源也不能释放 。
缓解2PC blocking思路
三阶段提交是两阶段提交的延伸 , 目的是解决2PC block的问题 , 但是也引入了其它问题 。 它的解决方式是为参与者引入timeout机制 , 如果参与者成功PreCommit后 , 一直收不到协调者最后的DoCommit请求 , 等待超时自动提交 , 显然这样会引入一致性问题 。
例如 , 协调者收到一个参与者PreCommit失败 , 打算发abort请求给其它参与者时宕机 , 显然此时该分布式事务应该失败 , 但一些参与者可能因为超时而提交 。
为了解决这个问题 , 3PC多引进了一个阶段 , 就是第一个阶段CanCommit阶段 , 协调者询问所有参与者是否可以提交 , 参与者如果状态正常 , 就会回应可以提交 , 但此时并不会占用任何系统资源 。 如果协调者及时收到了所有参与者ok的回应 , 便会认为各个参与者正常 , 之后的提交应该不会失败 。 但是实质上 , 仍有小概率失败的可能:某参与者PreCommit失败后 , 协调者和参与者都宕机 , 其它参与者超时自动提交 , 产生不一致 。
因此3PC还有一个关键优化是协调者宕机后 , 迅速找到一个继任者 , 继续未完的流程 , 尽量保证不会出现参与者超时提交的现象 。 但是如果出现诸如网络分区等异常 , 新的协调者联系不上参与者 , 还是会产生一致性问题 。
3PC通过牺牲一定的C(onsistency)来提高A(vailability) , 并且增加了网络开销 , 这些都是OLTP系统很难接受的 , 所以基本没有系统会采用 。
但是协调者高可用 , 确实可以使block的时间大幅减少 , 基于诸如Paxos/Raft的一致性协议的高可用方案 , 可以让多个节点就commit/abort达成一致后 , 再去通知参与者 , 当协调者出现异常 , 可以迅速选出新的协调者 , 推进事务至完成 。
推荐阅读
- 干货:“低估”的金融股,散户值得拥有吗?
- 塞尔维亚|美威胁塞尔维亚,要求放弃与华为合作,武契奇:内部事务与美无关
- 时政|俄资深评论员:西方无权插手香港事务
- 安陆市开展退役军人事务系统“枫桥式”基层服务站创建工作
- 央视新闻客户端|俄资深评论员:西方无权插手香港事务
- 面料|干货|时装大牌设计师都在用的手艺!一篇让你学会手工绣缀,给你的创意立裁加加餐!
- 火起来的 Flutter 开源项目大放送,不学习就Out了
- 人民币|老会计给大家分享金额书写的规范!干货!收藏!
- 智能锁究竟怎么选择,快进来看干货了
- 智能家居|智能锁究竟怎么选择,快进来看干货了
