转自:http://www.voidcn.com/article/p-dpwzjkho-bmt.html
这是个系列故事,没有读过前两回的不妨看看《持久化:Java帝国反击战》 和 《Java帝国之宫廷内斗》
1 前情提要上回说到IO大臣一直被JDBC大臣打压, 为了搞掉JDBC大臣, 他忍辱负重、历经千辛万苦终于搞出了分布式事务的标准Java Transaction API, 满心以为这次必定翻身,但是没想到国王为了平衡朝中的权利, 居然把JTA的管理权赐给了新任的JTA大臣。
更没有想到的是,幸亏自己没有管理JTA,这个官方标准太强调强一致性,和民间的高并发系统要求的最终一致性不合拍,用不起来,变成了JTA大臣的烫手山芋。
和民间代表深谈了一次以后,本来已经心灰意冷的 IO大臣再次激起了雄心壮志: 一定要把JDBC大臣和JTA大臣搞掉。
2 基本可用IO大臣马上找了自己的心腹幕僚 InputReader , 交代了一项任务, 去民间考察这些高并发系统是怎么折腾最终一致性的。
InputReader 连夜出发, 为了不引起JDBC大臣和JTA大臣的注意, 这次特意微服私访。
他不辞辛苦, 跑遍了帝国大大小小几十个高并发系统, 与大量的民间领袖深入地交换了意见。 他越谈越惊心: 我们总是高高在上地制定所谓官方标准,自我感觉良好,实际上根本没人用, 前有EJB, 今有JTA, 都是脱离了实际需求想出来的。
3个月后, InputReader 已经成竹在胸, 回到京城向大人汇报。
“大人, 据小人观察, 我们的JTA用的人确实很少,我现在是理解了他们民间所说的最终一致性了”
看着黑瘦的InputReader, IO大臣心里非常感动, 暗下决心: 等老夫控制了朝局, 一定给忠于自己的InputReader升两级。
“还是拿那个转账的例子来说吧” InputReader 喝了口茶继续说 “ 假设两个账户(吕秀才和郭芙蓉)在两个独立的数据库中, 我们原来设计的JTA是要求从吕秀才账户减去100两银子, 然后在郭芙蓉账户加上100两银子, 这两个操作要么全部做完,要么全部不做, 但是在网络的环境下, 这是不大容易做到的, 或者说在高并发的情况下做到的代价太高。”
“这我理解,上次说了, 你说说民间到底是怎么实现的。” IO大臣有点心急。
“其实特别简单, 他们用了一个叫做消息队列的东西来实现的, 大人请看 ” InputReader 展开了一张图:
(码农翻身注: 消息队列的故事参见《Java 帝国之消息队列》)
IO大臣看着图: “就这么简单?”
InputReader 说: “小人举的是个非常简单的例子, 但是也能说明问题了, 你看我们想从吕秀才账户转100两银子给郭芙蓉, 需要在数据库1发起一个事务, 从吕秀才账户扣除100两, 然后还得向消息队列插入一条给郭芙蓉账号增加100两的消息, 然后这个数据库1的事务就结束了! 消息队列中的消息会在某一刻被读取出来,进行处理,给郭芙蓉的账号增加100两。”
“那给郭芙蓉添加100两的消息什么时候会被处理呢? ”
“这个时间不确定, 就看具体怎么实现了, 比如有个后台程序定期运行,读取消息来处理 ”
“那万一消息队列down机怎么办? ”
“不用怕, 消息队列的数据都是持久化到硬盘上的, 不会丢失。”
“郭芙蓉这么刁蛮, 这100两银子不能立刻到账, 她还不把吕秀才给‘排山倒海’了?”
“大人,这就是关键了,你想啊, 假设数据库2 down机了, 对郭芙蓉有两种选择: 一种是由于系统原因,转账操作完全不能操作,另外一种是可以转账,但是钱稍后到账,你说郭芙蓉会选哪一种?”
IO大臣说: “有道理,第一种情况是完全不可用, 第二种只是是部分可用, 郭芙蓉肯定会先让吕秀才转账, 反正100两银子是自己的, 早一点晚一点也没关系。 ”
“对的, 这就是最终一致性,数据虽然在某些时候看起来不一致,吕秀才的钱少了但是郭芙蓉的钱没增加,这个时候钱在消息队列中暂时存着呢。”
“这样做有什么好处?”
“好处很大,对于高并发的场景,转账的时候扣完钱, 向消息队列插入消息,事务就结束了, 根本不用什么两阶段提交, 性能很好。”
“嗯,不错, 我们再来看看一些细节吧。。。。。。”
3 走漏风声天下没有不透风的墙, JDBC大臣的密探早已潜伏在IO府中好多年了,虽然只是个端茶送水的下人, 但是很多消息都进入了他的耳朵, 然后又进入了JDBC大臣的耳朵。
JDBC大臣找来了JTA大臣前来商议, 为了找一个同盟军和强大的IO大臣对抗, JDBC大臣收买了不干实事的JTA大臣。
“你知道吗? IO老头儿派人出去调查了, 我估计很快就会像上次那样参我一本。” JDBC大臣忧心忡忡。
“这IO老头儿为啥老是和大人过不去呢, 守好他那一亩三分地多好!”
“人的欲望都是无穷的,再说我这几年确实打压他比较厉害, 不说了,你先看看这张图, 是我们的卧底从IO府中偷出来的。”
JTA大臣抽了一口冷气:“现在民间都这么玩了? 不用JTA了? ”
“是啊, 你看他们的方法还不错嘛, 基本可用,最终一致性。真是实践中出真知啊” JDBC大臣感叹道,他在观察JTA的反应。
“大人, 我建议咱们抢先一步, 明天早朝就把这幅图献给陛下,陛下一高兴,估计就会把这一块儿划给我管了, 不不, 是给你管了。 ”
“这合适吗?”
“无毒不丈夫, 朝中争斗本来就是你死我活的, 大人不可太妇人之心了。”
“好,就这么办。”
4 宫廷激辩国王已经厌倦了早朝, 厌倦了臣子们在朝中争来争去。
这天出奇的平静, JDBC大臣和IO大臣没有像之前那样争得不可开交, 国王正要宣布 “有事启奏,无事退朝” , 一直以来战战兢兢的JTA大臣咳嗽了一声, 发言了 :
“陛下,臣最近得到一个民间上供的设计图,说是民间用了一种新型办法来处理高并发问题 ” JTA 一边把偷来的图纸呈上去,一边用余光迅速地扫了一眼IO大臣。
JDBC在一旁添油加火:“陛下,臣也看过这个设计, 觉得非常不错, 建议帝国设立标准推广。”
IO大臣一切都明白了,自己还没有出手,这俩老头儿先下手为强了。
国王自然是看不懂,听到两位大臣都这么肯定, 懒洋洋的说: “爱卿此言不错,这个既然属于分布式事务, JTA大臣,你来领衔把他设计出来。”
IO大臣看准时机,突然出手:“陛下万万不可, 这个设计有重大缺陷啊!”
“什么缺陷? ” JDBC大臣和IO大臣齐声问道。
IO大臣胸有成竹, 一切尽在计划之中,那个图纸只不过是个小诱饵而已,这两个愚蠢的老头儿果然上钩。
“陛下,请看这个图纸, 吕秀才给郭芙蓉转账的时候,图纸中写的是:”
“我想请问JDBC老头儿, 不, 大臣, 这个事务同时操作了数据库和一个消息队列, 这两个东西是完全不同的, 请问你是怎么实现的?不会还是使用老掉牙的JTA吧”
(码农翻身注: JTA不仅仅可以支持数据库, 只要是支持XA协议的数据源都可以)
JDBC心中大叫不好,中计了! 唉,自己怎么不仔细研究下图纸呢, 这么一个缺陷竟然没有发现, 冒冒失失地献给陛下,真是不可饶恕啊!
可是他不甘心就此失败, 稍一定神,立刻反击: “先不说缺陷问题, 我想问你这个图纸刚才只有陛下看了, 你怎么知道其中内容?!”
IO大臣看到他反咬一口,岂能罢休 ,一不做二不休,干脆撕破脸: “陛下, 这张图纸本来是我府中的InputReader 走遍帝国,遍访民间疾苦画出来的, 我们知道有缺陷, 还没来得及修改,就被他俩给偷了去 !”
“你血口喷人!” JDBC和JTA有些心虚了。
“陛下,我已经抓住了偷窃图纸的佣人, 随时可以传唤。”
国王一切都明白了: 这些大臣之间的争斗真是无处不在啊, 每天如此,都不能让我消停一天。
“爱卿,” 国王对IO大臣说, “你先说说怎么解决那个图纸中的缺陷问题吧”
“陛下,其实有很多办法, 比如这一种” IO大臣从袖中掏出一个图纸,举了起来,让大家都能看到:
“在这里,我们可以添加一个‘事件表’, 转账开始的时候,把吕秀才的100两银子扣除, 同时还向事件表插入一行记录: 需要向郭芙蓉转100两, 由于这两个表是在同一个数据库中,所以直接使用本地事务就行。不用什么分布式事务。”
“你那个定时运行程序干嘛?” JTA大臣理解力有限
“就是定时运行, 从事件表中取出记录, 向MQ写入消息, 然后把记录的状态改成‘DONE’, 这样下次就不用再去取去处理了。 ”
JDBC大臣很老练: “那你这个定时运行程序也有问题啊, 比如说它读了数据,向消息队列写入了消息, 还没来得及把事件表的status 改为 ‘DONE’ 就崩溃了,等到定时运行程序重启以后,岂不再次读取, 再次向MQ写入消息,这样郭芙蓉不就得到了200两银子,整个系统就不一致了。”
IO大臣心里有点佩服, 这老头儿还是有两把刷子的。 幸亏我和InputReader讨论过各种细节,要不然还真被他给问住, 那在陛下面前就悲催了。
5 幂等性“其实这里必须得引入一个概念: 幂等性” IO大臣说
“迷瞪性? 这是什么东西 ” JTA大臣大惑不解。
“是幂等性, mi ,四声” IO大臣对朝中有这样不学无术占据高位的家伙感到很悲哀, “这个幂等性说的是当你对一个事物操作的时候,可以一直重复地操作,那个事物不受影响, 例如对郭芙蓉的账号你查询一千次,一万次,账户余额还是那么多,不会变化。 转账操作就不是一个幂等性操作。 每次操作都会导致账号的变化。”
JDBC大臣也不由地鄙视了下JTA老头儿, 他说:“我明白了,你的意思是说那个定时运行的程序可以出错,可以向消息队列写入多次 ‘给郭芙蓉账号增加100两银子’ 这样的消息, 但是郭芙蓉那边在执行的时候, 肯定也要判断之前是否执行过了, 如果没有的话就增加, 如果执行过了就简单的抛弃这个消息即可。 ”
IO大臣向JDBC大臣投去了佩服的目光, 两人目光相遇, 碰出来了惺惺相惜的火花。
“唉, 我要是早点和JDBC/IO大臣合作多好” 两个人都在暗自吃后悔药。
IO大臣说: “是的, 郭芙蓉那边在判断是否已经执行过的时候,也需要查询之前的执行记录, 这就意味着之前执行过的也需要用一个表保存下来才行。”
“众位爱卿, 看来已经讨论得差不多了, 接下来怎么办啊?”
没人出声。
“那要不这样, 既然是民间先做出来的东西, 我们官方就不用去凑热闹了, 让他们自生自灭吧” 国王祭出了“无为而治” 的大法, 其实他实在不想再调停这几个大臣之间的争斗了。
IO大臣想发言却又忍住了,经过这一番较量, 他看清楚了各位大臣的实力, 也理解了国王的苦衷, 如果再这么争斗下去陛下估计会龙颜大怒, 算了,不争了。
傻傻的JTA大臣还不死心, 一直给JDBC大臣使眼色,只是JDBC大臣心中打定了和IO大臣一样的主意,微闭双眼开始养神了。
IO大臣心情平静地回到家中, 幕僚们围上来询问结果, 他们还做着升官发财的美梦。
IO大臣看着这些急于知道结果而显得特别饥渴的表情, 笑着摆了摆手, 一言不发地离开了。
很久以后,朝中得知民间有个叫做Dan Pritchet的人, 把这种方法总结了一下,称之为BASE模型, 从此流行开来。
你看到的只是冰山一角, 更多精彩文章,请移步《码农翻身2016文章精华》或者《码农翻身2017上半年文章精华》
有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan QQ: 3340792577
码农翻身
用故事讲述技术
- 1. Java帝国之宫廷内斗(2)
- 2. Java帝国之宫廷内斗
- 3. 宫廷男宠
- 4. Java 帝国之Java bean(下)
- 5. Java 帝国之Java bean (上)
- 6. 巴蜀2311 宫廷守卫
- 7. 马云帝国2
- 8. 变(3):宫斗
- 9. 帝国cms标签--2
- 10. Java 帝国之消息队列