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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

事务与分布式事务

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

很多同學在開發中已經不自覺的接觸了很多事務相關的代碼(尤其是在數據庫操作中),但是事務究竟是做什么的,有沒有必要必須這么操作?

一段典型的代碼如下:

db.beginTransaction(); try {// do some CRUD operationdb.commit(); } catch {//Error in between database transaction db.rollback(); } finally { db.endTransaction(); }

從這段代碼可以更直觀的感受一下 “事務” 這個抽象的概念,那么事務是干什么用的呢?

事務(Transaction)


在wiki的解釋中,事務是一組單元化的操作,這組操作可以保證要么全部成功,要么全部失敗(只要有一個失敗的操作,就會把其他已經成功的操作回滾)。這樣的解釋還是不夠直觀,看下面一個經典的例子。

假設有兩個銀行賬戶A和B,現在A要給B轉10塊錢,也就是轉賬。在銀行系統中A和B是兩個獨立的賬戶,所以轉賬操作會被分解:

  • 從A的賬戶中扣掉10塊錢
  • 在B的賬戶中添加10塊錢
  • 那么問題就來了,如果成功的在A賬戶中扣掉了錢,但是沒有在B中加錢怎么辦?或者A中沒有成功扣款,B中卻加了錢怎么辦?這些可能性都是有的,比如突然斷電、系統崩潰或者A賬戶本來就沒有錢。所以無論上面哪一張情況發生,都是不應該的。

    解決上面問題的一種簡單方法就是事務 - 要么兩個操作都成功返回一個成功的結果,否則把所有操作回滾,返回一個失敗的結果。所謂回滾就是如果從A中扣錢成功但B中加錢失敗的話,那么把A中扣得錢再還回去。

    注:事務的英文Transaction其實就是交易的意思

    事務操作的基本步驟概括如下:

  • 開始事務
  • 執行一系列的數據庫操作
  • 如果沒有錯誤發生,那么提交事務,返回成功
  • 如果有錯誤發生,那么回滾事務,返回失敗
  • 同時事務發展出幾個基本原則 - ACID:

  • Atomicity 原子性,要不成功要么失敗,部分成功是不可以的
  • Consistency 一致性,在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞(一致性一般是由應用來指定的)
  • Isolation 隔離性,當一個事務正在進行的時候,假設沒有第二個事務在進行(并發,如果真的發生了,系統需要保證隔離的程度)
  • Durability 持久性,事務完成后,該事務對數據庫所作的更改便持久地保存在數據庫之中(防止系統崩潰)
  • 這幾個原則構成了單一數據源事務的基本原則。

    代碼實現


    由于事務的這些特點,所以在事務相關的代碼中,基本都是類似的風格:

    db.beginTransaction(); try {// do some CRUD operationdb.commit(); } catch {//Error in between database transaction db.rollback(); } finally { db.endTransaction(); }

    這就是我們經常見到的代碼(無論哪種語言)。這種相對比較固定的模板導致一種“聲明式”事務的產生,在Spring中會經常見到,所謂的“聲明式”大概表現如下:

    @Transactional public void insertXXX() { // do something... }

    在方法的聲明上,通過 @Transactional 注解把一個方法標注為支持事務的,那么在執行的時候,容器會自動給這個方法圍繞上面的代碼塊。

    事務的實現原理


    在開始的時候,我們說事務可以保證操作的ACID原則,那么事務究竟是如何保證這些原則的?db.beginTransaction() 、db.commit()、db.rollback()和db.endTransaction()究竟干了什么事,如果這些操作本身也失敗了怎么辦?

    實現事務功能的系統通常叫 “TransactionProcessingMonitor” 或 “TransactionManager”,這些系統通常會被打包進數據庫引擎中,在分布式系統中也會作為一個獨立的模塊存在。

    解決ACID問題的兩大技術點是:

  • 預寫日志(Write-ahead logging) 保證原子性和持久性
  • (locking) 保證各隔離性
  • 這里并沒有提到一致性,這是因為一致性是應用相關的話題,它的定義一般由業務系統來定義 - 什么樣的狀態才是一致的?而實現一致性的代碼通常在業務層邏輯的代碼中得以體現。

    是大家熟悉的一個話題,在并發環境中通過讀寫鎖來保證操作的互斥性,沒有太多神奇的東西。根據隔離程度不同,鎖的運用也不同,可能會產生一些問題,具體可以查看 Isolation (database systems)。

    本文比較感興趣的是預寫日志。因為在數據庫的復雜數據結構中更新數據是一個比較慢的操作,保證這種操作的原子性和持久性是很困難的。預寫日志的工作模式是這樣的:在任何事務操作發生之前,先把所有的變化寫入一個日志文件并持久化,然后再開始真實的寫數據庫操作。如果在接下來的操作中系統崩潰,那么我們可以在系統恢復之后檢查日志和數據庫中的記錄,來決定是繼續執行完成未盡的任務還是回滾操作 - 把數據庫還原到這次事務之前的一個狀態。

    預寫日志一般采用簡單順序日志(sequential file)的寫入格式,這樣日志寫入速度可以很快。這點很重要,因為一般事務操作的吞吐量往往受到日志系統速度的限制。日志的格式會同時記錄redo和undo的信息。

    分布式事務


    在大型應用開發中,經常要做業務拆分,把原來的單一架構的應用拆分成不同的服務。不同的服務之間松耦合可以很好的解決業務耦合問題,但是這樣也會帶來事務處理的問題,如果一個操作會同時寫入兩個數據庫,那么如何保證這兩個寫入的一致性?

    單一數據庫可以通過ACID原則保證自己的事務處理,但是如果有兩個不同的數據庫,如何保證針對這兩個數據庫的事務都成功呢?在 JavaEE 規范中使用 2PC (2 Phase Commit, 兩階段提交) 來處理跨 DB 環境下的事務問題。

    簡單來說J2EE的2PC協議是這樣的,先把事物請求發送給中間協調器,協調器負責各個數據源的事物處理。處理過程分兩個階段:

  • 投票階段
    協調器把事物請求發送給各個數據源,數據源負責各自的事物處理。
  • 完成階段
    協調器根據各個數據源的返回結果,決定是處理成功或者失敗,只要有一個結果是失敗的,那么會回滾所有數據源的事物處理。
  • 這種處理方式,實際上是一個放大版的ACID原則。但是在分布式環境下,2PC 是反可伸縮模式,在事務處理過程中,參與者需要一直持有資源直到整個分布式事務結束。這樣,當業務規模達到千萬級以上時,2PC 的局限性就越來越明顯,系統可伸縮性會變得很差。

    CAP


    在過去Inktomi的Eric Brewer曾提出過分布式系統的一種猜想(conjecture),在分布式系統中的三項重要指標:

    • Consistency 一致性
    • Availability 可用性
    • Partition-tolerance 分區容忍度

    是不能同時成立的 - 在任意時刻,只有兩項能同時成立。對于高流量的網站來說,為了提高系統伸縮性,一般都會犧牲一致性。

    BASE


    BASE是一種嘗試通過犧牲一部分一致性而達到高可用性的原則,ACID原則中要求系統的每個操作之后都是連續的,但是BASE認為系統是可容忍局部的/短時間的不一致。

    在基于ACID的事務中,事務是簡單可靠的,為了達成這種效果,往往會造成耗盡整個系統的資源造成整體不可用。而BASE的實現是復雜的和業務緊密相關的。BASE 原則體現在(采用這種原則意味著放棄ACID):

    • 基本可用(Basically Available)
    • 軟狀態(Soft state)
    • 最終一致(Eventually consistent)

    這是一組非常抽象的概念,通過這組原則你不能領會任何可行的具體的系統設計方案。BASE并沒有指明任何方案,只是在告訴你 - 其實還可以這么搞!

    下面看一下簡單的例子(從這里偷來的):假如有一個系統可以在上面買賣物品,可以設計著這樣的表結構:

    user and transaction

    在這個系統中,如果產生了一項交易,那么會現在Transaction表中記下一條記錄,然后在買家和賣家表中分別更新記錄。基于ACID原則的事務代碼是這樣的:

    acid

    這里面的三條SQL操作會分別更新三個不同的數據庫,在ACID系統中會使用2PC實現。如果從BASE的角度來考慮可以這么設計:

    base

    對于整個系統來說Transaction表才是真正有意義的,User表中的相關數據可以認為是為了系統性能而設計的緩存(這樣不必查Transaction表即可或許相關的數據)。所以可以設計出上面這種事務模型,這種模型的潛在問題是,如果對于User表的操作失敗了,那么在用戶端看到的結果是不準確的。現在我們的系統已經出現了不一致的問題,如果我們提前告知用戶,他看到的數據是粗略的估計,那么這個問題在業務上算是解決了。

    但是如果我們不能容忍這種可能會造成永久的不一致,那么該如何解決問題呢?答案在消息系統 - 可靠的消息系統。下面是改進版:

    base and mq

    在這種設計中,第一段代碼保證了Transaction和消息持久化的事務性,然后在消息處理系統中在分別更新User表的數據。并且在處理消息的時候,僅在事務成功的時候才移除消息,這樣可以保證User可以成功的更新。因為用到了消息系統,所以必然存在消息的延遲問題,而這正式前面說的 - 犧牲一部分的一致性(User和Transaction表不是同步更新的)。但是一旦消息被成功處理,我們最終會達成一致的狀態 - 即最終一致。

    看完了這個例子,對于BASE也僅僅是初步的認識,在真實的業務系統中還需要根據自己業務的特色設計相應的解決方案。

    注1:分布式事務確實牛逼,寫作過程中深感壓力,如果不足不對的地方,還請高手多多指正。
    注2:對于最開始那個轉賬的例子,用BASE思想的實現現在還不方便說,因為這是螞蟻內部的資料。

    參考:

    • ACID
    • Transaction Processing Cheat Sheet
    • Database transaction
    • Spring事務配置的五種方式
    • Transaction processing system
    • Write-ahead logging
    • 犧牲一致性來換取分布式架構的可伸縮性
    • 可伸縮性最佳實踐:來自eBay的經驗
    • Base: An Acid Alternative



    作者:ntop
    鏈接:https://www.jianshu.com/p/d322cba3add4

    轉載于:https://www.cnblogs.com/miracle77hp/p/10170118.html

    總結

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

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