Java帝國之宮廷內(nèi)斗
1.JDBC大臣
自從和東海之濱的數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國締結(jié)了合作協(xié)議以后, IO大臣就退居二線了。
他本來也想把JDBC也劃歸自己管理, 奈何國王頭腦發(fā)熱、竟然任命了新的JDBC大臣, 專門負(fù)責(zé)這一攤事兒。
JDBC大臣經(jīng)常在早朝上給國王吹風(fēng): “ 陛下, 我們的JDBC設(shè)計(jì)的非常好, 別看什么Hibernate, Mybatis 是現(xiàn)在的事實(shí)標(biāo)準(zhǔn), 他們底層都在用我們的JDBC接口。 ”
國王贊許地頻頻點(diǎn)頭,似乎忘記了這是躲在角落中IO大臣的功績(jī)。
IO大臣咬牙切齒又無可奈何。
這天JDBC又在給國王安利關(guān)系數(shù)據(jù)庫的好處: “陛下,這關(guān)系數(shù)據(jù)庫相比于簡(jiǎn)單的文件系統(tǒng)有個(gè)巨大的好處,就是支持事務(wù)。”
聽到JDBC大臣又在貶低自己負(fù)責(zé)的部門, IO大臣怒火中燒。
國王問道:“什么是事務(wù),要事務(wù)干嘛? ”
“我舉個(gè)通俗的例子你就明白了, 假設(shè)IO大臣要給我轉(zhuǎn)賬100塊錢, 他的數(shù)據(jù)庫賬戶要扣掉100塊, 我的賬戶要增加100塊, 這就涉及到兩個(gè)操作, 這兩個(gè)操作要么全部完成,要么一個(gè)都不做,只有這樣才能保證數(shù)據(jù)的一致性, 這就是一個(gè)事務(wù)。數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國有個(gè)對(duì)事務(wù)總結(jié)了4個(gè)特性: 原子性(Atomicity) ,一致性(Consistency), 隔離性(Isolation) , 持久性(Durability) , 簡(jiǎn)稱ACID, 要不我再給詳細(xì)的解釋下?”
國王連忙擺手:“不不不, 別拿這些細(xì)節(jié)煩我, 你就告訴我們的臣民怎么去使用就行了”
JDBC大臣說: “這個(gè)很簡(jiǎn)單, 默認(rèn)情況下我們的JDBC都會(huì)把對(duì)數(shù)據(jù)庫的操作認(rèn)為是一個(gè)事務(wù), 當(dāng)然臣民們也可以設(shè)置成手工的方式, 手工地提交和回滾事務(wù)。不管哪種方式,都是非常簡(jiǎn)單的 。”
國王說: “那就好, 愛卿辛苦了, 還有事嗎? 有事啟奏,無事退朝。”
2 .密謀
IO大臣回到家中,依然感覺火氣難平, 招來幕僚商談。
InputStream說: “大人, 這JDBC大臣雖然猖狂, 我們卻暫時(shí)拿他沒辦法, 現(xiàn)在都是Web時(shí)代, 哪個(gè)應(yīng)用不用數(shù)據(jù)庫啊? ”
“難道就讓他這么猖獗下去? ”
InputReader足智多謀: “我倒是有一計(jì), 只是得等待時(shí)機(jī)。 ”
“什么時(shí)機(jī)?”
“你看今天JDBC那廝提到了事務(wù), 但是這個(gè)事務(wù)只是在一個(gè)數(shù)據(jù)庫中有用啊, 如果需要跨數(shù)據(jù)庫怎么辦? 比如我的賬號(hào)存在數(shù)據(jù)庫A, 你的賬號(hào)在數(shù)據(jù)庫B, 那轉(zhuǎn)賬的時(shí)候怎么辦? 怎么實(shí)現(xiàn)什么ACID ? ”
InputStream表示不同意: “誰會(huì)這么傻, 把我們的賬號(hào)信息放到兩個(gè)數(shù)據(jù)庫當(dāng)中? ”
“這就是時(shí)候未到, 現(xiàn)在大部分的應(yīng)用數(shù)據(jù)量都不大, 放到一個(gè)數(shù)據(jù)庫中綽綽有余,等到數(shù)據(jù)量大到一定程度,勢(shì)必要拆分?jǐn)?shù)據(jù)庫,就會(huì)出現(xiàn)跨數(shù)據(jù)庫的事務(wù), 到那個(gè)時(shí)候我們的機(jī)會(huì)就來了, 我們準(zhǔn)備好解決方案, 參那廝一本, 不信扳不倒他!”
IO大臣拍板: “好! 就這么辦, 這事離不開數(shù)聯(lián)酋(數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國)的支持,我和他們還有交情, 這就派人去,許以重金, 讓他們繼續(xù)和我們合作。”
在IO大臣密謀的同時(shí), JDBC大臣的家中卻是觥籌交錯(cuò)、鶯歌燕舞。
有識(shí)之士如Connection 曾經(jīng)向JDBC大臣提醒過要和數(shù)聯(lián)酋搞好關(guān)系, 以便將來有什么不時(shí)之需。 可是處于***的JDBC大臣哪能聽得進(jìn)去?
3 .兩階段提交
InputReader 果然很有遠(yuǎn)見, 隨著時(shí)間的流逝, Web越來越發(fā)達(dá), 帝國出現(xiàn)了很多巨型網(wǎng)站, 他們的各種數(shù)據(jù)果然是沒法放到一個(gè)數(shù)據(jù)庫中了,把大的業(yè)務(wù)系統(tǒng)查分成多個(gè)數(shù)據(jù)庫勢(shì)在必行, 當(dāng)一個(gè)業(yè)務(wù)同時(shí)操作多個(gè)數(shù)據(jù)庫的時(shí)候, 沒有分布式事務(wù)是做不了的。
正在此時(shí),一個(gè)秘密奏章被送到了國王的案頭, 狀告JDBC大臣因循守舊,面對(duì)大好的形式不與時(shí)俱進(jìn),對(duì)分布式事務(wù)漠不關(guān)心,毫無作為。
國王召集朝會(huì),討論分布式事務(wù)的問題, 他向JDBC大臣率先發(fā)難: “愛卿, 你聽說過臣民們要求支持分布式事務(wù)嗎?”
JDBC大臣慌了: “這。。。 這好像是一撮刁民提的要求吧, 陛下不用理會(huì)。”
IO大臣冷笑一聲:“刁民? 我看是良民吧 ! 啟奏陛下, 據(jù)臣所知,帝國有不下百個(gè)系統(tǒng)要求支持分布式事務(wù),JDBC大臣竟然連最基本的情況都不知道, 真是毫無作為。”
IO大臣覺得穩(wěn)操勝券,直接撕破了臉。
國王心里明白了幾分, 他直接對(duì)IO大臣說: “愛卿,你說說該怎么辦?”
“陛下,當(dāng)年臣和數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國談判的時(shí)候, 和他們建立了良好的交情。 前幾天我宴請(qǐng)他們的時(shí)候,特別提及了這件事情。 Oracle 告訴臣,這很好辦, 人家別的王國正在討論實(shí)施兩階段提交的協(xié)議, 我們也可以參與進(jìn)來。”
雖然IO大臣已經(jīng)和數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國討價(jià)還價(jià)了很久, 不知道花費(fèi)了多少金錢,但還是不顯山不漏水、很隨意地說了出來。
JDBC大臣一看IO大臣進(jìn)入了自己的一畝三分地, 急忙問道: 什么是兩階段提交?
IO大臣不屑地瞥了他一眼, 從袖子中拿出早就準(zhǔn)備好的提議,雙手向國王奉上。
國王哪里看得懂,掃了一眼就賜給望眼欲穿的JDBC大臣, 只見上面赫然寫著:
兩階段提交協(xié)議
由于涉及到多個(gè)分布式的數(shù)據(jù)庫, 我們特設(shè)一個(gè)全局的事務(wù)管理器,它來負(fù)責(zé)協(xié)調(diào)各個(gè)數(shù)據(jù)庫的事務(wù)提交, 為了實(shí)現(xiàn)分布式事務(wù),特設(shè)兩個(gè)階段:
階段1: 全局的事務(wù)管理器向各個(gè)數(shù)據(jù)庫發(fā)出準(zhǔn)備消息。 各個(gè)數(shù)據(jù)庫需要在本地把一切都準(zhǔn)備好,執(zhí)行操作,鎖住資源, 記錄redo/undo 日志, 但是并不提交, 總而言之,要進(jìn)入一個(gè)時(shí)刻準(zhǔn)備提交或回滾的狀態(tài), 然后向全局事務(wù)管理器報(bào)告是否準(zhǔn)備好了。
階段2: 如果所有的數(shù)據(jù)庫都報(bào)告說準(zhǔn)備好了, 那全局的事務(wù)管理器就下命令: 提交, 這時(shí)候各個(gè)數(shù)據(jù)庫才真正提交 , 由于之前已經(jīng)萬事具備,只欠東風(fēng),只需要快速完成本地提交即可;
如果有任何一個(gè)數(shù)據(jù)庫報(bào)告說沒準(zhǔn)備好, 事務(wù)管理器就下命令: 放棄, 這時(shí)候各個(gè)數(shù)據(jù)庫要執(zhí)行回滾操作, 并且釋放各種在階段1鎖住的資源。
JDBC大臣也是行家,一看就明白了是怎么回事。階段1就是讓大家都準(zhǔn)備好,階段2就是迅速提交。
這是一個(gè)看起來很美的理想方案,但是他意識(shí)到其中有漏洞,自己的幕僚曾經(jīng)告誡過:一旦涉及到分布式,事情就不會(huì)那么簡(jiǎn)單,任何地方都有失敗的可能。
比如在第二階段,那個(gè)事務(wù)管理器要是出了問題怎么辦? 人家各個(gè)數(shù)據(jù)庫還在等著你發(fā)命令呢? 你遲遲不發(fā)命令,大家都阻塞在那里,不知所措,到底是提交呢?還是不提交呢, 我這里還鎖著資源呢, 遲遲不能釋放,多耽誤事啊 !
還是第二階段,事務(wù)管理器發(fā)出的提交命令由于網(wǎng)絡(luò)問題,數(shù)據(jù)庫1收到了,數(shù)據(jù)庫2沒收到,這兩個(gè)數(shù)據(jù)庫就處于不一致狀態(tài)了, 該怎么處理?
JDBC大臣決心給IO大臣挖個(gè)坑:讓你逞能 ! 讓你給老子穿小鞋!
他說:“ 陛下,IO大臣不愧為設(shè)計(jì)過JDBC協(xié)議的股肱之臣, 臣才學(xué)疏淺,深為拜服,特奏請(qǐng)陛下恩準(zhǔn)IO大臣再次出山和數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國設(shè)計(jì)出新協(xié)議, 來支持分布式事務(wù)。”
國王準(zhǔn)奏。
4 .JTA
IO大臣滿心狐疑, 不知道JDBC老頭兒在給自己下什么藥,回到府中和大家商量。
InputReader 眼看自己多年前的計(jì)策就要成功,頗為興奮: “管它呢, 只要咱們把這個(gè)分布式事務(wù)的協(xié)議給制定好,JDBC老兒就得下臺(tái)了。”
“對(duì),到時(shí)候我們就掌管文件, 網(wǎng)絡(luò),數(shù)據(jù)庫,Java 帝國就是我們IO獨(dú)大了” InputStream 開始暢想美好的未來,到時(shí)候自己估計(jì)至少從5品升為4品。
IO大臣馬上安排和數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國的談判,由于之前良好的交情。 這一次協(xié)議很容易就達(dá)成了, IO大臣給他起了一個(gè)很響亮的名字: Java Transaction API (簡(jiǎn)稱JTA)。
這個(gè)JTA規(guī)范用起來也比較簡(jiǎn)單, 只要獲得一個(gè)UserTransaction 就可以操作了,帝國的臣民們根本不用關(guān)系底層的協(xié)議細(xì)節(jié):
經(jīng)過國王的批準(zhǔn), JTA正式推廣。
可是令I(lǐng)O大臣萬萬沒有想到的是, 國王在JTA發(fā)布的前夕, 親切地召見了自己和另外一個(gè)不知名的官員, 國王關(guān)心地說:“愛卿,朕知道你很忙,掌管著網(wǎng)絡(luò)和文件操作,為了給你減輕負(fù)擔(dān),朕決定任命一個(gè)新的JTA大臣來協(xié)助你!”
IO大臣如同五雷轟頂,自己辛辛苦苦的工作完全被無視, 這到底是為什么?
他失魂落魄地回到府中, 好幾天茶飯不思。
還是InputReader 出來安慰了他: “這是陛下的帝王之術(shù), 害怕我們一家坐大, 平衡了一下朝中力量。大人可以放寬心, 你看JDBC大臣也受到了打壓,風(fēng)光不再了。”
5. 塞翁失馬,焉知非福
JTA并沒有取得像JDBC那樣的廣泛應(yīng)用, JDBC大臣挖的那個(gè)坑現(xiàn)在終于露出了猙獰的面目。
只不過這個(gè)坑并沒有讓IO大臣掉進(jìn)去, 新任的JTA大臣背了黑鍋。
臣民的抗議聲越來越多: 分布式事務(wù)伴隨著大量節(jié)點(diǎn)的通信交換, 協(xié)調(diào)者要確定其他節(jié)點(diǎn)是否完成, 加上網(wǎng)絡(luò)帶來的超時(shí),導(dǎo)致JTA性能低下, 在高并發(fā)和高性能的場(chǎng)景下舉步維艱。
拜IO大臣的工作所賜, 現(xiàn)在數(shù)據(jù)庫聯(lián)合酋長(zhǎng)國的各個(gè)部落都支持兩階段提交,很多應(yīng)用服務(wù)器Websphere , Weblogic 等都支持JTA, 可是使用者確是***, 都快成擺設(shè)了。
JTA大臣每次上朝都戰(zhàn)戰(zhàn)兢兢, 他是個(gè)平庸之輩,雖然四處救火,但是無力解決根本的問題。
現(xiàn)在那些高并發(fā)的系統(tǒng)反而極力避免兩階段提交, 他們繞開JTA大臣, 直接找到了IO大臣訴苦:“大人,你帶領(lǐng)著制定了JTA, 但是這個(gè)標(biāo)準(zhǔn)太理想化,完全不符合實(shí)情啊! ”
IO大臣說: “不會(huì)吧,這不是你們要求的嗎, 用戶A和B的賬號(hào)分別在兩個(gè)數(shù)據(jù)庫, 當(dāng)A給B轉(zhuǎn)賬100塊的時(shí)候, 肯定得保證A扣掉100, 然后B增加100啊。”
“這就是官府的想法, 總是想著讓兩個(gè)數(shù)據(jù)庫保證實(shí)時(shí)的一致性(強(qiáng)一致性), 為了達(dá)到這個(gè)目標(biāo),JTA付出的代價(jià)太高了。 我們現(xiàn)在不想這么干了。 我們可以忍受一段時(shí)間的不一致,只有最終一致就行。 比方說A給B轉(zhuǎn)100元, A 中的錢已經(jīng)扣除, 但是B中不會(huì)實(shí)時(shí)地增加,過段時(shí)間能保證增加就行了”
“最終一致性? 有點(diǎn)意思!” ,想到Java 帝國的官方標(biāo)準(zhǔn)總是被臣民們所建立的事實(shí)標(biāo)準(zhǔn)所打敗,敏銳的IO大臣立刻看到了背后的機(jī)遇, 他決定這一次要聯(lián)合民間力量,再次反攻, 一舉搞掉JDBC大臣和JTA大臣。
想到這里, IO大臣得意地笑了......
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過作者微信公眾號(hào)coderising獲取授權(quán)】