成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官問我:分布式事務是什么?

開發 前端 分布式
事務其實大家應該不陌生,尤其是對于程序員來說,如果你連事務都沒聽說過,沒關系,因為你遇到了聰明和才智于一體的我,事務其實就是為了處理多種混合操作,涉及到多方面業務的情景

[[403411]]

事務

事務其實大家應該不陌生,尤其是對于程序員來說,如果你連事務都沒聽說過,沒關系,因為你遇到了聰明和才智于一體的我,事務其實就是為了處理多種混合操作,涉及到多方面業務的情景

重點是事務應用的場景就是為了解決多種事務必須要么同時完成,要么同時不能完成的場景,也就是做到真正意義上的"同生共死"

嚴格意義上來說事務其實具有原子性、一致性、隔離性和持久性四種特性,也就是大家老生常談的ACID

  • 原子性(Atomicity),可以理解為一個事務內的所有操作要么都執行,要么都不執行
  • 一致性(Consistency),可以理解為數據是滿足完整性約束的,也就是不會存在中間狀態的數據,比如你賬上有400,我賬上有100,你給我打200塊,此時你賬上的錢應該是200,我賬上的錢應該是300,不會存在我賬上錢加了,你賬上錢沒扣的中間狀態
  • 隔離性(Isolation),指的是多個事務并發執行的時候不會互相干擾,即一個事務內部的數據對于其他事務來說是隔離的
  • 持久性(Durability),指的是一個事務完成了之后數據就被永遠保存下來,之后的其他操作或故障都不會對事務的結果產生影響

嚴格意義上來說事務其實具有原子性、一致性、隔離性和持久性四種特性,也就是大家老生常談的ACID

其實在我們印象中,應該對這個事務再熟悉不過了,大家都知道事務就是為了使得一些數據庫層面的更新操作要么全部成功,要么全部失敗。

不知道大家學過Redis沒有,如果學過Redis的其實可能會有疑問,因為Redis的事務不能保證所有操作要么都執行,要么都不執行,但是也叫做事務。Redis其實在官網就已經說明白了,官網中告訴大家事務中的某個命令失敗了,之后的命令還是會被處理,Redis不會停止執行命令,也就是意味著不會回滾

Redis解釋為什么不支持回滾

他們給出的回的就是首先如果命令出錯那就是語法的錯誤,是屬于個人的編程錯誤,而且這種情況應該被檢測出來,而不是在生產環境出現,于是乎Redis為了速度更快不支持回滾操作

感覺很有道理的樣子,但是又有點不對勁

好了,這下大家都知道事務是啥了,那么我們一起來看看分布式事務吧

分布式事務

剛才說的事務都是屬于單體程序中,單機中這樣是沒問題的,通過普通的事務操作就可以來解決;當我們的系統逐漸變大,日益變強的同時,并發量和系統都隨之而增加,當涉及到多個系統之間的配合來完成一個事務的時候,這就比較難辦了,因為無法直接通過一個系統的數據庫來完成

假設現在有訂單系統、扣款系統、積分系統,這是屬于三個系統,也就是分別在不同的數據庫中,但是我需要保證三個系統中的服務要么全部成功、要么全部失敗,其實像這種設計到多個庫、多個系統之間的事務操作,也就是分布式事務了

分布式事務其實說簡單也簡單,其實就是有多個本地事務組合而成,對于分布式事務而言幾乎滿足不了ACID,其實對于單機事務大多是情況下也是無法全部滿足ACID的,否則哪里來的四種隔離級別?所以更別說分布在不同數據庫、不同系統之間的分布式事務了

分布式事務大致可以分為六種,但是其實這六種又可以按照三種思想來分類,接下來一起看看吧

2PC和3PC是一種強一致性事務,不過還是有數據的不一致、阻塞等風險,而且只能應用在數據庫層面;而TCC是一種補償性事務的思想,適用的范圍應該是比較廣,不過這種補償性機制一般對業務的侵入性比較大,每一個操作都需要實現對應的三種方法;還有一種思想就是努力實現最終一致性事務,有本地消息、事務消息、和最大努力通知這三種方法,都是實現最終一致性事務,因此適用于于一些對于時間不敏感的業務

大致了解了這三類,接下來來細細學習每一種吧

  • 2PC二階段提交:準備階段、提交階段

2PC,又叫做二階段提交,二階段指的是準備階段和提交兩個階段

二階段提交屬于一種強一致性的設計,2PC引入一個事務協調者的角色來協調管理各參與者的提交和回滾機制,我們來看下具體流程

準備階段協調者會向各個參與者發送準備的命令,這個準備其實就是準備環境,可以理解成提交之前的準備工作

同步的等待所有的資源的響應之后,就到了萬事俱備,只欠提交的狀態了

提交階段,提交階段并不一定是提交事務,也有可能是回滾事務,如果第一階段都準備成功,則第二階段的提交就是提交事務;同理如果第一階段未全部準備成功,則第二階段提交的就是回滾事務了。假設第一階段都準備成功,則協調者向所有參與者發送提交命令,然后接下來等待所有參與者都成功之后,返回事務執行成功

假設第一階段有部分參與者返回失敗的話,那么協調者則會向所有參與者都發送回滾事務的請求,即類似上圖,向全部參與者發送回滾事務

說到這里其實有些小伙伴已經開始有疑問了,我知道了第一階段有失敗的如何處理了,但是如果第二階段出現失敗了咋整呢

其實這里分了兩種情況,分別是第二階段執行的是提交階段、第二階段執行的是回滾操作,這兩種情況的處理方式其實是一樣的,都是屬于不斷地重試,直到重試成功;對于提交來說,可以根據業務場景,執行一定次數的重試之后,嘗試回滾;但是對于回滾操作,總不能執行成功操作吧

所以,如果第二階段是回滾操作有失敗,當失敗次數達到一定次數的時候,最好的方法就是人工介入了

提交流程大致也分析的差不多了,接下來一起看看細節部分,2PC可以看成同步阻塞協議,同步阻塞的等待所有參與者的第一階段都有響應之后,才會進行第二階段的操作;對于Java基礎很熟悉的小伙伴是不是很快想起來Java并發包中的一個工具類CountDownLatch,以及功能類似的CyclicBarrier,忘記的趕緊回憶下

其實2PC中對于這里的同步阻塞是有超時機制的,協調者等待參與者的響應超時的情況下,會默認失敗,然后協調者直接向所有參與者發起回滾的命令,知道這次事務失敗

上面這些都是基于參與者的角度來考慮的,那如果協調者出問題了呢

協調者如果是單點的,出現故障之后,可能會出現一些系統的問題,我們從流程的角度分析下:

準備階段命令未發出,協調者故障,事務還沒開始,問題不大;

準備階段命令發出了,協調者故障,事務開始了,無論參與者都是成功還是失敗,最終情況都很糟糕,因為參與者無法等到下一步的指令了,也就是卡碟了,不僅事務無法執行,還會鎖定一些公用資源而阻塞其它系統;準備階段命令發出,全部成功,第二階段執行提交階段命令發出,這種情況也是不行的,因為也可能因為分區和網絡阻塞,某些參與者未收到提交命令,理想情況下如果參與者一次性全部收到提交命令,但是參與者有可能提交失敗,這樣還是需要重試,此時協調者掛了,也是不行

準備階段命令發出,部分失敗,第二階段回滾命令發出,其實和上面情況類似,也是會出現各式各樣的問題

既然單點協調者不行,那就來個多個的吧,通過選舉機制再選一個新協調者

如果都處于第一階段,其實都還好,事務還沒提交,直接都會滾就好了;如果處于第二階段,假設參與者都沒掛,此時新協調者可以向所有參與者來進一步確認他們自身的情況來推斷下一步該如何操作,如果個別參與者掛了,就比較尷尬了。比如協調者發送了回滾的命令,此時第一個參與者收到了并執行了,然后協調者和第一個參與者都掛掉了,此時其它參與者都沒收到請求,然后新協調者來了,它詢問了其它的參與者都回答OK,但是它不知道其中第一個參與者掛了,此時要是按照全部OK來處理,直接發送提交命令,就糟糕了,這不是我們想要的結果

其實雖然2PC協議上沒說,但是在實現的時候我們需要靈活的讓協調者將自己發過的請求在哪些地方都記一下,也就類似于日志記錄,這樣新的協調者來的時候就不、知道此時該不該發了

即使協調者知道自己應該發提交還是回滾請求,但是在參與者也一起掛了的情況下也是沒用的,因為協調者無法知道參與者在掛之前有沒有提交事務,其實這里最靠譜的方法,就是對每一步都進行相應的日志記錄,重要的步驟最好還是強綁定日志記錄的,否則操作成功了,日志記錄失敗那也很糟糕,總之就是要考慮各種極端的情況,盡最大努力去做到每個細節都考慮到

2PC是一種盡量保證強一致性的分布式事務,因為它是同步阻塞的,而同步阻塞就意味著在某些情況下會出現鎖定資源的情況,而且單點一旦出現故障,就會造成資源鎖定的情況

以下代碼取自 <<Distributed System: Principles and Paradigms>>

  1. 協調者: 
  2.  
  3.  
  4.  
  5.     write START_2PC to local log; //開始事務 
  6.     multicast VOTE_REQUEST to all participants; //廣播通知參與者投票 
  7.     while not all votes have been collected { 
  8.         wait for any incoming vote; 
  9.         if timeout { //協調者超時 
  10.             write GLOBAL_ABORT to local log; //寫日志 
  11.             multicast GLOBAL_ABORT to all participants; //通知事務中斷 
  12.             exit; 
  13.         } 
  14.         record vote; 
  15.     }   //如果所有參與者都ok 
  16.     if all participants sent VOTE_COMMIT and coordinator votes COMMIT { 
  17.         write GLOBAL_COMMIT to local log; 
  18.         multicast GLOBAL_COMMIT to all participants; 
  19.     } else { 
  20.         write GLOBAL_ABORT to local log; 
  21.         multicast GLOBAL_ABORT to all participants; 
  22.     } 
  23.  
  24. 參與者: 
  25.  
  26.     write INIT to local log; //寫日志 
  27.     wait for VOTE_REQUEST from coordinator; 
  28.     if timeout { //等待超時 
  29.         write VOTE_ABORT to local log; 
  30.         exit; 
  31.     } 
  32.     if participant votes COMMIT { 
  33.         write VOTE_COMMIT to local log; //記錄自己的決策 
  34.         send VOTE_COMMIT to coordinator; wait for DECISION from coordinator; 
  35.         if timeout { 
  36.             multicast DECISION_REQUEST to other participants; //超時通知 
  37.             wait until DECISION is received;  /* remain blocked*/ 
  38.             write DECISION to local log; 
  39.         } 
  40.         if DECISION == GLOBAL_COMMIT 
  41.             write GLOBAL_COMMIT to local log; 
  42.         else if DECISION == GLOBAL_ABORT 
  43.             write GLOBAL_ABORT to local log; 
  44.     } else { 
  45.         write VOTE_ABORT to local log; 
  46.         send VOTE_ABORT to coordinator; 
  47.     } 
  48. 每個參與者維護一個線程處理其它參與者的DECISION_REQUEST請求: 
  49.  
  50.     while true { 
  51.         wait until any incoming DECISION_REQUEST is received; 
  52.         read most recently recorded STATE from the local log; 
  53.         if STATE == GLOBAL_COMMIT 
  54.             send GLOBAL_COMMIT to requesting participant; 
  55.         else if STATE == INIT or STATE == GLOBAL_ABORT; 
  56.             send GLOBAL_ABORT to requesting participant; 
  57.         else 
  58.             skip;  /* participant remains blocked */ 
  59.     } 
  • 3PC三階段提交:準備階段、預提交階段、提交階段

3PC其實就是2PC的升級版,相比于2PC,參與者也引入了超時機制,并且還新增了一個階段使得參與者可以利用這一階段來統一各自的狀態

3PC分為三個階段:準備階段、預提交階段、提交階段。看起來更像是把2PC中的提交階段分為了預提交和提交的兩個階段, 但是這里的準備階段其實就是詢問參與者的自身狀況,就是問你現在的狀況如何,負載是不是超載,還可以再接受新的任務嗎

而預提交階段其實就是類似于2PC的準備階段,就是除了事務的提交該做的都做了,就是之前的準備工作,但是在3PC中叫做預提交階段 


3PC是首先準備階段并不會直接執行事務,而是先去詢問此時的參與者是否有條件可以執行這個事務,因此不會直接鎖住資源,而預提交階段的引入則是為了起到了一個統狀態的作用,在預處理階段表面所有參與者都已經回應了

其實這也多引入了一個階段,因此性能會差一些,而且絕大部分的情況下資源也都是沒問題的,也就是可用的,這樣等于每次明知可用但是還是得詢問一次

當然,這其中哪一個階段的參與者返回失敗都會宣布事務失敗,這個2PC也是一樣的,當然到最后的提交階段和2PC一樣都是只要是提交請求也就只能通過不斷的重試咯

我們上面說過2PC是同步阻塞的,協調者掛在了提交請求還未發出去的時候是最尷尬的,所有參與者都已經鎖定了資源并且阻塞的等待著,于是引入了超時機制,參與者則不用直接干干的等著了,如果是等待提交命令超時,那么參與者就會提交事務了,因為到了這一階段大概率都是提交的,如果是等待預提交超時,接下來也沒啥影響

這里其實有一個問題,然后超時機制會帶來數據不一致的問題,就是在等待提交命令的時候超時,那么參與者自動提交事務了,但是呢,也可能執行的是回滾機制,這樣一來數據便出現了不一致了

3PC的引入是為了解決提交階段2PC協調者和其中的部分參與者都掛了的情況下,然后之后的新選舉的協調者不知道當前應該是該提交還是回滾的問題,新協調者來的時候發現有一個參與者處于預提交或者提交階段,那么表明所以參與者都已經經過確認了,所以此時執行的就是提交命令了

3PC就是通過引入預提交階段來是的參與者之間的狀態得到真正的統一,也就是留了一個階段讓大家都同步,但是這也是只能讓協調者知道如何做,并不能保證這樣做一定是對的,這其實和上面的2PC的分析一直,因為掛了的參與者到底有沒有執行事務是無法斷定的,所以說呢,3PC通過預提交階段可以減少故障時候的復雜性,但是并不能保證數據真正的一致,處理掛了的那個參與者也恢復了

一句話總結:3PC相比于2PC做了一定的參與者超時機制的改進,并且增加了預提交階段,可以使故障恢復之后的協調者的決策復雜度降低,但整體的交互過程會變得更長,性能會有所下降,而且還會出現數據不一致的情況

  • TCC:Try-Confirm-Cancel

TCC屬于業務層面的分布式事務,分布式事務不僅僅包含數據庫層面的操作,還包括業務層面的操作,這時候TCC就要排上用場了

TCC指的就是Try、Confirm、Cancel三個步驟,Try指的是預留,指的是資源的預留和鎖定;Confirm指的就是確認操作,這一步其實就是屬于真正的執行了,真正的消耗資源來進行相應的業務提交操作;Cancel指的是撤銷操作,可以理解為把預留階段的動作銷毀了,就是一個回滾操作

從思想上來看,其實是和2PC、3PC是類似的,都是先試探性的執行,先試探性的鎖定資源,如果每一個參與者都沒問題了,就可以執行真正的操作了,提交或者回滾 

舉個例子:一個事務要執行A、B、C三個操作,那么先對三個操作執行預留動作,如果所有都預留成功了那么就執行確認提交操作,如果其中至少有一個預留失敗,那就都執行撤銷的動作

TCC模型其中還有一個事務管理者的角色,用來記錄TCC有關的全局事務操作的狀態,并且準備提交或者回滾事務,其實這個是比較容易理解的,難點在于業務上的定義

怎么說呢,TCC這種是對業務的侵入較大和業務緊耦合,需要根據相應的特定的業務場景和業務邏輯來設定的響應操作,其實還有一點需要注意的是,撤銷和確認的操作的執行的就是需要重試,就是需要保證操作的冪等性

TCC相對來說,適用的范圍應該是更廣的,但是這個是有一個缺點的,就是這個和業務是耦合的,需要大量的開發,因為都是在業務上的實現,等同于每個場景都需要三個方法來實現,就是嵌入業務,所以TCC是可以跨業務系統、跨數據庫來實現事務

  • 本地消息表

本地消息表,就是利用了各個系統的本地事務來實現分布式事務,這個呢,其實很簡單的道理,其實就是會有一張存放本地消息的表,一般都是放在數據庫中,然后在執行業務的時候,必須把業務的真正的執行操作和相應的這個操作的消息放入到消息表中這個操作,存放到同一個事務中,就是只要操作成功了,就必須保證該消息也成功的放入到本地的消息表中了

接下來調用下一個操作的時候,如果下一個操作調用成功了,就可以直接把消息的狀態改成已成功,調用失敗也沒有關系,我們可以寫一個定時任務來讀取本地的消息表,然后篩選出未執行成功的消息再調用對應的服務,服務更新成功了,再改變消息的狀態

其實這里也是需要重試機制,重試就得保證對應服務的方法是冪等的,而且一般重試也會有最大的次數,超過最大次數的時候可以人工介入

本地消息表實現的是業務的最終一致性,需要能夠容忍數據暫時不一致的情況

  • 消息事務

其實消息事務,最典型的就是屬于RocketMQ中的實現了,而且應用的場景也是比較多的

RocketMQ的機制就是先給Broker發送事務消息,也就是半消息,半消息指的是這個消息對消費者來說不可見,然后發送成功后,發送之后會繼續執行本地事務

第二步就是根據本地事務的執行結果向Broker發送Commit和Rollback命令,如果一直不發送,RocketMQ的發送方會提供一個反查事務狀態的接口,用來反查相應的事務的結果到底是成功還是回滾

其實這也就是個超時機制,在一段時間內沒有收到任何的操作請求,那么Broker就會通過相應的結果查出該事務是否成功執行呢,是Commit還是Rollback

如果是Commit,則broker就會發送這個消息到訂閱方,然后再做對應的操作,做完了之后就可以消費這個消息,如果是Rollback則訂閱方即收不到這個消息,等同于事務沒有執行過

  • 最大努力通知

其實最大努力通知我個人認為是一種思想,像上面的本地消息表、事務消息也是屬于最大努力通知類型的

本地消息表會有后臺任務定時查看未完成的任務的消息,然后去調用對應的服務,進行多次重試,當多次失敗的時候就需要引入人工,這也是屬于最大努力

事務消息也是屬于類似,半消息被Commit之后就會發送到消費端了,如果消費端一直不消費或者消費不了則會一直重試,如果重試次數達到一定數量,該消息變回進入到私信隊列,也是屬于盡最大努力通知吧

這應該是屬于一種思想,盡最大努力的達到事務的最終一致,適用于對時間不敏感的業務場景

 

責任編輯:姜華 來源: 大魚仙人
相關推薦

2022-11-25 17:29:27

分布式事務

2024-06-26 11:55:44

2024-09-24 16:30:46

分布式鎖Redis數據中間件

2022-08-11 18:27:50

面試Redis分布式鎖

2021-12-02 08:19:06

MVCC面試數據庫

2023-01-26 02:16:17

2024-02-22 17:02:09

IDUUID雪花算法

2020-09-27 06:52:22

分布式存儲服務器

2025-03-05 00:01:00

ReduxReact

2024-08-07 08:15:47

2022-06-27 08:21:05

Seata分布式事務微服務

2024-03-01 09:53:34

2020-04-16 08:22:11

HTTPS加解密協議

2021-05-20 08:54:16

Go面向對象

2010-08-23 15:06:52

發問

2022-05-24 08:03:28

InnoDBMySQL數據

2021-01-08 09:14:59

分布式事務框架

2024-10-07 08:52:59

分布式系統分布式 IDID

2022-06-21 08:27:22

Seata分布式事務

2017-07-26 15:08:05

大數據分布式事務
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91精品久久久久久久久久入口 | 久久久久久成人 | 黄色网址免费看 | 在线视频一区二区三区 | 国产一区二区在线播放视频 | 亚洲成av片人久久久 | 华丽的挑战在线观看 | 成人一级视频在线观看 | 国产欧美日韩一区二区三区在线观看 | 成人国产a | 久久亚洲一区 | 国户精品久久久久久久久久久不卡 | av二区三区 | 中文字幕1区2区3区 日韩在线视频免费观看 | 久久夜色精品国产 | 最新免费视频 | 少妇特黄a一区二区三区88av | 日日夜夜狠狠操 | 日韩视频在线观看中文字幕 | a亚洲精品 | 亚洲逼院| 亚洲国产精品成人无久久精品 | 玖玖国产精品视频 | 午夜视频在线免费观看 | 日本在线播放一区二区 | 波多野结衣先锋影音 | 日韩一区二区福利视频 | 一区二区国产精品 | 国产高清视频一区二区 | 午夜精品久久久久久久久久久久久 | 人人人人干 | 久久久精品一区二区三区四季av | 看片一区 | 国产99久久 | 久久久精品久久久 | 国产一区二区精品自拍 | 精品综合久久 | 91pao对白在线播放 | 日韩欧美在线播放 | 精品久久久av | 在线观看中文字幕av |