查看原文
其他

Java帝国之宫廷内斗

2017-08-10 老刘 码农翻身

前言: 本文是《持久化:Java帝国反击战》续集,开始讲解分布式事务。

1 JDBC大臣


自从和东海之滨的数据库联合酋长国缔结了合作协议以后, IO大臣就退居二线了。


他本来也想把JDBC也划归自己管理, 奈何国王头脑发热、竟然任命了新的JDBC大臣, 专门负责这一摊事儿。


JDBC大臣经常在早朝上给国王吹风:  “ 陛下, 我们的JDBC设计的非常好, 别看什么Hibernate, Mybatis 是现在的事实标准, 他们底层都在用我们的JDBC接口。 ”


国王赞许地频频点头,似乎忘记了这是躲在角落中IO大臣的功绩。


IO大臣咬牙切齿又无可奈何。


这天JDBC又在给国王安利关系数据库的好处: “陛下,这关系数据库相比于简单的文件系统有个巨大的好处,就是支持事务。”


听到JDBC大臣又在贬低自己负责的部门, IO大臣怒火中烧。


国王问道:“什么是事务,要事务干嘛? ”


“我举个通俗的例子你就明白了, 假设IO大臣要给我转账100块钱, 他的数据库账户要扣掉100块, 我的账户要增加100块, 这就涉及到两个操作, 这两个操作要么全部完成,要么一个都不做,只有这样才能保证数据的一致性, 这就是一个事务。数据库联合酋长国有个对事务总结了4个特性: 原子性(Atomicity) ,一致性(Consistency), 隔离性(Isolation) , 持久性(Durability) , 简称ACID, 要不我再给详细的解释下?”


国王连忙摆手:“不不不, 别拿这些细节烦我, 你就告诉我们的臣民怎么去使用就行了”


JDBC大臣说: “这个很简单, 默认情况下我们的JDBC都会把对数据库的操作认为是一个事务, 当然臣民们也可以设置成手工的方式, 手工地提交和回滚事务。不管哪种方式,都是非常简单的 。”


国王说: “那就好, 爱卿辛苦了, 还有事吗? 有事启奏,无事退朝。”

2 密谋


IO大臣回到家中,依然感觉火气难平, 招来幕僚商谈。


InputStream说: “大人, 这JDBC大臣虽然猖狂, 我们却暂时拿他没办法, 现在都是Web时代, 哪个应用不用数据库啊? ”


“难道就让他这么猖獗下去? ”


InputReader足智多谋: “我倒是有一计, 只是得等待时机。 ”


“什么时机?”


“你看今天JDBC那厮提到了事务, 但是这个事务只是在一个数据库中有用啊, 如果需要跨数据库怎么办? 比如我的账号存在数据库A,  你的账号在数据库B, 那转账的时候怎么办? 怎么实现什么ACID ? ”


InputStream表示不同意: “谁会这么傻, 把我们的账号信息放到两个数据库当中? ”


“这就是时候未到, 现在大部分的应用数据量都不大, 放到一个数据库中绰绰有余,等到数据量大到一定程度,势必要拆分数据库,就会出现跨数据库的事务, 到那个时候我们的机会就来了, 我们准备好解决方案, 参那厮一本, 不信扳不倒他!”


IO大臣拍板: “好! 就这么办, 这事离不开数联酋(数据库联合酋长国)的支持,我和他们还有交情, 这就派人去,许以重金, 让他们继续和我们合作。”


在IO大臣密谋的同时, JDBC大臣的家中却是觥筹交错、莺歌燕舞。


有识之士如Connection 曾经向JDBC大臣提醒过要和数联酋搞好关系, 以便将来有什么不时之需。 可是处于巅峰的JDBC大臣哪能听得进去?


3  两阶段提交


InputReader 果然很有远见, 随着时间的流逝, Web越来越发达, 帝国出现了很多巨型网站, 他们的各种数据果然是没法放到一个数据库中了,把大的业务系统查分成多个数据库势在必行, 当一个业务同时操作多个数据库的时候, 没有分布式事务是做不了的。


正在此时,一个秘密奏章被送到了国王的案头, 状告JDBC大臣因循守旧,面对大好的形式不与时俱进,对分布式事务漠不关心,毫无作为。


国王召集朝会,讨论分布式事务的问题, 他向JDBC大臣率先发难: “爱卿, 你听说过臣民们要求支持分布式事务吗?”


JDBC大臣慌了: “这。。。 这好像是一撮刁民提的要求吧, 陛下不用理会。”


IO大臣冷笑一声:“刁民? 我看是良民吧 !  启奏陛下, 据臣所知,帝国有不下百个系统要求支持分布式事务,JDBC大臣竟然连最基本的情况都不知道, 真是毫无作为。”


IO大臣觉得稳操胜券,直接撕破了脸。


国王心里明白了几分, 他直接对IO大臣说: “爱卿,你说说该怎么办?”


“陛下,当年臣和数据库联合酋长国谈判的时候, 和他们建立了良好的交情。 前几天我宴请他们的时候,特别提及了这件事情。 Oracle 告诉臣,这很好办, 人家别的王国正在讨论实施两阶段提交的协议, 我们也可以参与进来。”


虽然IO大臣已经和数据库联合酋长国讨价还价了很久, 不知道花费了多少金钱,但还是不显山不漏水、很随意地说了出来。


JDBC大臣一看IO大臣进入了自己的一亩三分地, 急忙问道: 什么是两阶段提交?


IO大臣不屑地瞥了他一眼, 从袖子中拿出早就准备好的提议,双手向国王奉上。


国王哪里看得懂,扫了一眼就赐给望眼欲穿的JDBC大臣, 只见上面赫然写着:


两阶段提交协议

由于涉及到多个分布式的数据库, 我们特设一个全局的事务管理器,它来负责协调各个数据库的事务提交, 为了实现分布式事务,特设两个阶段:


阶段1: 全局的事务管理器向各个数据库发出准备消息。 各个数据库需要在本地把一切都准备好,执行操作,锁住资源, 记录redo/undo 日志, 但是并不提交, 总而言之,要进入一个时刻准备提交或回滚的状态, 然后向全局事务管理器报告是否准备好了。


阶段2: 如果所有的数据库都报告说准备好了, 那全局的事务管理器就下命令: 提交, 这时候各个数据库才真正提交 , 由于之前已经万事具备,只欠东风,只需要快速完成本地提交即可;

如果有任何一个数据库报告说没准备好, 事务管理器就下命令: 放弃, 这时候各个数据库要执行回滚操作, 并且释放各种在阶段1锁住的资源。


JDBC大臣也是行家,一看就明白了是怎么回事。阶段1就是让大家都准备好,阶段2就是迅速提交。


这是一个看起来很美的理想方案,但是他意识到其中有漏洞,自己的幕僚曾经告诫过:一旦涉及到分布式,事情就不会那么简单,任何地方都有失败的可能。


比如在第二阶段,那个事务管理器要是出了问题怎么办? 人家各个数据库还在等着你发命令呢? 你迟迟不发命令,大家都阻塞在那里,不知所措,到底是提交呢?还是不提交呢, 我这里还锁着资源呢, 迟迟不能释放,多耽误事啊 ! 


还是第二阶段,事务管理器发出的提交命令由于网络问题,数据库1收到了,数据库2没收到,这两个数据库就处于不一致状态了, 该怎么处理?


JDBC大臣决心给IO大臣挖个坑:让你逞能 ! 让你给老子穿小鞋! 


他说:“ 陛下,IO大臣不愧为设计过JDBC协议的股肱之臣, 臣才学疏浅,深为拜服,特奏请陛下恩准IO大臣再次出山和数据库联合酋长国设计出新协议, 来支持分布式事务。”


国王准奏。

4  JTA


IO大臣满心狐疑, 不知道JDBC老头儿在给自己下什么药,回到府中和大家商量。


InputReader 眼看自己多年前的计策就要成功,颇为兴奋: “管它呢, 只要咱们把这个分布式事务的协议给制定好,JDBC老儿就得下台了。”


“对,到时候我们就掌管文件, 网络,数据库,Java 帝国就是我们IO独大了”  InputStream 开始畅想美好的未来,到时候自己估计至少从5品升为4品。


IO大臣马上安排和数据库联合酋长国的谈判,由于之前良好的交情。 这一次协议很容易就达成了, IO大臣给他起了一个很响亮的名字: Java Transaction API (简称JTA)。


这个JTA规范用起来也比较简单, 只要获得一个UserTransaction 就可以操作了,帝国的臣民们根本不用关系底层的协议细节:

经过国王的批准, JTA正式推广。


可是令IO大臣万万没有想到的是, 国王在JTA发布的前夕, 亲切地召见了自己和另外一个不知名的官员, 国王关心地说:“爱卿,朕知道你很忙,掌管着网络和文件操作,为了给你减轻负担,朕决定任命一个新的JTA大臣来协助你!”


IO大臣如同五雷轰顶,自己辛辛苦苦的工作完全被无视, 这到底是为什么?


他失魂落魄地回到府中, 好几天茶饭不思。


还是InputReader 出来安慰了他: “这是陛下的帝王之术, 害怕我们一家坐大, 平衡了一下朝中力量。大人可以放宽心, 你看JDBC大臣也受到了打压,风光不再了。”


5 塞翁失马,焉知非福


JTA并没有取得像JDBC那样的广泛应用, JDBC大臣挖的那个坑现在终于露出了狰狞的面目。


只不过这个坑并没有让IO大臣掉进去, 新任的JTA大臣背了黑锅。


臣民的抗议声越来越多: 分布式事务伴随着大量节点的通信交换, 协调者要确定其他节点是否完成, 加上网络带来的超时,导致JTA性能低下, 在高并发和高性能的场景下举步维艰。


拜IO大臣的工作所赐,  现在数据库联合酋长国的各个部落都支持两阶段提交,很多应用服务器Websphere , Weblogic 等都支持JTA, 可是使用者确是寥寥无几, 都快成摆设了。


JTA大臣每次上朝都战战兢兢, 他是个平庸之辈,虽然四处救火,但是无力解决根本的问题。


现在那些高并发的系统反而极力避免两阶段提交, 他们绕开JTA大臣, 直接找到了IO大臣诉苦:“大人,你带领着制定了JTA, 但是这个标准太理想化,完全不符合实情啊! ”


IO大臣说: “不会吧,这不是你们要求的吗, 用户A和B的账号分别在两个数据库, 当A给B转账100块的时候, 肯定得保证A扣掉100, 然后B增加100啊。”


“这就是官府的想法, 总是想着让两个数据库保证实时的一致性(强一致性), 为了达到这个目标,JTA付出的代价太高了。 我们现在不想这么干了。 我们可以忍受一段时间的不一致,只有最终一致就行。 比方说A给B转100元, A 中的钱已经扣除, 但是B中不会实时地增加,过段时间能保证增加就行了”


“最终一致性? 有点意思!”   ,想到Java 帝国的官方标准总是被臣民们所建立的事实标准所打败,敏锐的IO大臣立刻看到了背后的机遇, 他决定这一次要联合民间力量,再次反攻, 一举搞掉JDBC大臣和JTA大臣。


想到这里, IO大臣得意地笑了......


(未完待续)


你看到的只是冰山一角, 更多精彩文章,请移步《码农翻身2016文章精华》或者《码农翻身2017上半年文章精华


有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 3340792577



码农翻身

用故事讲述技术

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存