標籤:blog http 使用 strong width 資料
目前OceanBase中還存在updaeserver單點,下一步的開發工作單位是使得OB支援多點寫入,支援多個UPS(及updateserver)。
其中痛點是如何設計兩階段交易認可的失敗恢複以及多機的快照讀寫,和同事討論後,形成一個可以work的簡單設計版本,記錄在此。
為分散式交易的兩階段交易認可細化具體流程,擬採用primary record方式實現失敗恢複,即在進入commit階段之前,先寫入primary record 記錄當前事務的狀態(commit/rollback)。Primary record起到一個全域日誌的作用,可供所有參與者讀取。需要注意的是,為了保證一致性,讀寫primary record 都需要加鎖,需要使用select update語句。
採用primary record 方式的優勢是,協調者在整個交易處理過程中可以是無狀態的,不需要記錄動作記錄,宕機重啟後不需要做失敗處理;而參與者宕機重啟或逾時失敗後,可以無需與協調者以及其他參與者通訊,實現獨立恢複,實現簡單。其缺點是每次分散式交易中都會記錄一次primary record,會增加寫入資料量以及事務延遲。
將兩階段交易認可的流程分為以下子流程描述:
? 協調者處理流程
? 參與者處理流程
? 未決交易處理流程
為支援長事務、長事務中長語句以及兩階段交易認可,文檔還簡單描述了對UPS日誌的修改目標。
最後,文檔簡單記錄了組內討論實現多UPS快照讀寫的一些討論結果。
1. 兩階段交易認可詳細流程
? 協調者處理流程
協調者處理流程指的是開始一個分散式交易直到事務結束或者失敗。處理期間,協調者需要維護分散式交易的相關狀態和資訊,如參與者清單,事務執行計畫,事務提交的時間戳記,事務的primary record 主鍵等等,這些資訊不需要持久化儲存,協調者宕機後,也不需要執行失敗恢複。
具體流程如所示:
在中,當準備寫入rollbackprimary record時候,如果已經存在相同的記錄,即有可能參與者寫入了rollback primary record,是正常情況,具體看後面參與者的處理流程;但如果準備寫下commit primary record時候發現已經存在rollback primary record,或者準備寫下rollback時候發現存在commitprimary record,這是有問題的,需要警示,人工幹預。
? 參與者處理流程
參與者處理流程指的是收到協調者發來的start session 請求直到收到end session請求或者失敗。
協調者發送startsession時候需要攜帶primary record 的rowkey,參與者需要將其記錄到prepared日誌和commit日中,用於失敗恢複時候查驗primary record和日誌回放時候串接prepare日誌和commit日誌。
由於協調者在開始期間無法得知哪些參與者需要寫入資料,哪些參與者只需要讀取資料,因此參與者最初的session都是READ ONLY,當收到寫入請求後,原先的ROSession升級為RWSession。同時,協調者需要記錄相關資訊,用於發送prepare訊息。
對於開啟ROSession的參與者,沒有兩階段交易認可的問題,處理流程和UPS現有邏輯保持一致;對於開啟了RWSession的參與者,兩階段交易認可流程如下:
在上述流程中,參與者出現訊息逾時或者寫入失敗後,是有許可權寫rollback primary record的。這樣的好處是,如果協調者在寫primary record前宕機,而參與者在寫入prepare日誌也宕機,在參與者重啟處理未決交易時候可以查primary record判定事務狀態,無需等到逾時即可終止未決交易,及時完成回放。
參與者只能寫rollbackprimary record,不能寫commit primary record。當寫rollback primary record時候,可以允許已經存在rollbackprimary record的情況出現,而不應該存在commit primary record。
另外,還有一種情況沒有在圖中畫出來,讀寫事務開始後,必須沿著一下順序進行:
處理讀寫請求->處理prepared請求->處理commit/rollback請求。對於錯序請求(即未prepare前收到commit請求),需要異常處理。
? 未決交易的處理流程
未決交易來源於以下兩種情況:
l 參與者在處理事務請求的過程中出現等待逾時;
l 宕機重啟後回放日誌,回放完畢所有日誌後,還有未提交事務。
對於這兩種情況,都採用以下的處理流程:
宕機重啟後,回放日誌時如果出現未決交易(即只有prepare 日誌,沒有commit日誌),並且未讀到primary record,則需要等到此事務逾時後,再去嘗試寫rollback primary record ,其原因是為了防止這樣情況的出現:
在一個分散式交易中,一個參與者寫下prepared並回應協調者後宕機,但迅速重啟,重啟後這個分散式交易還在prepare階段,在這種情況下,這個分散式交易還是可以正確提交的。需要注意的時候,逾時時間需要將記錄在prepare日誌中
每個參與者嘗試結束未決交易時,先要讀取或寫primary record成功primary,如果出錯,是會阻塞未決交易的提交或者復原的,此時需要警示,並保持重試。
在兩階段交易認可協議中,一旦所有參與者都prepare成功,則要求這個事務一定能提交,但在這個文檔所描述的方案中是存在反例的:協調者如果在寫commit primary record前宕機,所有參與者逾時後走恢複流程,是會將這個交易回復的。
2. UPS日誌改造目標
目前受限於2MB的網路包最大長度,UPS不支援日誌大於2MB的長事務。在兩階段交易認可的流程中,對於一次分散式交易,至少需要寫入兩條日誌,在這個驅動下,準備修改UPS寫入和回放日誌的方式,使得其支援長事務以及兩階段交易認可對日誌的要求。
基本想法如下:
? UPS在執行事務的過程中,如果日誌內容超過一定閾值,則非同步提交一次日誌任務,同一個事務的多條日誌之間,使用唯一的事務ID進行關聯
? 在事務中,UPS支援一條語句寫多條日誌,使用唯一的語句ID進行關聯
? ups支援事務內部,單條語句層級的提交和復原需要記錄提交或復原的日誌
對於兩階段交易認可的日誌:
? 協調者收到prepare請求時,無需寫專用的prepare日誌,但是要阻塞等待確認prepare之前執行的語句日誌都已經刷盤。
? 事務commit/rollback要記錄日誌,但非同步執行,不阻塞協調者,即收到commit請求後,可直接回複協調者,無需等待commit日誌落盤。這是因為即便此時commit日誌寫入失敗,也可通過讀取primary record重新完成提交或者復原操作。
3. 多UPS快照讀和寫
多UPS進行分散式交易時,在沒有全域時鐘的情況下,每個UPS使用本地時鐘獨立維護自己的多版本資料。當一次讀寫事務涉及多個UPS時候,需要協調者在prepare階段擷取到每個參與者的本地prepare時間戳記,然後使用其中的最大值作為此次分散式交易的時間戳記,在commit階段發給所有參與者,每個參與者都使用此時間戳記作為此次事務寫入資料的版本時間戳記。
執行快照讀時候,協調者需要使用所涉及的多UPS中時間戳記最小作為統一的時間戳記,以免讀到未提交資料,出現幻讀。討論中,針對快照讀,提出一下最佳化方式:
? 每個UPS中,本地最大事務版本號碼(CV)是在有讀寫事務提交時後才會更新的,為了避免有的UPS在長時間沒有讀寫事務提交的情況下,CV得不到更新,導致其值遠遠落後其他UPS,採取定時寫入NOP日誌的方式,隨著時間推移,不斷更新CV。
? 快照讀時,需要使用所有參與者中最小版本號碼(即時間戳記)作為本次快照讀的時間戳記,而由於事務的互動性,無法預知參與者有哪些。為了避免全域廣播擷取所有機器版本號碼,可以採用下面做法:
快照讀的發起者,採用本地版本號碼V作為此次讀的版本號碼,發送讀請求給其他參與者S,如果S本地的版本號碼小於V,則阻塞等待,直到S的版本號碼大於V後再進行讀取。另外,如果S上存在狀態為prepare的分散式交易,且這些事務prepare的版本號碼小於S, 則需要等待這些分散式交易進入commit狀態,才能繼續讀取。這是因為這些狀態為prepare的分散式交易轉變為commit狀態後,其版本號碼既可能大於V也可能小於V。