日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分布式事务的问题

發布時間:2024/4/13 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分布式事务的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引入了分布式事務的問題

1、什么是分布式事務 分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位于不同的分布式系統的不同節點之上。以上是百度百科的解釋,簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分布在不同的服務器上,且屬于不同的應用,分布式事務需要保證這些小操作要么全部成功,要么全部失敗。本質上來說,分布式事務就是為了保證不同數據庫的數據一致性。2、分布式事務的產生的原因 2.1、數據庫分庫分表 當數據庫單表一年產生的數據超過1000W,那么就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以后有空詳細說,簡單的說就是原來的一個數據庫變成了多個數據庫。這時候,如果一個操作既訪問01庫,又訪問02庫,而且要保證數據的一致性,那么就要用到分布式事務。2.2、應用SOA化 所謂的SOA化,就是業務的服務化。比如原來單機支撐了整個電商網站,現在對整個網站進行拆解,分離出了訂單中心、用戶中心、庫存中心。對于訂單中心,有專門的數據庫存儲訂單信息,用戶中心也有專門的數據庫存儲用戶信息,庫存中心也會有專門的數據庫存儲庫存信息。這時候如果要同時對訂單和庫存進行操作,那么就會涉及到訂單數據庫和庫存數據庫,為了保證數據一致性,就需要用到分布式事務。以上兩種情況表象不同,但是本質相同,都是因為要操作的數據庫變多了!3、事務的ACID特性 3.1、原子性(A) 所謂的原子性就是說,在整個事務中的所有操作,要么全部完成,要么全部不做,沒有中間狀態。對于事務在執行中發生錯誤,所有的操作都會被回滾,整個事務就像從沒被執行過一樣。3.2、一致性(C) 事務的執行必須保證系統的一致性,就拿轉賬為例,A有500元,B有300元,如果在一個事務里A成功轉給B50元,那么不管并發多少,不管發生什么,只要事務執行成功了,那么最后A賬戶一定是450元,B賬戶一定是350元。3.3、隔離性(I) 所謂的隔離性就是說,事務與事務之間不會互相影響,一個事務的中間狀態不會被其他事務感知。3.4、持久性(D) 所謂的持久性,就是說一單事務完成了,那么事務對數據所做的變更就完全保存在了數據庫中,即使發生停電,系統宕機也是如此。4、分布式事務的應用場景 4.1、支付 最經典的場景就是支付了,一筆支付,是對買家賬戶進行扣款,同時對賣家賬戶進行加錢,這些操作必須在一個事務里執行,要么全部成功,要么全部失敗。而對于買家賬戶屬于買家中心,對應的是買家數據庫,而賣家賬戶屬于賣家中心,對應的是賣家數據庫,對不同數據庫的操作必然需要引入分布式事務。4.2、在線下單 買家在電商平臺下單,往往會涉及到兩個動作,一個是扣庫存,第二個是更新訂單狀態,庫存和訂單一般屬于不同的數據庫,需要使用分布式事務保證數據一致性。5、常見的分布式事務解決方案 5.1、基于XA協議的兩階段提交 XA是一個分布式事務協議,由Tuxedo提出。XA中大致分為兩部分:事務管理器和本地資源管理器。其中本地資源管理器往往由數據庫實現,比如Oracle、DB2這些商業數據庫都實現了XA接口,而事務管理器作為全局的調度者,負責各個本地資源的提交和回滾。XA實現分布式事務的原理如下:總的來說,XA協議比較簡單,而且一旦商業數據庫實現了XA協議,使用分布式事務的成本也比較低。但是,XA也有致命的缺點,那就是性能不理想,特別是在交易下單鏈路,往往并發量很高,XA無法滿足高并發場景。XA目前在商業數據庫支持的比較理想,在mysql數據庫中支持的不太理想,mysql的XA實現,沒有記錄prepare階段日志,主備切換回導致主庫與備庫數據不一致。許多nosql也沒有支持XA,這讓XA的應用場景變得非常狹隘。5.2、消息事務+最終一致性 所謂的消息事務就是基于消息中間件的兩階段提交,本質上是對消息中間件的一種特殊利用,它是將本地事務和發消息放在了一個分布式事務里,保證要么本地操作成功成功并且對外發消息成功,要么兩者都失敗,開源的RocketMQ就支持這一特性,具體原理如下:1、A系統向消息中間件發送一條預備消息 2、消息中間件保存預備消息并返回成功 3、A執行本地事務 4、A發送提交消息給消息中間件通過以上4步完成了一個消息事務。對于以上的4個步驟,每個步驟都可能產生錯誤,下面一一分析:步驟一出錯,則整個事務失敗,不會執行A的本地操作 步驟二出錯,則整個事務失敗,不會執行A的本地操作 步驟三出錯,這時候需要回滾預備消息,怎么回滾?答案是A系統實現一個消息中間件的回調接口,消息中間件會去不斷執行回調接口,檢查A事務執行是否執行成功,如果失敗則回滾預備消息 步驟四出錯,這時候A的本地事務是成功的,那么消息中間件要回滾A嗎?答案是不需要,其實通過回調接口,消息中間件能夠檢查到A執行成功了,這時候其實不需要A發提交消息了,消息中間件可以自己對消息進行提交,從而完成整個消息事務 基于消息中間件的兩階段提交往往用在高并發場景下,將一個分布式事務拆成一個消息事務(A系統的本地操作+發消息)+B系統的本地操作,其中B系統的操作由消息驅動,只要消息事務成功,那么A操作一定成功,消息也一定發出來了,這時候B會收到消息去執行本地操作,如果本地操作失敗,消息會重投,直到B操作成功,這樣就變相地實現了A與B的分布式事務。原理如下:雖然上面的方案能夠完成A和B的操作,但是A和B并不是嚴格一致的,而是最終一致的,我們在這里犧牲了一致性,換來了性能的大幅度提升。當然,這種玩法也是有風險的,如果B一直執行不成功,那么一致性會被破壞,具體要不要玩,還是得看業務能夠承擔多少風險。5.3、TCC編程模式 所謂的TCC編程模式,也是兩階段提交的一個變種。TCC提供了一個編程框架,將整個業務邏輯分為三塊:Try、Confirm和Cancel三個操作。以在線下單為例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,如果更新訂單失敗,則進入Cancel階段,會去恢復庫存。總之,TCC就是通過代碼人為實現了兩階段提交,不同的業務場景所寫的代碼都不一樣,復雜度也不一樣,因此,這種模式并不能很好地被復用。6、總結 分布式事務,本質上是對多個數據庫的事務進行統一控制,按照控制力度可以分為:不控制、部分控制和完全控制。不控制就是不引入分布式事務,部分控制就是各種變種的兩階段提交,包括上面提到的消息事務+最終一致性、TCC模式,而完全控制就是完全實現兩階段提交。部分控制的好處是并發量和性能很好,缺點是數據一致性減弱了,完全控制則是犧牲了性能,保障了一致性,具體用哪種方式,最終還是取決于業務場景。作為技術人員,一定不能忘了技術是為業務服務的,不要為了技術而技術,針對不同業務進行技術選型也是一種很重要的能力 --------------------------------------------------------------------------- 昨晚某技術群里大家熱火的在討論分布式事務的問題,想起了自己前幾年由于技術太渣也犯過很多相關錯誤,現結合自己之前一次BUG案例由感而寫此文,希望對看到文章的同學們多少有些幫助(如果發現錯誤之處,歡迎交流)。一個注冊業務,用戶注冊成功后,后臺調用另外一個服務同步完成開通資金賬戶,后來加了一個需求同時還要把注冊用戶數據同步到另一個業務系統中。真實情況邏輯更復雜,現在簡化方便描述后相關偽代碼如下:@Transactionalpublic void register(){//保存用戶saveUser();//初始化賬戶initAccount();//推送用戶信息pushUser();} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15后面兩個方法可以理解成是其他業務系統的遠程服務;代碼上線后一段時間內倒也平穩沒出什么問題(用戶數少),然而是bug早晚會復現的,最終在一個周末問題觸發了,接到領導通知,網站不能注冊,趕緊連上服務器看日志,發現日志中大量超時及mysql死鎖異常,然后瞬間明白了問題原因,畢竟鍋是自己引起的。pushUser()里面是一個請求其他業務系統的HTTP接口,此處當時沒加connectTimeout超時限制,那天此業務系統接口異常,請求了60多秒還沒響應,這個整體方法上還有一個大事務,接著就造成了大量死鎖,再之后網站就不能注冊。上面的這個示例可以說是分布式事務中常見的一類問題;一個業務的完成,要依賴于其他項目的多個遠程服務;但上面的那種寫法明顯問題很大,極易引發各種BUG,至少存在以下問題:事務范圍過大 注冊業務嚴重耦合其他業務系統接口 數據不一致性問題現在回想起來,當時果然是不知者無畏,啥代碼都敢寫。現在根據目前的認知水平針對上面問題,重新提供一個優化思路,使用MQ來解耦下面兩個遠程服務。用戶信息保存成功后,插一條記錄到user_task_record表(user_id,account_flag,push_flag,create_time,update_time等字段,兩個狀態字段初始值默認為0);這兩個操作在同一個事務內; 扔一條消息到MQ中; 消費者接受到廣播消息后分別再處理initAccount、pushUser邏輯;相應消費者接收到消息處理成功后,修改user_task_record表對應狀態字段為1; 失敗重試機制,因為接口可能會有調用失敗的情況,新增一個5分鐘一次的定時任務,掃user_task_record表狀態為0的記錄,扔消息到MQ中; 如果業務重要還可以加入監控預警,設定一個閥值,如果發現user_task_record表中create_time大于閥值并且狀態一直是0的記錄,可以給相關人員短信,郵件預警。注意:由于有失敗重試機制,所以業務系統的相關接口必須是冪等的(冪等很重要),即我可以調用多次,不會產生重復數據。在本例中我們的消費者接受到消息后,可以先從user_task表中查取下對應狀態是否為1,如果是1,說明業務邏輯已經執行成功,只用確認下消息扔給下一個消費者處理;不等于1的就執行相應業務邏輯。相關偽代碼如下:public void register(){//保存用戶@TransactionalsaveUser();//生成一條消息producer.send(message);} 1 2 3 4 5 6 7 8 9 10 簡易流程圖如下: 這里寫圖片描述安利下mq,mq在實際開發中能幫我們很多忙: 在傳統的事務處理中,多個系統之間的交互耦合到一個事務中,響應時間長,影響系統可用性。引入分布式事務消息,業務系統和消息隊列之間,組成一個事務處理,能保證分布式系統之間數據的最終一致;下游業務系統(訂單交易、購物車、積分、其他)相互隔離,并行處理。常見使用場景:列表內容 列表內容 異步解耦 削峰填谷 異步通知 分布式事務處理 …… 最后總結:我們把2個同步遠程調用方法改成異步了 事務范圍變小了 引入MQ,把業務解耦了,保證了分布式系統事務的最終一致性 項目更高可用了,不會因為其他業務系統引起項目宕機不可用 -------------------------------------------------------------------------------- 問題的起源在電商等業務中,系統一般由多個獨立的服務組成,如何解決分布式調用時候數據的一致性??具體業務場景如下,比如一個業務操作,如果同時調用服務 A、B、C,需要滿足要么同時成功;要么同時失敗。A、B、C 可能是多個不同部門開發、部署在不同服務器上的遠程服務。在分布式系統來說,如果不想犧牲一致性,CAP 理論告訴我們只能放棄可用性,這顯然不能接受。為了便于討論問題,先簡單介紹下數據一致性的基礎理論。強一致當更新操作完成之后,任何多個后續進程或者線程的訪問都會返回最新的更新過的值。這種是對用戶最友好的,就是用戶上一次寫什么,下一次就保證能讀到什么。根據 CAP 理論,這種實現需要犧牲可用性。弱一致性系統并不保證續進程或者線程的訪問都會返回最新的更新過的值。系統在數據寫入成功之后,不承諾立即可以讀到最新寫入的值,也不會具體的承諾多久之后可以讀到。最終一致性弱一致性的特定形式。系統保證在沒有后續更新的前提下,系統最終返回上一次更新操作的值。在沒有故障發生的前提下,不一致窗口的時間主要受通信延遲,系統負載和復制副本的個數影響。DNS 是一個典型的最終一致性系統。在工程實踐上,為了保障系統的可用性,互聯網系統大多將強一致性需求轉換成最終一致性的需求,并通過系統執行冪等性的保證,保證數據的最終一致性。但在電商等場景中,對于數據一致性的解決方法和常見的互聯網系統(如 MySQL 主從同步)又有一定區別,群友的討論分成以下 6 種解決方案。1. 規避分布式事務——業務整合業務整合方案主要采用將接口整合到本地執行的方法。拿問題場景來說,則可以將服務 A、B、C 整合為一個服務 D 給業務,這個服務 D 再通過轉換為本地事務的方式,比如服務 D 包含本地服務和服務 E,而服務 E 是本地服務 A ~ C 的整合。優點:解決(規避)了分布式事務。缺點:顯而易見,把本來規劃拆分好的業務,又耦合到了一起,業務職責不清晰,不利于維護。由于這個方法存在明顯缺點,通常不建議使用。2. 經典方案 - eBay 模式此方案的核心是將需要分布式處理的任務通過消息日志的方式來異步執行。消息日志可以存儲到本地文本、數據庫或消息隊列,再通過業務規則自動或人工發起重試。人工重試更多的是應用于支付場景,通過對賬系統對事后問題的處理。消息日志方案的核心是保證服務接口的冪等性。考慮到網絡通訊失敗、數據丟包等原因,如果接口不能保證冪等性,數據的唯一性將很難保證。eBay 方式的主要思路如下。Base:一種 Acid 的替代方案此方案是 eBay 的架構師 Dan Pritchett 在 2008 年發表給 ACM 的文章,是一篇解釋 BASE 原則,或者說最終一致性的經典文章。文中討論了 BASE 與 ACID 原則在保證數據一致性的基本差異。如果 ACID 為分區的數據庫提供一致性的選擇,那么如何實現可用性呢?答案是BASE (basically available, soft state, eventually consistent)BASE 的可用性是通過支持局部故障而不是系統全局故障來實現的。下面是一個簡單的例子:如果將用戶分區在 5 個數據庫服務器上,BASE 設計鼓勵類似的處理方式,一個用戶數據庫的故障只影響這臺特定主機那 20% 的用戶。這里不涉及任何魔法,不過它確實可以帶來更高的可感知的系統可用性。文章中描述了一個最常見的場景,如果產生了一筆交易,需要在交易表增加記錄,同時還要修改用戶表的金額。這兩個表屬于不同的遠程服務,所以就涉及到分布式事務一致性的問題。文中提出了一個經典的解決方法,將主要修改操作以及更新用戶表的消息放在一個本地事務來完成。同時為了避免重復消費用戶表消息帶來的問題,達到多次重試的冪等性,增加一個更新記錄表 updates_applied?來記錄已經處理過的消息。系統的執行偽代碼如下(點擊可全屏縮放圖片)基于以上方法,在第一階段,通過本地的數據庫的事務保障,增加了 transaction 表及消息隊列 。在第二階段,分別讀出消息隊列(但不刪除),通過判斷更新記錄表 updates_applied 來檢測相關記錄是否被執行,未被執行的記錄會修改 user 表,然后增加一條操作記錄到?updates_applied,事務執行成功之后再刪除隊列。通過以上方法,達到了分布式系統的最終一致性。進一步了解 eBay 的方案可以參考文末鏈接。3. 去哪兒網分布式事務方案隨著業務規模不斷地擴大,電商網站一般都要面臨拆分之路。就是將原來一個單體應用拆分成多個不同職責的子系統。比如以前可能將面向用戶、客戶和運營的功能都放在一個系統里,現在拆分為訂單中心、代理商管理、運營系統、報價中心、庫存管理等多個子系統。拆分首先要面臨的是什么呢?最開始的單體應用所有功能都在一起,存儲也在一起。比如運營要取消某個訂單,那直接去更新訂單表狀態,然后更新庫存表就 ok 了。因為是單體應用,庫在一起,這些都可以在一個事務里,由關系數據庫來保證一致性。但拆分之后就不同了,不同的子系統都有自己的存儲。比如訂單中心就只管理自己的訂單庫,而庫存管理也有自己的庫。那么運營系統取消訂單的時候就是通過接口調用等方式來調用訂單中心和庫存管理的服務了,而不是直接去操作庫。這就涉及一個『分布式事務』的問題。?分布式事務有兩種解決方式1. 優先使用異步消息。上文已經說過,使用異步消息 Consumer 端需要實現冪等。冪等有兩種方式,一種方式是業務邏輯保證冪等。比如接到支付成功的消息訂單狀態變成支付完成,如果當前狀態是支付完成,則再收到一個支付成功的消息則說明消息重復了,直接作為消息成功處理。另外一種方式如果業務邏輯無法保證冪等,則要增加一個去重表或者類似的實現。對于 producer 端在業務數據庫的同實例上放一個消息庫,發消息和業務操作在同一個本地事務里。發消息的時候消息并不立即發出,而是向消息庫插入一條消息記錄,然后在事務提交的時候再異步將消息發出,發送消息如果成功則將消息庫里的消息刪除,如果遇到消息隊列服務異常或網絡問題,消息沒有成功發出那么消息就留在這里了,會有另外一個服務不斷地將這些消息掃出重新發送。2. 有的業務不適合異步消息的方式,事務的各個參與方都需要同步的得到結果。這種情況的實現方式其實和上面類似,每個參與方的本地業務庫的同實例上面放一個事務記錄庫。比如 A 同步調用 B,C。A 本地事務成功的時候更新本地事務記錄狀態,B 和 C 同樣。如果有一次 A 調用 B 失敗了,這個失敗可能是 B 真的失敗了,也可能是調用超時,實際 B 成功。則由一個中心服務對比三方的事務記錄表,做一個最終決定。假設現在三方的事務記錄是 A 成功,B 失敗,C 成功。那么最終決定有兩種方式,根據具體場景:重試 B,直到 B 成功,事務記錄表里記錄了各項調用參數等信息;執行 A 和 B 的補償操作(一種可行的補償方式是回滾)。對 b 場景做一個特殊說明:比如 B 是扣庫存服務,在第一次調用的時候因為某種原因失敗了,但是重試的時候庫存已經變為 0,無法重試成功,這個時候只有回滾 A 和 C 了。那么可能有人覺得在業務庫的同實例里放消息庫或事務記錄庫,會對業務侵入,業務還要關心這個庫,是否一個合理的設計?實際上可以依靠運維的手段來簡化開發的侵入,我們的方法是讓 DBA 在公司所有 MySQL 實例上預初始化這個庫,通過框架層(消息的客戶端或事務 RPC 框架)透明的在背后操作這個庫,業務開發人員只需要關心自己的業務邏輯,不需要直接訪問這個庫。總結起來,其實兩種方式的根本原理是類似的,也就是將分布式事務轉換為多個本地事務,然后依靠重試等方式達到最終一致性。4. 蘑菇街交易創建過程中的分布式一致性方案交易創建的一般性流程我們把交易創建流程抽象出一系列可擴展的功能點,每個功能點都可以有多個實現(具體的實現之間有組合/互斥關系)。把各個功能點按照一定流程串起來,就完成了交易創建的過程。?面臨的問題每個功能點的實現都可能會依賴外部服務。那么如何保證各個服務之間的數據是一致的呢?比如鎖定優惠券服務調用超時了,不能確定到底有沒有鎖券成功,該如何處理?再比如鎖券成功了,但是扣減庫存失敗了,該如何處理?方案選型服務依賴過多,會帶來管理復雜性增加和穩定性風險增大的問題。試想如果我們強依賴 10 個服務,9 個都執行成功了,最后一個執行失敗了,那么是不是前面 9 個都要回滾掉?這個成本還是非常高的。所以在拆分大的流程為多個小的本地事務的前提下,對于非實時、非強一致性的關聯業務寫入,在本地事務執行成功后,我們選擇發消息通知、關聯事務異步化執行的方案。消息通知往往不能保證 100% 成功;且消息通知后,接收方業務是否能執行成功還是未知數。前者問題可以通過重試解決;后者可以選用事務消息來保證。但是事務消息框架本身會給業務代碼帶來侵入性和復雜性,所以我們選擇基于 DB 事件變化通知到 MQ 的方式做系統間解耦,通過訂閱方消費 MQ 消息時的 ACK 機制,保證消息一定消費成功,達到最終一致性。由于消息可能會被重發,消息訂閱方業務邏輯處理要做好冪等保證。所以目前只剩下需要實時同步做、有強一致性要求的業務場景了。在交易創建過程中,鎖券和扣減庫存是這樣的兩個典型場景。要保證多個系統間數據一致,乍一看,必須要引入分布式事務框架才能解決。但引入非常重的類似二階段提交分布式事務框架會帶來復雜性的急劇上升;在電商領域,絕對的強一致是過于理想化的,我們可以選擇準實時的最終一致性。我們在交易創建流程中,首先創建一個不可見訂單,然后在同步調用鎖券和扣減庫存時,針對調用異常(失敗或者超時),發出廢單消息到MQ。如果消息發送失敗,本地會做時間階梯式的異步重試;優惠券系統和庫存系統收到消息后,會進行判斷是否需要做業務回滾,這樣就準實時地保證了多個本地事務的最終一致性。5. 支付寶及螞蟻金融云的分布式服務?DTS?方案業界常用的還有支付寶的一種 xts 方案,由支付寶在 2PC 的基礎上改進而來。主要思路如下,大部分信息引用自官方網站。分布式事務服務簡介分布式事務服務 (Distributed Transaction Service, DTS) 是一個分布式事務框架,用來保障在大規模分布式環境下事務的最終一致性。DTS 從架構上分為 xts-client 和 xts-server 兩部分,前者是一個嵌入客戶端應用的 JAR 包,主要負責事務數據的寫入和處理;后者是一個獨立的系統,主要負責異常事務的恢復。核心特性傳統關系型數據庫的事務模型必須遵守 ACID 原則。在單數據庫模式下,ACID 模型能有效保障數據的完整性,但是在大規模分布式環境下,一個業務往往會跨越多個數據庫,如何保證這多個數據庫之間的數據一致性,需要其他行之有效的策略。在 JavaEE 規范中使用 2PC (2 Phase Commit, 兩階段提交) 來處理跨 DB 環境下的事務問題,但是 2PC 是反可伸縮模式,也就是說,在事務處理過程中,參與者需要一直持有資源直到整個分布式事務結束。這樣,當業務規模達到千萬級以上時,2PC 的局限性就越來越明顯,系統可伸縮性會變得很差。基于此,我們采用 BASE 的思想實現了一套類似 2PC 的分布式事務方案,這就是 DTS。DTS在充分保障分布式環境下高可用性、高可靠性的同時兼顧數據一致性的要求,其最大的特點是保證數據最終一致 (Eventually consistent)。簡單的說,DTS 框架有如下特性:最終一致:事務處理過程中,會有短暫不一致的情況,但通過恢復系統,可以讓事務的數據達到最終一致的目標。協議簡單:DTS 定義了類似 2PC 的標準兩階段接口,業務系統只需要實現對應的接口就可以使用 DTS 的事務功能。與 RPC 服務協議無關:在 SOA 架構下,一個或多個 DB 操作往往被包裝成一個一個的 Service,Service 與 Service 之間通過 RPC 協議通信。DTS 框架構建在 SOA 架構上,與底層協議無關。與底層事務實現無關: DTS 是一個抽象的基于 Service 層的概念,與底層事務實現無關,也就是說在 DTS 的范圍內,無論是關系型數據庫 MySQL,Oracle,還是 KV 存儲 MemCache,或者列存數據庫 HBase,只要將對其的操作包裝成 DTS 的參與者,就可以接入到 DTS 事務范圍內。以下是分布式事務框架的流程圖?實現一個完整的業務活動由一個主業務服務與若干從業務服務組成。主業務服務負責發起并完成整個業務活動。從業務服務提供 TCC 型業務操作。業務活動管理器控制業務活動的一致性,它登記業務活動中的操作,并在活動提交時確認所有的兩階段事務的 confirm 操作,在業務活動取消時調用所有兩階段事務的 cancel 操作。”與 2PC 協議比較沒有單獨的 Prepare 階段,降低協議成本系統故障容忍度高,恢復簡單6. 農信網數據一致性方案1. 電商業務公司的支付部門,通過接入其它第三方支付系統來提供支付服務給業務部門,支付服務是一個基于 Dubbo 的 RPC 服務。對于業務部門來說,電商部門的訂單支付,需要調用支付平臺的支付接口來處理訂單;同時需要調用積分中心的接口,按照業務規則,給用戶增加積分。從業務規則上需要同時保證業務數據的實時性和一致性,也就是支付成功必須加積分。我們采用的方式是同步調用,首先處理本地事務業務。考慮到積分業務比較單一且業務影響低于支付,由積分平臺提供增加與回撤接口。具體的流程是先調用積分平臺增加用戶積分,再調用支付平臺進行支付處理,如果處理失敗,catch 方法調用積分平臺的回撤方法,將本次處理的積分訂單回撤。(點擊圖片可以全屏縮放)2. 用戶信息變更公司的用戶信息,統一由用戶中心維護,而用戶信息的變更需要同步給各業務子系統,業務子系統再根據變更內容,處理各自業務。用戶中心作為 MQ 的 producer,添加通知給 MQ。APP Server 訂閱該消息,同步本地數據信息,再處理相關業務比如 APP 退出下線等。我們采用異步消息通知機制,目前主要使用 ActiveMQ,基于 Virtual Topic 的訂閱方式,保證單個業務集群訂閱的單次消費。總結分布式服務對衍生的配套系統要求比較多,特別是我們基于消息、日志的最終一致性方案,需要考慮消息的積壓、消費情況、監控、報警等。參考資料Base: An Acid Alternative (eBay 方案)In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability.英文版 :?http://queue.acm.org/detail.cfm?id=1394128?中文版:?http://article.yeeyan.org/view/167444/125572分布式事務服務 (DTS)??https://www.cloud.alipay.com/docs/middleware/xts/index.html --------------------- 事務在數據庫系統中,一個事務是指:由一系列數據庫操作組成的一個完整的邏輯過程。例如銀行轉帳,從原賬戶扣除金額,以及向目標賬戶添加金額,這兩個數據庫操作的總和,構成一個完整的邏輯過程,不可拆分。這個過程被稱為一個事務,具有ACID特性。ACID:是指在數據庫管理系統(DBMS)中,事務(transaction)所具有的四個特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。 l ?原子性:一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。 l ?一致性:在事務開始之前和事務結束以后,數據庫的完整性限制沒有被破壞。 l ?隔離性:當兩個或者多個事務并發訪問(此處訪問指查詢和修改的操作)數據庫的同一數據時所表現出的相互關系。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。 l ?持久性:在事務完成以后,該事務對數據庫所作的更改便持久地保存在數據庫之中,并且是完全的。分布式理論當我們的單個數據庫的性能產生瓶頸的時候,我們可能會對數據庫進行分區,這里所說的分區指的是物理分區,分區之后可能不同的庫就處于不同的服務器上了,這個時候單個數據庫的ACID已經不能適應這種情況了,而在這種ACID的集群環境下,再想保證集群的ACID幾乎是很難達到,或者即使能達到那么效率和性能會大幅下降,最為關鍵的是再很難擴展新的分區了,這個時候如果再追求集群的ACID會導致我們的系統變得很差,這時我們就需要引入一個新的理論原則來適應這種集群的情況,就是 CAP 原則或者叫CAP定理,那么CAP定理指的是什么呢?CAP:CAP原理指的是,一致性(Consistency)可用性(Availability)分區容忍性(Partitiontolerance)這三個要素最多只能同時實現兩點,不可能三者兼顧。這是Brewer教授于2000年提出的,后人也論證了CAP理論的正確性。l ?一致性(Consistency) :對于分布式的存儲系統,一個數據往往會存在多份。簡單的說,一致性會讓客戶對數據的修改操作(增/刪/改),要么在所有的數據副本(replica)全部成功,要么全部失敗。即,修改操作對于一份數據的所有副本(整個系統)而言,是原子(atomic)的操作。如果一個存儲系統可以保證一致性,那么則客戶讀寫的數據完全可以保證是最新的。不會發生兩個不同的客戶端在不同的存儲節點中讀取到不同副本的情況。 l ?可用性(Availability) :可用性很簡單,顧名思義,就是指在客戶端想要訪問數據的時候,可以得到響應。但是注意,系統可用(Available)并不代表存儲系統所有節點提供的數據是一致的。這種情況,我們仍然說系統是可用的。往往我們會對不同的應用設定一個最長響應時間,超過這個響應時間的服務我們仍然稱之為不可用的。 l ?分區容忍性(Partition Tolerance) :如果你的存儲系統只運行在一個節點上,要么系統整個崩潰,要么全部運行良好。比如,兩個存儲節點之間聯通的網絡斷開(無論長時間或者短暫的),就形成了分區。一般來講,為了提高服務質量,同一份數據放置在不同城市非常正常的。因此節點之間形成分區也很正常。CAP定理總結CAP定理是由加州大學伯克利分校Eric Brewer教授提出來的,他指出WEB服務無法同時滿足一下3個屬性:·????????一致性(Consistency) :客戶端知道一系列的操作都會同時發生(生效)·????????可用性(Availability) :每個操作都必須以可預期的響應結束·????????分區容錯性(Partitiontolerance) :即使出現單個組件無法可用,操作依然可以完成具體地講在分布式系統中,在任何數據庫設計中,一個Web應用至多只能同時支持上面的兩個屬性。顯然,任何橫向擴展策略都要依賴于數據分區。因此,設計人員必須在一致性與可用性之間做出選擇。這個定理在迄今為止的分布式系統中都是適用的!?為什么這么說呢?這個時候有同學可能會把數據庫的2PC(兩階段提交)搬出來說話了。OK,我們就來看一下數據庫的兩階段提交。對數據庫分布式事務有了解的同學一定知道數據庫支持的2PC,又叫做 XA Transactions。MySQL從5.5版本開始支持,SQL Server 2005 開始支持,Oracle 7 開始支持。其中,XA 是一個兩階段提交協議,該協議分為以下兩個階段:·????????第一階段:事務協調器要求每個涉及到事務的數據庫預提交(precommit)此操作,并反映是否可以提交.·????????第二階段:事務協調器要求每個數據庫提交數據。其中,如果有任何一個數據庫否決此次提交,那么所有數據庫都會被要求回滾它們在此事務中的那部分信息。這樣做的缺陷是什么呢?咋看之下我們可以在數據庫分區之間獲得一致性。如果CAP 定理是對的,那么它一定會影響到可用性。(該方案犧牲了一定的可用性換取一致性)如果說系統的可用性代表的是執行某項操作相關所有組件的可用性的和。那么在兩階段提交的過程中,可用性就代表了涉及到的每一個數據庫中可用性的和。我們假設兩階段提交的過程中每一個數據庫都具有99.9%的可用性,那么如果兩階段提交涉及到兩個數據庫,這個結果就是99.8%。根據系統可用性計算公式,假設每個月43200分鐘,99.9%的可用性就是43157分鐘, 99.8%的可用性就是43114分鐘,相當于每個月的宕機時間增加了43分鐘。以上,可以驗證出來,CAP定理從理論上來講是正確的,CAP我們先看到這里,等會再接著說。BASE:在分布式系統中,我們往往追求的是可用性,它的重要性比一致性要高,那么如何實現高可用性呢?前人已經給我們提出來了另外一個理論,就是BASE理論,它是用來對CAP定理進行進一步擴充的。BASE理論指的是:·????????Basically Available(基本可用)·????????Soft state(軟狀態)·????????Eventually consistent(最終一致性)BASE全稱是BasicallyAvailable(基本可用), Soft-state(軟狀態/柔性事務), Eventually Consistent(最終一致性)。BASE模型在理論邏輯上是相反于ACID(原子性Atomicity、一致性Consistency、隔離性Isolation、持久性Durability)模型的概念,它犧牲高一致性,獲得可用性和分區容忍性。|?基本可用(Basically Available)。基本可用是指分布式系統在出現故障的時候,允許損失部分可用性,即保證核心可用。電商大促時,為了應對訪問量激增,部分用戶可能會被引導到降級頁面,服務層也可能只提供降級服務。這就是損失部分可用性的體現。|?軟狀態(Soft-state)。軟狀態是指允許系統存在中間狀態,而該中間狀態不會影響系統整體可用性。分布式存儲中一般一份數據至少會有三個副本,允許不同節點間副本同步的延時就是軟狀態的體現。mysql replication的異步復制也是一種體現。l ?最終一致性?(Eventually Consistent)。最終一致性是指:經過一段時間以后,更新的數據會到達系統中的所有相關節點。這段時間就被稱之為最終一致性的時間窗口 BASE理論總結BASE理論是對CAP中的一致性和可用性進行一個權衡的結果,理論的核心思想就是:我們無法做到強一致,但每個應用都可以根據自身的業務特點,采用適當的方式來使系統達到最終一致性(Eventualconsistency)。有了以上理論之后,我們來看一下分布式事務的問題。分布式事務在分布式系統中,要實現分布式事務,無外乎那幾種解決方案。一、兩階段提交(2PC)和上一節中提到的數據庫XA事務一樣,兩階段提交就是使用XA協議的原理,我們可以從下面這個圖的流程來很容易的看出中間的一些比如commit和abort的細節。兩階段提交這種解決方案屬于犧牲了一部分可用性來換取的一致性。在實現方面,在 .NET 中,可以借助 TransactionScop 提供的 API 來編程實現分布式系統中的兩階段提交,比如WCF中就有實現這部分功能。不過在多服務器之間,需要依賴于DTC來完成事務一致性,Windows下微軟搞的有MSDTC服務,Linux下就比較悲劇了。另外說一句,TransactionScop 默認不能用于異步方法之間事務一致,因為事務上下文是存儲于當前線程中的,所以如果是在異步方法,需要顯式的傳遞事務上下文。優點:?盡量保證了數據的強一致,適合對數據強一致要求很高的關鍵領域。(其實也不能100%保證強一致)缺點:?實現復雜,犧牲了可用性,對性能影響較大,不適合高并發高性能場景,如果分布式系統跨接口調用,目前 .NET 界還沒有實現方案。二、補償事務(TCC)TCC 其實就是采用的補償機制,其核心思想是:針對每個操作,都要注冊一個與其對應的確認和補償(撤銷)操作。它分為三個階段:·?????Try 階段主要是對業務系統做檢測及資源預留·?????Confirm 階段主要是對業務系統做確認提交,Try階段執行成功并開始執行 Confirm階段時,默認 Confirm階段是不會出錯的。即:只要Try成功,Confirm一定成功。·?????Cancel 階段主要是在業務執行錯誤,需要回滾的狀態下執行的業務取消,預留資源釋放。舉個例子,假入 Bob 要向 Smith 轉賬,思路大概是: 我們有一個本地方法,里面依次調用 1、首先在 Try 階段,要先調用遠程接口把 Smith 和 Bob 的錢給凍結起來。 2、在 Confirm 階段,執行遠程調用的轉賬的操作,轉賬成功進行解凍。 3、如果第2步執行成功,那么轉賬成功,如果第二步執行失敗,則調用遠程凍結接口對應的解凍方法 (Cancel)。優點:?跟2PC比起來,實現以及流程相對簡單了一些,但數據的一致性比2PC也要差一些缺點:?缺點還是比較明顯的,在2,3步中都有可能失敗。TCC屬于應用層的一種補償方式,所以需要程序員在實現的時候多寫很多補償的代碼,在一些場景中,一些業務流程可能用TCC不太好定義及處理。(在我的理解是,有點try,catch的思想。)三、本地消息表(異步確保)本地消息表這種實現方式應該是業界使用最多的,其核心思想是將分布式事務拆分成本地事務進行處理,其基本的設計思想是將遠程分布式事務拆分成一系列的本地事務,這種思路是來源于ebay。我們可以從下面的流程圖中看出其中的一些細節:基本思路就是:消息生產方,需要額外建一個消息表,并記錄消息發送狀態。消息表和業務數據要在一個事務里提交,也就是說他們要在一個數據庫里面。然后消息會經過MQ發送到消息的消費方。如果消息發送失敗,會進行重試發送。消息消費方,需要處理這個消息,并完成自己的業務邏輯。此時如果本地事務處理成功,表明已經處理成功了,如果處理失敗,那么就會重試執行。如果是業務上面的失敗,可以給生產方發送一個業務補償消息,通知生產方進行回滾等操作。生產方和消費方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發送一遍。如果有靠譜的自動對賬補賬邏輯,這種方案還是非常實用的。這種方案遵循BASE理論,采用的是最終一致性,筆者認為是這幾種方案里面比較適合實際業務場景的,即不會出現像2PC那樣復雜的實現(當調用鏈很長的時候,2PC的可用性是非常低的),也不會像TCC那樣可能出現確認或者回滾不了的情況。優點:?一種非常經典的實現,避免了分布式事務,實現了最終一致性。在 .NET中有現成的解決方案。缺點:?消息表會耦合到業務系統中,如果沒有封裝好的解決方案,會有很多雜活需要處理。四、MQ 事務消息有一些第三方的MQ是支持事務消息的,比如RocketMQ,他們支持事務消息的方式也是類似于采用的二階段提交,但是市面上一些主流的MQ都是不支持事務消息的,比如 RabbitMQ 和 Kafka 都不支持。以阿里的 RocketMQ 中間件為例,其思路大致為:第一階段Prepared消息,會拿到消息的地址。 第二階段執行本地事務,第三階段通過第一階段拿到的地址去訪問消息,并修改狀態。也就是說在業務方法內要想消息隊列提交兩次請求,一次發送消息和一次確認消息。如果確認消息發送失敗了,RocketMQ會定期掃描消息集群中的事務消息,這時候發現了Prepared消息,它會向消息發送者確認,所以生產方需要實現一個check接口,RocketMQ會根據發送端設置的策略來決定是回滾還是繼續發送確認消息。這樣就保證了消息發送與本地事務同時成功或同時失敗。總結通過本文我們了解到兩個分布式系統的理論,他們分別是CAP和BASE 理論,同時我們也總結并對比了幾種分布式分解方案的優缺點,分布式事務本身是一個技術難題,是沒有一種完美的方案應對所有場景的,具體還是要根據業務場景去抉擇吧。然后我們介紹了一種基于本地消息的的分布式事務解決方案CAP。介紹個場景:4、分布式事務的應用場景 4.1、支付 最經典的場景就是支付了,一筆支付,是對買家賬戶進行扣款,同時對賣家賬戶進行加錢,這些操作必須在一個事務里執行,要么全部成功,要么全部失敗。而對于買家賬戶屬于買家中心,對應的是買家數據庫,而賣家賬戶屬于賣家中心,對應的是賣家數據庫,對不同數據庫的操作必然需要引入分布式事務。4.2、在線下單 買家在電商平臺下單,往往會涉及到兩個動作,一個是扣庫存,第二個是更新訂單狀態,庫存和訂單一般屬于不同的數據庫,需要使用分布式事務保證數據一致性。5、常見的分布式事務解決方案 5.1、基于XA協議的兩階段提交 XA是一個分布式事務協議,由Tuxedo提出。XA中大致分為兩部分:事務管理器和本地資源管理器。其中本地資源管理器往往由數據庫實現,比如Oracle、DB2這些商業數據庫都實現了XA接口,而事務管理器作為全局的調度者,負責各個本地資源的提交和回滾。XA實現分布式事務的原理如下:總的來說,XA協議比較簡單,而且一旦商業數據庫實現了XA協議,使用分布式事務的成本也比較低。但是,XA也有致命的缺點,那就是性能不理想,特別是在交易下單鏈路,往往并發量很高,XA無法滿足高并發場景。XA目前在商業數據庫支持的比較理想,在mysql數據庫中支持的不太理想,mysql的XA實現,沒有記錄prepare階段日志,主備切換回導致主庫與備庫數據不一致。許多nosql也沒有支持XA,這讓XA的應用場景變得非常狹隘。5.2、消息事務+最終一致性 所謂的消息事務就是基于消息中間件的兩階段提交,本質上是對消息中間件的一種特殊利用,它是將本地事務和發消息放在了一個分布式事務里,保證要么本地操作成功并且對外發消息成功,要么兩者都失敗,開源的RocketMQ就支持這一特性,具體原理如下:1、A系統向消息中間件發送一條預備消息 2、消息中間件保存預備消息并返回成功 3、A執行本地事務 4、A發送提交消息給消息中間件通過以上4步完成了一個消息事務。對于以上的4個步驟,每個步驟都可能產生錯誤,下面一一分析:·????????步驟一出錯,則整個事務失敗,不會執行A的本地操作·????????步驟二出錯,則整個事務失敗,不會執行A的本地操作·????????步驟三出錯,這時候需要回滾預備消息,怎么回滾?答案是A系統實現一個消息中間件的回調接口,消息中間件會去不斷執行回調接口,檢查A事務執行是否執行成功,如果失敗則回滾預備消息·????????步驟四出錯,這時候A的本地事務是成功的,那么消息中間件要回滾A嗎?答案是不需要,其實通過回調接口,消息中間件能夠檢查到A執行成功了,這時候其實不需要A發提交消息了,消息中間件可以自己對消息進行提交,從而完成整個消息事務基于消息中間件的兩階段提交往往用在高并發場景下,將一個分布式事務拆成一個消息事務(A系統的本地操作+發消息)+B系統的本地操作,其中B系統的操作由消息驅動,只要消息事務成功,那么A操作一定成功,消息也一定發出來了,這時候B會收到消息去執行本地操作,如果本地操作失敗,消息會重投,直到B操作成功,這樣就變相地實現了A與B的分布式事務。原理如下:雖然上面的方案能夠完成A和B的操作,但是A和B并不是嚴格一致的,而是最終一致的,我們在這里犧牲了一致性(不是某一時刻就立刻一致的),換來了性能的大幅度提升。當然,這種玩法也是有風險的,如果B一直執行不成功,那么一致性會被破壞,具體要不要玩,還是得看業務能夠承擔多少風險。舉個例子,比如A訂單系統,B為庫存系統,正常是下單,減庫存。那么如果按照二階段是,如果庫存系統因為并發而發生回滾,那么A系統也一并回滾,這樣的可用性就很低。如果加入這個消息中間件,則認為A系統事務成功了,B系統也會事務成功,B不成功則再發送直到它成功即可。分布式事務是A下單,B減庫存,把分布式事務分為,A下單的本地事務+發送消息,然后B再減庫存的本地事務。5.3、TCC編程模式 所謂的TCC編程模式,也是兩階段提交的一個變種。TCC提供了一個編程框架,將整個業務邏輯分為三塊:Try、Confirm和Cancel三個操作。以在線下單為例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,如果更新訂單失敗,則進入Cancel階段,會去恢復庫存。總之,TCC就是通過代碼人為實現了兩階段提交,不同的業務場景所寫的代碼都不一樣,復雜度也不一樣,因此,這種模式并不能很好地被復用。6、總結 分布式事務,本質上是對多個數據庫的事務進行統一控制,按照控制力度可以分為:不控制、部分控制和完全控制。不控制就是不引入分布式事務,部分控制就是各種變種的兩階段提交,包括上面提到的消息事務+最終一致性、TCC模式,而完全控制就是完全實現兩階段提交。部分控制的好處是并發量和性能很好,缺點是數據一致性減弱了,完全控制則是犧牲了性能,保障了一致性,具體用哪種方式,最終還是取決于業務場景。作為技術人員,一定不能忘了技術是為業務服務的,不要為了技術而技術,針對不同業務進行技術選型也是一種很重要的能力! ---------------------

?

總結

以上是生活随笔為你收集整理的分布式事务的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。