2PC(Two Phase Commitment Protocol)原理
读TiDB原理部分,知道其分布式事务是参考的Google percolator。而percolator是一种2PC的优化。
分布式事务解决的是什么问题呢?
假设一个场景,一个电商网站,用户在购买商品时,需要两步操作1)创建订单,2)扣减库存。我们通常希望这两步是事务的,要么同时成功,要么同时失败。如果订单创建成功,库存扣减失败,会导致超卖。如果订单创建失败但扣减了库存呢,会导致少卖。
怎么解决这个问题呢?
如果订单表和商品表在MySQL同一个逻辑DB里面,可以使用MySQL的单机事务来保证。
如果在不同DB呢?
一种折中的做法,分别在两张表上开事务A、B,两事务都执行完后,同时commit,我们将重要的事务放在前面commit;这样如果A事务失败,则AB同时回滚。但如果A成功commit,B失败,就存在数据不一致的问题。
上面我们让AB等待同时完成后提高,一定程度降低了这种不一致发生的概率。但不是个完善的解决方案。
下面介绍的2PC,为解决这个问题。
首先2PC中有一个协调者节点,多个参与者节点(不同的数据库表)。
【一】协调者协议流程如下:
1. 开启一个事务,写本地日志begin_transaction,进行wait状态
2. 向所有参与者节点发送prepare消息,并等待参与者节点对prepare消息的响应
a. 若任何一个节点返回vote-abort消息,则写本地日志global-abort, 行向所有参与者节点发送global-abort消息,进入ABORT状态
b.若收到所有参与者节点返回的vote-commit消息,本地日志写global-commit日志,并向所有参与者节点发送golobal-commit消息,进入COMMIT状态】
3.等待参与者节点的global-commit或global-abort消息的回复,若所有节点都回复,则写日志end_transication,并完成事务。
【二】参与者协议流程如下:
1.开启事物,写本地日志init,进入INIT状态
2.等待协调者的prepare消息
a.若可以进行本次事务,则写本地日志ready,进入READY状态,并向协调者节点发送vote-commit消息等待回复
b.若收到回复global-abort,写本地日志abort,进入ABORT状态,并向协调者节点发送回复
c.若收到global-commit消息,写本地日志commit,进入COMMIT状态,向协调者发送回复
3.若参与者无法进行本次事务
a.写本地日志abort,进入abort状态,并向协调节点发送vote-abort消息。可以对后序收到的global-abort消息进行响应
4.即使流程结束,但任何时候收到协调者发送的global-abort或global-commit消息,也发送一个相应的回复。
** 以上操作都是先写日志,再进行处理
接下来讨论一下异常处理:
【协调者节点宕机恢复】
先看一下协调节点几种可能日志记录:begin_transiaction, global-commit或global-abort, end_transication
协调者宕机恢复后,先让到事务其最新日志,若是begin_transiaction,表示协调者处于WAIT状态,此时或者已经发送过prepare消息,也可能没有发过。但可以确认,一定没有发送过global-commit或global-abort消息。此时只需要重发prepare消息,即使参与者已经收到并回复过prepare消息,此时只需重新发一条即可。不影响一致性。
如果日志中最后是global-commit或global-abort日志。说明宕机前处于COMMIT或ABORT状态,此时协调者只需向参与者再发一次global-commit或global-abort消息,继续2PC流程。
【参与者节点宕机恢复】
如果日志处于init状态,表示还未对本事务做出选择,继续等待prepare消息即可。
如果处于ready状态,说明已经收到了prepare消息,但是否已经做出回复 不消息可知;所以重发vote-commit消息即可。注意这里是发送的vote-commit而不是vote-abort,因为只有本次事务可以提交,才会到ready状态。
如果日志最后是commit或abort状态,则表示已经收到了global-commit或global-abort消息,但不能确定是否已经发送过了确认消息。这时候只需要等待新的 global-commit或global-abort消息,并进行回复即可。因为协调者节点会不断重发消息。
分布式系统中,错误一般分为两块,超时和其它错误,其中超时是最难处理的错误。接下来讨论超时的问题。
协议的异常,体现在等待消息的超时上面。
【一,协调者在WAIT状态超时】
一般有两种原因,1.协调者与某个参与者之间的网络断开。2.某个参与者宕机,这种超时,可以选择放弃整个事务。因为WAIT状态下,协调者一定未发送来global-abort或global-commit消息,因此只要向所有参与者发送global-abort停止事务就可以,不影响协议正确性。
【二,协调者在COMMIT或ABORT状态超时】
此时,等待参与者对global-commit或global-abort的响应消息超时。这种情况下协调者只能不断重发global-commit或global-abort消息,直到所有参与者都响应。
2PC对这种情况没有很好的容错,只能阻塞在这里不断重试。其中任何结点的超时,或者协调者本身的网络问题,都会导致2PC完成不了。
【三,参与者INIT状态超时】
此时还没收到prepare消息,直接abort即可。但可能导致原先可以提交的事务不能成功完成。
【三,参与者READY状态超时】
READY状态,代表参与者收到prepare消息,并回复了vote-commit消息。此时参与者不能再改变自己的选择,只能不断重发vote-commit,直到收到global-abort或global-commit消息,继续下面流程。这里可以对应到协调者不断重发global-commit或global-abort消息,同样没有很好的容错机制。整个流程阻塞在这里,对于参与者而言,协议状态处于未知,即不能提交本节点事务,也不能放弃本节点事务。(如果提交了,实际协调者发送了global-abort,则在本节点提交,其它节点未提交,导致数据不一致。如果放弃了,则实际协调者发送了global-commit,则本节点放弃,其它节点提交了,同样导致数据不一致。)
实际上,2PC的有很多缺点:
1)容错很差,以上超时分析可知。
2)性能很差,一次通信涉及到4次消息交互,慢节点对整个协议性能影响很大。
3)可用性差,协调者单点
2PC(Two Phase Commitment Protocol)原理的更多相关文章
- nginx phase handler的原理和选择
nginx phase handler的原理和选择 PHASE HANDLER的种类 nginx在接收并解析完请求行.请求头之后.就会依次调用各个phase handler. phase handle ...
- 《大型网站系统与JAVA中间件实践》读书笔记-数据访问层
数据访问层 5.1.2数据库垂直/水平拆分的困难 随着网站业务的快速发展,数据量和访问量不断上升,数据库的压力越来越大. 更换更好的硬件(Scale Up)是一种解决方案,而且在我们能付得起硬件费用并 ...
- zookeeper(2) zookeeper的核心原理
zookeeper 的前世今生 分布式系统的很多难题,都是由于缺少协调机制造成的.在分布式协调这块做得比较好的,有 Google 的 Chubby 以及 Apache 的 Zookeeper. Goo ...
- Zookeeper核心原理
Zookeeper 的核心原理 Zookeeper 的由来 各个节点的数据一致性 怎么保证任务只在一个节点执行 如果orderserver1挂了,其他节点如何发现并接替 存在共享资源,互斥性.安全性 ...
- 分布式事务中的2PC和3PC
分布式事务 分布式事务是指会涉及到操作多个数据库的事务.其实就是将对同一库事务的概念扩大到了对多个库的事务. 分布式事务中需要注意的是分布式系统中存在的一致性问题: CAP原则:在一个分布式系统中,C ...
- mysql小白系列_01 原理
1.什么是MVCC?有什么作用? Multi-Version Concurrency Conrol 多版本并发控为解决数据库并发读写可能会出现不一致数据的情况,需要实现数据库的并发访问控制,写时复制产 ...
- 搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法
搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法 2PC 由于BASE理论需要在一致性和可用性方面做出权衡,因此涌现了很多关于一致性的算法和协议.其中比较著名的有二阶提交协议(2 Phas ...
- 了解一下Mysql分布式事务及优缺点、使用案例(php+mysql)
在开发中,为了降低单点压力,通常会根据业务情况进行分表分库,将表分布在不同的库中(库可能分布在不同的机器上),但是一个业务场景可能会同时处理两个表的操作.在这种场景下,事务的提交会变得相对复杂,因为多 ...
- MSSQL-并发控制-1-Transaction
MSSQL并发控制原先打算分为两个部分写:隔离级别及锁,写的过程中,发现需要提及下事务的相关内容,故加多一篇博文,共3篇. 如果转载,请注明博文来源: www.cnblogs ...
随机推荐
- gevent模块学习(三)
3. Group类,常用于不限制数量的管理异步任务的分组且可搜集运行结果 g = gevent.pool.Group(*args) -> Group 说明: 创建一个组对象,其实就是一个不限gr ...
- cron 配置
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素. 按顺序依次为 秒(0~59) 分钟(0~59) 小时(0~23) 天(月)(0~31,但是你需要考虑你月的天数) 月(0~11) 天( ...
- Vue.js学习过程
打开各大论坛,看到好多Vue.js的话题,可以说现在是非常火的框架,看到一个人这样评论Vue:“Vue.js兼容angular.js和 react.js的优点,并剔除他们的缺点.”因为现在公司不用Vu ...
- AngelToken钱包——值得投资与存币的钱包
Angeltoken有多好? Angeltoken到底值不值得我们投资? 简而言之 Angeltoken结合了:钱包+机器人,钱包+币币交易,钱包+宠物,钱包+结算代币等等. 它颠覆传统的运营和赚钱模 ...
- 阿里云已买到域名价格统计js代码
var sum = 0; $('.table-hover tr.ng-scope').each(function(){ sum = sum + parseInt($(this).children()[ ...
- AnnotationTransactionAttributeSource is only available on Java 1.5 and higher
前言: 在eclipse中用到spring2.0的web项目,启动elipse自带的tomcat7,tomcat7报错如下: AnnotationTransactionAttributeSource ...
- Applet
Applet简介: 可以翻译为小应用程序,Java Applet就是用Java语言编写的这样的一些小应用程序,它们可以直接嵌入到网页中,并能够产生特殊的效果.包含Applet的网页被称为Java-po ...
- Cocos2dx 代码中包含中文导致编译错误的问题解决方法
从网上下载一个cocos2dx的源码,是IOS版本的,我将其迁移到windows 7下 ,用VS2010编译,出现一堆的C2001错误: 1>d:\cocos2d-x-2.2.6\mygame\ ...
- centos下使用yum 安装pip
本文为转载:原文出处:https://www.cnblogs.com/saolv/p/6963314.html centos下安装pip时失败: [root@wfm ~]# yum -y instal ...
- web APIS
WEB API系列: 很多人都很迷惑,既然有了WCF为什么还要有WEB API?WEB API会不会取代WCF? 就我的看法,WCF提供的是一种RPC实现的集合,WCF的设计更多地考虑了SOA的场 ...