FantasticMao 技术笔记
BlogGitHub
  • README
  • C & Unix
    • C
      • 《C 程序设计语言》笔记
      • C 语言中的陷阱
      • CMake 示例
      • GNU make
      • LLVM Clang
      • Nginx 常用模块
      • Vim 常用命令
    • Unix-like
      • 《深入理解计算机系统》笔记
      • 《UNIX 环境高级编程》笔记 - UNIX 基础知识
      • 《UNIX 环境高级编程》笔记 - 文件 IO
      • 《UNIX 环境高级编程》笔记 - 标准 IO 库
      • 《鳥哥的 Linux 私房菜》笔记 - 目录配置
      • 《鳥哥的 Linux 私房菜》笔记 - 认识与学习 bash
      • 《鳥哥的 Linux 私房菜》笔记 - 任务管理
      • OpenWrt 中的陷阱
      • iptables 工作机制
  • Go
    • 《A Tour of Go》笔记
    • Go vs C vsJava
    • Go 常用命令
    • Go 语言中的陷阱
  • Java
    • JDK
      • 《Java 并发编程实战》笔记 - 线程池的使用
      • 设计模式概览
      • 集合概览
      • HashMap 内部算法
      • ThreadLocal 工作机制
      • Java Agent
    • JVM
      • 《深入理解 Java 虚拟机》笔记 - Java 内存模型与线程
      • JVM 运行时数据区
      • 类加载机制
      • 垃圾回收算法
      • 引用类型
      • 垃圾收集算法
      • 垃圾收集器
    • Spring
      • Spring IoC 容器扩展点
      • Spring Transaction 声明式事务管理
      • Spring Web MVC DispatcherServlet 工作机制
      • Spring Security Servlet 实现原理
    • 其它
      • 《Netty - One Framework to rule them all》演讲笔记
      • Hystrix 设计与实现
  • JavaScript
    • 《写给大家看的设计书》笔记 - 设计原则
    • 《JavaScript 权威指南》笔记 - jQuery 类库
  • 数据库
    • ElasticSearch
      • ElasticSearch 概览
    • HBase
      • HBase 数据模型
    • Prometheus
      • Prometheus 概览
      • Prometheus 数据模型和指标类型
      • Prometheus 查询语法
      • Prometheus 存储原理
      • Prometheus vs InfluxDB
    • Redis
      • 《Redis 设计与实现》笔记 - 简单动态字符串
      • 《Redis 设计与实现》笔记 - 链表
      • 《Redis 设计与实现》笔记 - 字典
      • 《Redis 设计与实现》笔记 - 跳跃表
      • 《Redis 设计与实现》笔记 - 整数集合
      • 《Redis 设计与实现》笔记 - 压缩列表
      • 《Redis 设计与实现》笔记 - 对象
      • Redis 内存回收策略
      • Redis 实现分布式锁
      • Redis 持久化机制
      • Redis 数据分片方案
      • 使用缓存的常见问题
    • MySQL
      • 《高性能 MySQL》笔记 - Schema 与数据类型优化
      • 《高性能 MySQL》笔记 - 创建高性能的索引
      • 《MySQL Reference Manual》笔记 - InnoDB 和 ACID 模型
      • 《MySQL Reference Manual》笔记 - InnoDB 多版本
      • 《MySQL Reference Manual》笔记 - InnoDB 锁
      • 《MySQL Reference Manual》笔记 - InnoDB 事务模型
      • B-Tree 简述
      • 理解查询执行计划
  • 中间件
    • gRPC
      • gRPC 负载均衡
    • ZooKeeper
      • ZooKeeper 数据模型
    • 消息队列
      • 消息积压解决策略
      • RocketMQ 架构设计
      • RocketMQ 功能特性
      • RocketMQ 消息存储
  • 分布式系统
    • 《凤凰架构》笔记
    • 系统设计思路
    • 系统优化思路
    • 分布式事务协议:二阶段提交和三阶段提交
    • 分布式系统的技术栈
    • 分布式系统的弹性设计
    • 单点登录解决方案
    • 容错,高可用和灾备
  • 数据结构和算法
    • 一致性哈希
    • 布隆过滤器
    • 散列表
  • 网络协议
    • 诊断工具
    • TCP 协议
      • TCP 报文结构
      • TCP 连接管理
由 GitBook 提供支持
在本页
  • 二阶段提交协议
  • 算法步骤
  • 算法缺点
  • 三阶段提交协议
  • 算法步骤
  • 算法比较
  1. 分布式系统

分布式事务协议:二阶段提交和三阶段提交

二阶段提交协议

算法步骤

@startuml

group 投票阶段

协调者 -> 参与者: can commit?
activate 参与者
参与者 -> 参与者: execute transaction
return yes / no

end

group 提交阶段

alt yes case
	协调者 -> 参与者: do commit
	activate 参与者
	参与者 -> 参与者: commit transaction
	return ack
else no / timeout case
	协调者 -> 参与者: do rollback
	activate 参与者
	参与者 -> 参与者: rollback transaction
	return ack
end

end

@enduml

投票阶段

  1. 协调者向所有参与者询问是否可以执行事务 commit 操作,并(阻塞)等待所有参与者的响应;

  2. 各个参与者执行事务操作至 commit 之前,并记录 undo 日志和 redo 日志;

  3. 各个参与者回复协调者响应消息,事务执行成功 -> yes,事务执行失败 -> no。

提交阶段

情况一:所有参与者返回 yes

  1. 协调者向所有参与者发送执行事务 commit 消息;

  2. 各个参与者在收到消息之后执行事务 commit,并释放整个事务期间占用的资源;

  3. 各个参与者在事务 commit 之后,回复协调者 ack 响应消息;

  4. 协调者收到所有参与者 ack 消息之后,事务 commit 完成。

情况二:任意参与者返回 no,或者协调者等待超时

  1. 协调者向所有参与者发送执行事务 rollback 消息;

  2. 各个参与者在收到消息之后执行事务 rollback,并释放整个事务期间占用的资源;

  3. 各个参与者在事务 rollback 之后,回复协调者 ack 响应消息;

  4. 协调者收到所有参与者 ack 消息之后,事务 rollback 完成。

算法缺点

同步阻塞:已经通过第一阶段的参与者需要等待其它所有参与者响应,才能执行第二阶段。

单点问题:协调者宕机时会导致事务阻塞,参与者宕机时会导致数据不一致。

三阶段提交协议

算法步骤

@startuml

group can commit 阶段

协调者 -> 参与者: can commit?
return yes / no

end

group pre commit 阶段

alt yes case
	协调者 -> 参与者: prepare commit
	activate 参与者
	参与者 -> 参与者: execute transaction
	return commit / abort
else no / timeout case
	协调者 -> 参与者: abort
	return abort
end

end

group do commit 阶段

alt commit case
	协调者 -> 参与者: do commit
	activate 参与者
	参与者 -> 参与者: commit transaction
	return ack
else abort / timeout case
	协调者 -> 参与者: do rollback
	activate 参与者
	参与者 -> 参与者: rollback transaction
	return ack
end

end

@enduml

can commit 阶段

  1. 协调者向所有参与者发送 can commit 消息,并(阻塞)等待所有参与者的响应;

  2. 各个参与者回复协调者响应消息,事务可以执行 -> yes,事务不可以执行 -> no。

pre commit 阶段

情况一:所有参与者返回 yes

  1. 协调者向所有参与者发送 prepare commit 消息,并(阻塞)等待所有参与者的响应;

  2. 各个参与者执行事务操作至 commit 之前,并记录 undo 日志和 redo 日志;

  3. 各个参与者回复协调者响应消息,事务执行成功 -> commit,事务执行失败 -> abort。

情况二:任意参与者返回 no,或者协调者等待超时

  1. 协调者向所有参与者发送中断事务消息;

  2. 各个参与者回复协调者响应消息。

do commit 阶段

情况一:所有参与者返回 commit

  1. 协调者向所有参与者发送 do commit 消息;

  2. 各个参与者在收到消息之后执行事务 commit,并释放整个事务期间占用的资源;

  3. 各个参与者在事务 commit 之后,回复协调者 ack 响应消息;

  4. 协调者收到所有参与者 ack 消息之后,事务 commit 完成。

情况二:任意参与者返回 abort,或者协调者等待超时

  1. 协调者向所有参与者发送 do rollback 消息;

  2. 各个参与者在收到消息之后执行事务 rollback,并释放整个事务期间占用的资源;

  3. 各个参与者在事务 rollback 之后,回复协调者 ack 响应消息;

  4. 协调者收到所有参与者 ack 消息之后,事务 rollback 完成。

异常情况:协调者出现了问题,或者协调者和参与者之间的网络出现问题,导致了参与者无法接受消息

  1. 参与者在等待超时之后执行事务 commit。

算法比较

相较于二阶段提交协议,三阶段提交协议 降低了参与者的阻塞范围,并且能够支持 协调者在 do commit 阶段中出现单点问题时依旧保持数据一致。

但是三阶段协议也是存在问题的,如果 参与者在 do commit 阶段中出现单点问题时会导致数据不一致。

最后更新于1年前