从2PC和容错共识算法讨论zookeeper中的Create请求 | 京东云技术团队

最近在读《数据密集型应用系统设计》,其中谈到了zookeeper对容错共识算法的应用。这让我想到之前参考的zookeeper学习资料中,误将容错共识算法写成了2PC(两阶段提交协议),所以准备以此文对共识算法和2PC做梳理和区分,也希望它能帮助像我一样对这两者有误解的同学。

1. 2PC(两阶段提交协议)

两阶段提交 (two-phase commit) 协议是一种用于实现 跨多个节点的原子事务(分布式事务)提交 的算法。它能确保所有节点提交或所有节点中止,并在某些数据库内部使用,也以 XA事务 的形式在分布式服务中使用。

在 Java EE 中,XA事务使用 JTA(Java Transaction API) 实现。

2PC的实现

2PC包含 准备阶段 和 提交阶段 两个阶段,需要借助 协调者(事务管理器,如阿里巴巴的Seata)  来实现,参与分布式事务的数据库节点为 参与者。当分布式服务中的节点准备提交时,协调者开始 准备阶段:发送一个 准备请求 到每个节点,询问它们是否能够提交,然后协调者会跟踪参与者的响应

  • 如果所有参与者都回答"是",表示它们已经准备好提交,那么协调者在 提交阶段 发出 提交请求,分布式事务提交
  • 如果任意一个参与者回答"否",则协调者在 提交阶段 中向所有节点发送 中止请求,分布式事务回滚

image.png

上图是2PC提交成功的情况,我们来详述下过程:

  1. 当服务启动一个分布式事务时,它会向协调者请求一个事务ID,此事务ID是全局唯一的
  2. 在每个参与者上启动单节点事务,每个单节点事务会持有这个全局事务 ID。所有的读写都是在这些单节点事务中各自完成的。如果在这个阶段出现任何问题(节点崩溃或请求超时),则协调者或任何参与者都可以中止
  3. 当应用准备提交时,对应准备阶段:协调者向所有参与者发送一个 准备请求,同样也持有全局事务 ID 。如果任意一个请求失败或超时,则协调者向所有参与者发送针对该事务 ID 的 中止请求,即2PC提交中止的情况
  4. 参与者收到 准备请求 时,需要确保在任意情况下都可以提交事务。这包括将所有事务数据写入磁盘(出现故障,电源故障,或硬盘空间不足都不能是稍后拒绝提交的理由)以及检查是否存在任何冲突或违反约束。通过向协调者回答 “是”,节点承诺这个事务一定可以不出差错地提交。也就是说:参与者没有实际提交,同时放弃了中止事务的权利
  5. 当协调者收到所有 准备请求 的答复时,会就 提交或中止事务 作出明确的决定(只有在 所有参与者 投赞成票的情况下才会提交),这里对应提交阶段。协调者必须把这个提交或中止事务的决定 写到磁盘上的事务日志中,记录为 提交点(commit point) 。如果它随后崩溃,能通过提交点进行恢复
  6. 一旦协调者的决定已经保存在事务日志中,提交或中止请求会发送给所有参与者。如果这个请求失败或超时,协调者 必须永远保持重试,直到成功为止,对于已经做出的决定,协调者不管需要多少次重试它都必须被执行

2PC协议中有两个关键的 不归路 需要注意:

  • 一旦协调者做出决定,这一决定是不可撤销的
  • 参与者投票 “是” 时,它承诺它稍后肯定能够提交(尽管协调者可能仍然选择放弃),即使参与者在此期间崩溃,事务也需要在其恢复后提交,而且由于参与者投了赞成,它不能在恢复后拒绝提交

这些承诺保证了2PC的 原子性。

协调者失效的情况

如果 协调者失效 并且所有参与者都收到了准备请求并投了是,那么参与者什么都做不了只能等待,而且这种情况 解决方案 是等待协调者恢复或数据库管理员介入操作来提交或回滚事务,当然如果在生产期间这需要承担运维压力。

所以,协调者在向参与者发送提交或中止请求 之前,将其提交或中止决定写入磁盘上的事务日志(提交点)。这样就能在协调者发生崩溃恢复后,通过读取其事务日志来确定所有 存疑事务 的状态,任何在协调者事务日志中没有提交记录的事务都会被终止。因此两阶段提交在第二阶段(提交阶段)存在阻塞等待协调者恢复的情况,所以两阶段提交又被称为 阻塞原子提交协议

番外:3PC

三阶段提交协议也是应用在分布式事务提交中的算法,它的提出是为了解决两阶段提交协议中存在的阻塞问题。它分为 CanCommit阶段PreCommit阶段 和 DoCommit阶段,通过引入 参与者超时判断机制 来解决2PC中存在的参与者依赖协调者的提交请求而阻塞导致的资源占用等问题。

上图为在DoCommit阶段,参与者判断 DoCommit请求 超时情况的流程图,我们详述下它的避免阻塞的流程

  1. 服务在每个参与者上启动单节点事务,当参与者准备提交时,对应CanCommit阶段,协调者会向所有参与者发送 CanCommit请求,如果任意一个请求失败或超时,则协调者会向所有参与者发送针对该事务的 中止请求,执行事务回滚
  2. 当协调者收到所有CanCommit请求的答复时,如果全是“是”那么则进入PreCommit阶段,否则发送中止请求,执行事务回滚
  3. 进入PreCommit阶段后,协调者会向所有参与者发送 PreCommit请求,同样还是如果存在请求失败或超时,会发送中止请求执行事务回滚
  4. 协调者收到所有PreCommit请求的答复时,如果全是“是”那么则进入DoCommit阶段,否则发送中止请求,执行事务回滚
  5. 进入DoCommit阶段后,协调者会向所有参与者发送 DoCommit请求,注意这里,如果某个参与者没有收到该请求,它默认认为协调者会发送提交请求,那么便本地执行提交事务,从而避免阻塞

3PC虽然解决了2PC中存在的阻塞问题,但是也引入了新的问题:

  • 如果协调者在DoCommit阶段回复的是中止请求,那么超时节点自顾自地提交事务就会发生数据不一致的情况
  • 通讯次数增加和实现相对复杂

3PC使原子提交协议变成非阻塞的,但是3PC 假定网络延迟和节点响应时间有限,在大多数具有无限网络延迟和进程暂停的实际系统中,它 并不能保证原子性。非阻塞原子提交需要一个 完美的故障检测器 来以可靠的机制判断一个节点是否已经崩溃,而在无限延迟的网络中,超时并不是一种可靠的故障检测机制,因为即使节点没有崩溃也会因为网络延迟而超时,出于这个原因,2PC仍然被使用,尽管存在协调者故障的问题。

2. 容错共识算法

容错共识算法用于 节点间数据同步,保证各个副本间数据的一致性和集群的高可用。它的通常形式是一个或多个节点可以 提议(propose)  某些值,而共识算法 决定(decides)  采用其中的某个值,并让这些节点就提议达成一致。共识算法必须具备如下性质:

  • 一致同意:没有两个节点的决定不同
  • 完整性:没有节点决定两次
  • 有效性:如果节点决定了v值,那么v由该节点所提议
  • 终止性:由所有未崩溃的节点来最终决定值

终止性实质上是说:容错共识算法不能简单地永远闲坐着等待,而是需要根据大多数节点来达成一项决定,因此终止属性也暗含着 不超过一半的节点崩溃或不可达 的信息。

一致同意和完整性是共识的 核心思想,即所有节点决定了相同的结果并且决定后不能改变主意。

容错共识算法在节点集群内部都以某种形式使用一个领导者,并定义了一个 纪元编号(epoch number)  来确保在每个时代中,领导者都是唯一的。每当现任领导宕机时,节点间会开始一场投票,来选出一个新的领导,每次选举被赋予一个新的纪元编号(全序且单调递增),如果有两个不同时代的领导者之间出现冲突(脑裂问题),那么带有更高纪元编号的领导者说了算。领导者每想要做出的每一个决定,都必须将提议值发送给其他节点,并等待 法定人数 的节点响应并赞成提案。法定人数通常(但不总是)由多数节点组成(一般为过半),只有在没有发现任何带有更高纪元编号的领导者的情况下,一个节点才会投票赞成提议。

容错共识算法的局限性

  1. 节点在做出决定之前对提议进行投票的过程是一种同步复制
  2. 共识系统总是需要有 法定人数 的节点存活来保证运转
  3. 大多数共识算法假定参与投票的节点是固定的集合,这意味着你不能简单的在集群中添加或删除节点
  4. 共识系统通常依靠 超时 来检测失效的节点,在网络延迟高度变化的环境中,特别是在地理上散布的系统,经常发生一个节点由于暂时的网络问题,错误地认为领导者已经失效。虽然这种错误不会损害安全属性,但频繁的领导者选举会导致糟糕的性能表现,所以共识算法对网络问题比较敏感,而在面对不可靠的网络相关的共识算法研究仍在进展中

3. 2PC和容错共识算法的区别

  1. 负责解决的问题不同:2PC解决的是分布式事务的一致性,各个节点存储的数据各有不同,目标侧重于保证事务的ACID;容错共识算法解决的是节点副本间数据的一致性和保证集群的高可用,节点间存储的数据完全一致,目标侧重于数据的复制和同步
  2. 每个提议通过要求的参与节点数不同:2PC要求 所有的参与者表决成功 才通过;容错共识算法只需要 遵循基于法定人数的表决 即可,这也是容错共识算法 终止属性(由所有未崩溃的节点来决定最终值)  的体现
  3. 集群的高可用保证:2PC的协调者不是通过选举产生的,而是单独部署并人为指定的组件,所以它没有选主机制,不具备高可用性;应用容错共识算法的集群领导者是通过选举机制来指定的,并且在发生异常情况时(主节点宕机)能够选出新的领导者,并进入一致的状态,以此来保证集群的高可用

4. zookeeper中的一次Create请求

一些资料中会提到zookeeper在执行CRUD请求时,使用的是2PC,而 实际上它使用的是容错共识算法。我们以Create请求的流程为例(如下图),来加深和记忆这一知识

  1. 客户端发 create 请求到 Leader,即使请求没落到 Leader 上,那么其他节点也会将写请求转发到 Leader
  2. Leader 会先发一个 提议(proposal)请求给各个 Follower,且自己将数据写到本地文件
  3. Follower 集群收到 proposal 请求后会将数据写到本地文件,写成功后返回给 Leader 一个 ack回复
  4. Leader 发现收到 ack 回复的数量为 法定人数(过半,包含当前 Leader 节点)时,则提交一个 commit 请求给各个 Follower 节点。发送 commit 请求就代表该数据在集群内同步情况没有问题,并且 可以对外提供访问 了,此时Leader会把数据写到内存中
  5. Follower 收到 commit 请求后也会将数据写到各自节点的内存中,同时Leader会将数据发给 Observer集群,通知 Observer集群 将数据写到内存

巨人的肩膀

  • 《数据密集型应用系统设计》第九章:分布式事务与共识
  • 百度百科:三阶段提交
  • 浅谈分布式一致性协议之3PC
  • 分布式事务(2PC) vs 共识协议(Paxos/raft)
  • 《深度剖析zookeeper核心原理》
  • 原文收录:GitHub-Enthusiasm

作者:京东物流 王奕龙

内容来源:京东云开发者社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1669.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch快速入门中文——07(TensorBoard)

使用 TensorBoard 可视化模型,数据和训练 原文:https://pytorch.org/tutorials/intermediate/tensorboard_tutorial.html 在 60 分钟突击中,我们向您展示了如何加载数据,如何通过定义为nn.Module子类的模型提供数据,如…

H.264帧结构和RTSP协议源码框架

目录 1、H264编码原理和基本概念 1.1、h.264编码原理 1.2、h.264编码相关的一些概念 2、H264的NAL单元详解 2.1、VCL和NAL的关系 2.2、H.264视频流分析工具 2.3、h264视频流总体分析 2.4、相关概念 3、H264的NAL单元---sps和pps 3.1、sps和pps详解 3.2、H264的profil…

【从删库到跑路】详细讲解MySQL的函数和约束作用

🎊专栏【MySQL】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 文章目录 🍔函数⭐字符串函数🎈字符串拼接函数&…

途乐证券|人工智能概念再度下挫 海天瑞声、寒武纪等跌超10%

人工智能概念26日盘中大幅回调,截至发稿,当虹科技跌近18%,美亚柏科、昆仑万维跌约13%,博睿数据、光云科技、海天瑞声、寒武纪等跌超10%,焦点科技跌停,云从科技、朗玛信息、三六零等跌超9%。 香港途乐证券有…

如何在编程中中实现负载均衡和容错处理

什么是容错 容错是指系统(计算机、网络、云集群等)在其一个或多个组件发生故障时继续运行而不会中断的能力。 创建容错系统的目的是防止由单点故障引起的中断,确保任务关键型应用程序或系统的高可用性和业务连续性。 容错系统使用备份组件…

走进人工智能|深度学习 算法的创世纪

前言: 深度学习通过训练深层神经网络模型,可以自动学习和提取数据的特征,包括更准确的图像识别、自然语言处理、医学诊断等方面的应用。 文章目录 序言背景算法的创世纪技术支持应用领域程序员如何学总结 序言 深度学习是一种机器学习方法&a…

【2023年江西省研究生数学建模竞赛】题目一 蒸汽发生器倒U型管内液体流动 建模方案及参考文献

代码与结果如下:完整文档见文末 完整思路”请点击这里“到原文章获取 题目: PACTEL压水堆整体测试设备在2009年建造,用于带有垂直倒U型管蒸汽发生器的压水堆热液压相关的安全性研究,参见图1。 PACTEL压水堆设施包括一个反应堆压力容器模型…

2.ThreadLocalRandom

Random类及其局限性 一般情况下&#xff0c;我们都会使用java.util.Random来生成随机数&#xff08;Math.random()也是使用Random实例生成随机数&#xff09;。 示例 public static void main(String[] args) {Random random new Random();for (int i 0; i < 10; i) {S…

LED显示屏结构

LED显示屏通常由以下几个主要组成部分构成&#xff1a; LED模块&#xff1a;LED模块是构成LED显示屏的基本单元。它包含多个LED点阵&#xff0c;每个点阵包含红色、绿色和蓝色LED灯珠&#xff0c;通过不同的亮度和颜色组合来呈现图像和视频。LED模块的尺寸和像素密度可以根据需…

训练自己的ChatGPT 语言模型(一).md

0x00 Background 为什么研究这个&#xff1f; ChatGPT在国内外都受到了广泛关注&#xff0c;很多高校、研究机构和企业都计划推出类似的模型。然而&#xff0c;ChatGPT并没有开源&#xff0c;且复现难度非常大&#xff0c;即使到现在&#xff0c;没有任何单位或企业能够完全复…

利用低代码平台实现协同办公,助力企业提升效益

概要&#xff1a;本文介绍了协同办公的作用&#xff0c;以及利用低代码平台实现协同办公的优势。同时也分享了天翎为华晨汽车打造的低代码协同工具&#xff0c;帮助企业提高管理效率&#xff0c;改善运营模式&#xff0c;提升产品质量及生产精益化。展示了咨询库、原料质量录入…

实习工作之定时任务

需求&#xff1a;在当天晚上12点定时将过期数据的状态置为冻结状态 版本一代码实现[相当于是一个死代码&#xff0c;因为不能自动调度] public void updateStatus() throws CommonException, ParseException {String date_str "2023-07-01 00:00:00";Date expireT…