深入淺出事務的本質,附 OceanBase 事務解析14問!

OceanBase開源社群發表於2022-03-21

深入淺出事務的本質,附 OceanBase 事務解析14問!

作者:顏然,螞蟻集團資深技術專家

OceanBase 初創成員之一,OceanBase 分散式資料庫事務研發負責人,目前負責事務引擎、高可用架構、負載均衡、效能優化等方面的工作。


事務的前世

每個人的手機和電腦中幾乎不會安裝一款叫“資料庫”的應用,但是幾乎每一款 App 內部都會使用一個叫“資料庫”的更底層的系統來儲存資料。每個人日常生活中都會訂票、購物、付款,但也許還沒有意識到這些操作的背後都是由“資料庫”系統來支撐。那麼究竟什麼是“資料庫”?“資料庫”和“事務”又有什麼關係呢?

計算機系統在其發展的歷程中經歷了多次重要的事件,而上個世紀 60 年代迎來一次重大變革,為計算機系統帶來了鉅變,自那之後,計算機就開始以數字化的方式重塑整個世界的程式。這次變革就是“磁碟”的大規模使用。在磁碟之前,計算機使用“磁帶”來儲存資料。計算機使用的磁帶,和聽歌使用的磁帶,或者看電影用的錄影帶,本質是一種東西。這是個暴露年齡的比喻,畢竟這兩種東西現在已經只能在博物館裡才能看到了。磁帶的最大問題是不方便找東西,“倒帶”是個極其需要耐心的活。這就決定了,當時的計算機所處理的資料都是通過後期謄錄到磁帶上的,計算機只是用於統計和彙報所需。

最初的磁碟是個大傢伙,看下圖也許分辨不出大小,但實際上它有微波爐那麼大。這第一塊硬碟,呃,不能稱為一塊,這一臺硬碟只能儲存 3.75MB 的資料。當然,隨著技術的不停迭代,硬碟越做越小,容量越做越大。再到後面,又出現了升級版的快閃記憶體介質,硬碟就小到無孔不入了。但是不論大小,這些儲存裝置隨機訪問的特性都是一樣的。

深入淺出事務的本質,附 OceanBase 事務解析14問!

磁碟最重要的特性是“隨機訪問”,即使用者需要查詢的東西,可以輕鬆地定位到。計算機的快速處理能力,加上磁碟對資料的快速定位和修改能力,珠聯璧合,為計算機系統開啟了新世界的大門。自此,計算機開始參與到人類社會的方方面面。比如,航空公司的第一個售票系統 Sabre,使用計算機和磁碟直接儲存每一個待售賣的航班客票資訊和購票人資訊。這些資訊儲存在硬碟上,被售票員實時訪問和修改,直接替代了以紙質方式記錄客票資訊的方式。在此之後,銀行、通訊、交通等各行業,都使用磁碟來儲存其業務資訊,並使用計算機來響應各種“實時處理”的需求。

對於資料處理需求的極速膨脹,專門用於資料儲存和訪問的“資料庫管理系統”也應運而生,並被作為一個獨立的系統而廣泛接受。一個軟體系統之所以能獨立出來並被市場接受,原因在於其可複用性,也就是說,在眾多的業務場景中,使用了這個軟體要比不使用的時候,更方便,效率更高,世界也會因此而變得更美好。

資料庫管理系統幫助使用者解決的通用性問題主要有:

  1. 資料儲存與管理
  2. 資料訪問
  3. 資料變更
  4. 高可用

資料的儲存與管理解決了資料如何管的問題,它本質上是對儲存裝置的提煉和抽象,讓使用者不用關心資料在硬碟上具體是如何放置的,而只用關心資料的模型即可。從早期到現在,資料模型層出不窮,在關係模型之前,有網路模型和層次模型,在關係模型之後,有物件模型、文件模型、圖模型等。

資料的訪問解決如何在資料中做查詢和分析,在資料模型之上,資料庫系統會提供抽象的介面讓使用者方便使用,比如 SQL 語句就是在關係模型之上有超強表達能力的資料訪問介面。

資料變更解決的就是修改資料的問題,而修改資料的核心在於怎麼保證資料的正確性和一致性,把資料改錯了,是使用者最不願看到的情況。而“事務”功能就是“資料變更”功能的核心。事務功能提供給使用者 4 個著名的特性:原子性 Atomicity、一致性 Consistency、隔離性 Isolatation、永續性 Durability,簡稱 ACID。使用者將多個資料變更的操作以一個事務的整體提交到資料庫管理系統上進行操作,那麼資料庫管理系統就能保證使用者做的資料變更具有 ACID 的特性。

高可用特性是近些年來人們對系統特別強調的一個要求。以前,系統往往強調可靠性,而現在系統則更多的改為可用性。究其原因,隨著網際網路逐漸深入人們的生活,線上化專案的快進,服務不可用對於人們生活的影響越來越大,所以人們對於系統的要求也從可靠性變成了可用性。這是一種質的變化,可用性等於可靠性加上服務的連續性。高可用也和事務特性密切相關,我們將在後文提及。

再來,我們說回事務處理。

資料庫管理系統本是給另一些軟體開發者使用的,用於儲存、查詢、修改業務資料以及表達業務邏輯。既然已經有了關係模型,有了 SQL 語句來給開發者使用。作為寫程式的開發者,對儲存在硬碟上的資料做一些修改,直接改不可以嗎,為什麼還需要“事務”功能呢?難點就在於計算機系統並不太好操作,設想在售票系統售票過程中,如果我們修改了預定座位資訊,但是還沒有收錢,計算機故障了,待計算機恢復的時候,想要把這個錯誤的資訊核對出來並修復,那可就一點也不簡單了。而事務功能,則可以解決開發者這方面的顧慮。

事務的挑戰

事務功能究竟解決了哪些難題,從而讓使用者覺得世界更美好的呢?

事務功能從本質上做了兩件重要的事情,即“故障恢復”和“併發控制”。前者保證在計算機系統出現故障時,資料修改的原子性和永續性。後者保證在系統內的資料處於併發操作時,操作與操作之間可以保持隔離性。這兩者共同的目的是保證資料庫管理系統在對資料進行操作時,資料本身要保持完整性和一致性。比如,張三給李四的轉賬操作時我們要同時修改張三的賬戶和李四的賬戶,這次轉賬操作不會因為故障而導致憑空多出來錢或少了錢,也不會因為同時進行張三和王五的轉賬操作,而導致張三的錢變成負數。

“故障恢復”和“併發控制”挑戰性高嗎?是的,非常高。

先說“故障恢復”。計算機系統可能會出現什麼故障呢?儲存資料的硬碟會損壞?主機板可能突然燒壞導致系統停機?機器會斷電?網線會時斷時續?交換機會停擺,甚至夏季用電高峰期整個機房可能面臨無電可用的情況,然而儲備的柴油發電機只能支援幾個小時?上述情形都是本人曾經遇到過的情況。

事務的“故障恢復”功能就是為計算機編制好應對這些異常的手冊,通過異常處理的流程,保證原子性和永續性。目前最常見的,也是 OceanBase 使用的故障恢復的方案,即使用日誌。

日誌指的是一本記錄操作的“流水賬”。為了實現很多個資料變更操作一起成功,而記錄修改的硬碟又不能讓多個寫操作一次性完成。事務功能的做法是把一個事務內所有要做的修改轉化成在日誌系統裡的記錄,把所有要修改的內容都記錄完之後,記錄一個結束標記“搞定”,整個事務是否原子的完成,就取決於這個“搞定”標記最終是否完成。一旦最終的標記完成,就意味著事務內的所有修改都已經被記錄下來了,即使實際資料變更說因為故障沒有完成,但是當系統重新恢復後,日誌裡都記錄著這個事務需要做的所有事情,再重新做一遍即可。

保證剛剛完成的事務不會丟失的祕密就在於這個日誌。資料庫會把這個日誌記錄在不只一塊硬碟上,保證如果有一塊硬碟意外損壞了,還有其他硬碟上儲存的日誌可以用來恢復事務的修改。為了提升保障能力,比如保障當機器損壞時日誌不會丟,當機房故障時日誌不會丟,甚至城市內的多個機房都發生故障時日誌亦然不會丟,日誌需要儲存在更多的地方。OceanBase 的三地五中心架構下,日誌會儲存在三個城市的五個資料中心裡,因為有 Paxos 協議加持,所以有任意兩個城市儲存成功,事務就能提交成功,同時還保證了任何一個城市的全部機房出現故障,事務資料都不會丟。

悄悄告訴大家一個內幕訊息,目前還沒有資料庫能對地球故障進行容災,如果地球沒了,資料就都丟了, OceanBase 還需努力。

資料庫的高可用特性也和剛才說的多個副本的處理機制密切相關。最新產生的日誌通過 Paxos 協議同步到其他副本,根據部署的規格不同,可能是同一個城市的其他機房,也可能是另一個城市的機房,那麼日誌和對應的資料就在多個機房或者多個城市有備份,當出現機器或者機房故障時,根據 Paxos 協議,會啟用另外一個具有完好副本的機房,繼續提供資料庫的服務。這也是 OceanBase 資料庫高可用能力的基石。

再來,我們談談“併發控制”。

如果資料庫系統一次只處理一個使用者的一個事務,那麼就沒有“併發控制”的需要了。一個事務接著一個事務做,最安全。但是這樣太低效了,放著 CPU、硬碟、網路這些資源利用不起來。資料庫管理系統作為一種系統軟體,其內在的使命就是把計算機系統的硬體能力盡可能發揮出來,讓同樣的硬體可以更好地滿足實際業務的需要。“效率”是系統軟體與生俱來的使命,而“高效”也是複雜性的由來所在。

事務的“併發控制”其根本是在解決對於資料讀和寫的併發問題。首先,資料庫系統要決定併發控制的粒度,常見的併發控制粒度有以資料儲存頁面為單位的和以資料行為單位的。一般來說,粒度越小越好。粒度越小,相互之間的影響越小。OceanBase 採用的併發控制粒度是“行”。其次,要解決讀和寫的併發問題。這裡要分別列舉說一說。第一,讀與讀之間的併發操作;第二,寫與寫之間的併發操作;第三,讀與寫之間的併發操作。

讀與讀之間,不需要特別的處理,一份資料被讀多少次,資料還在那裡,不增不減。

寫與寫之間,不能同時進行,否則資料就會被改亂了。OceanBase 通過行級別的互斥鎖機制,即一個事務修改過的行,都會通過行鎖保護上,在事務結束之前,這些行是不允許被其他事務修改的。

讀與寫之間,多版本併發控制是目前的大勢所趨,OceanBase 採用的也是多版本併發控制。事務執行過程中更改的資料都是以新版本的形式儲存在系統中,保證更新前的資料依然在系統中,在事務提前之前,事務更改的資料都是不生效的,這時有讀取操作讀到這些行時,可以直接讀之前的資料。這是多版本併發控制的最大魅力,一行資料在做修改時,並不影響同時間進行的資料讀取。通過讀與寫之間是隔離開的設計,系統就可以儘可能“榨乾”硬體的能力。

分散式事務

下面,我們要討論分散式事務。

分散式環境給事務功能帶來了新的挑戰,所有的一切都是因為分散式系統裡的“延遲”帶來的。分散式系統什麼樣的延遲問題帶來了這麼大的挑戰呢?

延遲這件事情,伴隨著計算機系統的每一次通訊,而通訊是所有計算機操作的基礎。

CPU 訪問記憶體耗時50納秒,而同一個機房內的網路延遲是 100 微秒。也就是說,CPU 的一個從本機記憶體裡取資料的操作,從發起指令開始到把資料取到,需要 50 納秒。如果需要取的資料在另一臺機器上,即使是在同一個機房內,那也需要 100 微秒,兩者相差 2 千倍。

這種延遲差別帶來兩個影響,一是要考慮通訊的延遲,設計專門的演算法;二是一臺機器故障時,其他的機器不會立即知道,容災處理需要考慮這種新的故障場景。

考慮事務功能要解決的“故障恢復”和“併發控制”這兩件事情,在分散式環境下會遇到哪些新的挑戰呢?

先來看“併發控制”。

多版本併發控制機制需要一種表達全域性快照版本的方式,通常有兩種:一種拿的快照叫 Read View,另一種拿的快照叫 Read Version。這兩者的差別是,事務是否是在提交時才能確定版本號。如果事務不是在提交時才確定版本號,那麼快照版本需要包含所有活躍的事務列表,這是很難擴充套件的一種架構。 OceanBase 使用的是後者,即一個快照版本是一個時間戳,因此命名為 Read Version。這種模式的擴充套件能力要強很多,但是依然需要有一個全域性的單點提供時間戳。在 OceanBase 裡,提供全域性時間戳的叫全域性時間戳服務 GTS,雖然這個時間戳服務每秒可以處理幾百萬次請求,使用者的業務需求應該都能滿足,但是我們還是希望 OceanBase 的處理能力是完全可擴充套件的。OceanBase 採用了聚合方式取時間戳,每臺伺服器同一時間併發的事務可以聚合起來取時間戳,這大大降低了對於時間戳服務的請求。OceanBase TPC-C 測試時,每分鐘要執行 15 億個事務,時間戳服務支援起來完全不在話下。

對比業界另一個分散式資料庫 CockRoachDB。CRDB 採用的快照模式與 OceanBase 是一樣的,都是 Read Version 方式。但是,CRDB 沒有采用全域性時間戳服務,而是使用了混合邏輯時鐘 HLC。

HLC 的優勢是其本質是邏輯時鐘,基於通訊的方式保證有因果關係的事件之間時鐘值是有嚴格順序的,這種模式不需要一個單點來生成時間戳。但是,HLC 有一個巨大的缺陷,在資料的一致性上無法做到與傳統資料庫相同的全域性有序的事務處理,按照 CRDB 系統自己的描述,他們只能保證單行的線性一致性。

怎麼理解單行的線性一致性呢?就是資料庫只保證如果兩個事務修改的是同一行,那麼其先後關係才是明確的。反過來理解,如果兩個事務修改的是不同的行,那麼資料庫不保證其資料修改的先後順序。繞不繞?給大家舉一個這種場景下會遇到的問題就容易理解了。交易業務中的一個常見場景,如使用者下單買一件商品,有一張表儲存這個訂單是否支付完成的狀態,另一張表儲存這個訂單是否發貨的狀態。付款系統處理了使用者付款動作,並修改了訂單狀態為已支付,然後通知發貨系統,發貨系統確認訂單已付款後,發起了發貨動作,並修改訂單狀態為已發貨。已支付和已發貨是先後修改的資料,但是是在兩張不同的表裡。如果這時有另一個查詢動作來查詢這個訂單的這兩行資料,在 CRDB 中是有可能看到已發貨的狀態,同時是未支付的狀態。也就是說,看到了後面一次的修改,但是沒有看到前面一次的修改,這會給資料庫的使用者新增很多負擔,也是 OceanBase 為什麼沒有選擇這種方式的原因。

再看“故障恢復”。

在分散式環境下,事務的更新會出現在多臺機器上,用於完成“故障恢復”的事務日誌也會分別在不同的機器上記錄,這時日誌記在了多處,想要保證記錄操作的日誌全部都能記全,就需要新的流程。這個新流程就是“兩階段提交協議”。兩階段提交的新增流程就是先讓每臺機器記錄自己的操作日誌,但是先別標記最終成功,待協調者確認了所有操作日誌都記錄成功後,再記下事務提交成功的記錄,這就保證了日誌記錄原子成功的特性。

剛才描述的是經典兩階段提交協議的流程,而 OceanBase 的極致優化,則讓兩階段提交協議可以在更短的時間內完成。OceanBase 的策略是不依賴協調者最終記的事務成功日誌,而是依賴每一個參與者上記錄的操作日誌,在兩階段執行過程中如果出現了系統故障,那麼由參與者互相校驗事務的日誌是否記全了,最終依然可以通過確認所有的參與者都記全了各自的操作日誌,來確認事務最終提交的狀態。如果不是所有人都記全了,那麼事務就沒有完成提交,最終就會呈現回滾狀態。

OceanBase 的兩階段提交協議將事務的提交延遲從傳統協議中三次日誌同步延遲減小到只有一次日誌同步延遲,極大提高了事務提交的效率。

繼續對比 CRDB。與傳統資料庫和 OceanBase 有很大差別的一點,CRDB 的整個事務持久化模型由 KV 系統完成,事務不再操作獨立的日誌系統,所以 CRDB 失去了用日誌系統記錄系統變更的機會,完全依賴於 KV 系統的操作。從 CRDB 的設計原則來看,這是在簡化分散式系統的複雜度,但是這個簡化也引入了大量的負擔。在 CRDB 中,事務提交時依然要保證事務內的修改在故障時的原子性。但是,事務內不同的修改是直接操作 KV 中的對應的行,CRDB 要保證事務內修改的所有行原子的生效,相當於,每一個行都是 CRDB 事務的參與者,雖然最終也能完成事務“故障恢復”的工作,但是開銷很大。

總結

時至今日,事務特性不只在資料庫管理系統中使用,也被應用於其他系統裡以描述類似的需求,比如最新的 Intel 伺服器 CPU 支援以事務特性來訪問記憶體,這就把事務的原子性和併發控制引入了記憶體系統中。這麼做的好處是可以讓程式開發者更方便地使用記憶體來表達複雜的修改邏輯。

事務的核心就是把複雜的操作邏輯隱藏在系統內部,給使用人員暴露出簡單的介面,讓使用的人更方便。把複雜留在系統內,把簡單留給使用者,這是資料庫系統的最大價值,也是 OceanBase 各種功能開發中秉承的原則。

----------


【彩蛋環節】

QA: 結合使用者關注的14個問題,顏然老師瞭解答,具體問答見下,希望能給到大家一點幫助。


問1、OceanBase 作為一款分散式資料庫,其內部是如何界定一個事務是屬於分散式還是屬於單機事務,比如以下情況:

a. 同一個事務涉及到多個副本在同一個 observer 節點

b. 同一個事務涉及的多個副本在不同的 observer 節點

答:OceanBase  是按分割槽區分是否為分散式事務。Ocean Base  會自動追蹤一個事務內的修改,到事務最終執行 COMMIT 命令時,如果發現修改都在一個分割槽上,就會通過分割槽內的一階段提交邏輯完成事務原子提交,如果修改的內容出現在多個分割槽,就會走兩階段提交。


問2、OceanBase 作為一個分散式資料庫是如何做到交換機級故障後,服務快速恢復的?

答:OceanBase 通過多副本來容災,如果要容交換機故障,只需要跨交換機部署 OceanBase 的多個副本,多個副本通過 Paxos 協議保證一致性。如果交換機出現故障,只要故障的交換機之外還有剩下多數的副本,這些副本會重新選主並恢復資料庫服務。


問3、OceanBase 分散式事務的兩階段提交優化為一次落盤兩次 RPC,能否具體講講故障情況下怎麼保證一致性?

答:事務的所有修改依然是依賴日誌來進行持久化,OceanBase 的優化是讓所有參與者同時記錄日誌,只要這次日誌都記錄成功了,事務的所有變更就是完整的,根據這些日誌裡記錄的修改,就能恢復事務內所有變更,如果因為故障有參與者沒有記錄成功,那麼識別出這種情況後,就走事務的回滾邏輯,將事務內的所有修改回滾掉。所以,整體只需要依賴參與者的一次日誌持久化就能保證前面的邏輯。兩次 RPC 通訊,就是用來確認所有參與者都持久化成功,以及告訴所有參與者事務最終是否成功。


問4、請問一下 OceanBase 多版本控制,同個主鍵不同版本資料是如何組織的,是存在同一個樹裡還是怎麼實現?

答:一共有兩種組織方式:在記憶體中和硬碟上。記憶體 MemTable 是 btree 組織的行結構,行內多版本是連結串列結構,硬碟 SSTable 中是按照行資料和行內的多版本進行連續儲存。


問5、能介紹下 spanner 裡面時間相關的東西嗎?

答:spanner 的 TrueTime 本質上是各臺伺服器機器在普通的 wall clock 上加了一個誤差值,要保證因果關係時,就要等完使用的時間戳對應的誤差值。


問6、OceanBase 分散式事務的內部類似一個優化後的 XA 方案,其對事務查詢還有其他優化嗎?比如說 prepare 後,對查詢可以直接讀取,但是對於寫操作還是需要二階段非同步完成後才可以寫?是否提供微服務級的分散式事務協調?外部 XA 呼叫?或者是其他事務解決方案?

答:OceanBase 現在也支援通過 XA 協議與其他系統做聯合事務,在這個使用模式下,OceanBase 就是 XA 裡的一個 RM ,只是 OceanBase 這個 RM 內部還是會通過兩階段協議保證自己內部的分散式事務的原子性。相當於是級聯的兩層兩階段提交。XA 協議本身不解決併發控制的問題,只解決原子提交。如果 XA prepare 後就允許讀取的話,相當於沒有併發控制,可能出現一些事務的資料問題,比如一個 RM 的 XA prepare 即使成功,其他 RM可能失敗,最終事務還會回滾,即剛被讀取的資料就又被回滾掉了。微服務使用 XA 來解決事務的需求是一種較優的方向,相比較外部的事務系統,X 對業務開發最為友好。


問7、請問 OceanBase 支援的隔離等級有哪些呢?

答:OceanBase 的 mysql 模式支援 rc rr s、oracle 模式支援 rc s ,和對應相容的系統一致。


問8、請問 OceanBase 是通過行級鎖還是 occ 的方式來處理事務衝突呢?

答:OceanBase 實現的是行級別鎖,使用悲觀鎖的方式處理寫寫衝突。


問9、跨機房,尤其是跨 IDC,網路 IO 就成為不可忽視的效能瓶頸,一般都是非同步化解決效能問題,OceanBase 是如何做到解決效能瓶頸的同時又保證查詢的實時性?

答:這種跟部署和使用方式有關係。如果資料庫的請求本身涉及大量跨機的處理,一般最好是把這種處理聚集在一個機房內,利用機房內的低延遲網路處理資料。只利用跨機房和跨 IDC 做副本間的資料同步,保證高可用,副本同步只同步修改日誌,並且是批量聚合的方式,處理能力不受延遲影響。


問10、使用多地多中心時,主副均勻分佈在各個 zone,網路抖動頻繁,會多次發生故障切換嗎?是否會造成資料不一致?

答:如果 SQL 處理就要跨機房,那麼網路抖動會導致處理變慢甚至超時,但資料不會不一致。


問11、

1.OceanBase 是單點授時還是多點授時,異地多機房的場景下對效能有沒有影響?

答:單點授時,異地多機房同時服務會有延遲大的影響。

2.兩階段提交簡化成一階段提交,具體方案能否說一下?和 CRDB 的並行提交是否為同一概念?

答:OceanBase 的最佳實踐是利用多租戶的能力,單個租戶在一個地域服務,利用跨地域同步做容災。多個租戶可以分佈在不同的地域提供服務。


問12、請問 gts 是如何維護可靠性的,如果所提供的 gts 伺服器故障了 OceanBase 是如何保證系統正常執行的?

答:GTS 本身也依賴 Paxos 的多副本提供高可用。


問13、 OceanBase 對於死鎖檢測有什麼措施嗎? 如果是超時機制的話,對於長事務有特別處理嗎?

答:OceanBase 最新的版本實現了分散式的死鎖檢測,同時保留超時機制,作為應用可選的功能。


問14、

1、2PC 中,事務的協調者 crash 後,事務的參與者可以相互通訊協商。用的協議是什麼?

答:在 OceanBase 內部還是重建了記憶體中的兩階段狀態機,只是在狀態機中新增了一些協議,讓參與者可以來驅動建立。

2、具體是怎麼參與驅動的呢?

OceanBase 內事務的兩階段狀態機本來就是參與者來負責完成的,一般是第一個參與者會在記憶體裡構建並記錄其他參與者的狀態。

最後的最後,您有任何疑問都可以通過以下方式聯絡到我們~

聯絡我們

歡迎廣大 OceanBase 愛好者、使用者和客戶隨時與我們聯絡、反饋,方式如下:

深入淺出事務的本質,附 OceanBase 事務解析14問!


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70005215/viewspace-2879041/,如需轉載,請註明出處,否則將追究法律責任。

相關文章