TPC-C是TPC組織(國際事務(wù)性能委員會(huì ))制定的關(guān)于商品銷(xiāo)售的訂單創(chuàng )建和訂單支付等的基準測試標準,是數據庫聯(lián)機交易處理系統的權威基準測試標準。
螞蟻金服自研的分布式關(guān)系數據庫OceanBase獲得TPC-C測試第一名后,引起了大量關(guān)注,今天,我們邀請了OceanBase的核心研發(fā)人員對本次測試做專(zhuān)業(yè)的技術(shù)解讀。
一、OceanBase如何做TPC-C測試
有機會(huì )挑戰TPC-C測試相信是所有數據庫內核開(kāi)發(fā)人員的夢(mèng)想,但TPC-C測試標準非常復雜。由于這是國產(chǎn)數據庫同時(shí)也是分布式數據庫第一次沖擊這個(gè)榜單,為了完成這次挑戰,OceanBase團隊前后準備時(shí)間超過(guò)一年。
前期準備
TPC-C測試首先需要找到官方唯一認證的審計員來(lái)對測試進(jìn)行審計監察,他們對這次OceanBase的審計也相當重視,全世界僅有的三個(gè)審計員這次就有兩個(gè)參與到測試審計工作中。
測試系統
目前市面上基本找不到一個(gè)能夠開(kāi)箱即用的符合TPC-C標準的測試工具。以目前各個(gè)廠(chǎng)商PoC環(huán)境最常遇到的benchmarksql為例,可以說(shuō)只是模擬TPC-C壓力模型的壓測工具,連最基本的數據導入都不合規,大量的字符串生成未保證全局隨機,缺乏壓測階段最基本的think time、keying time這些基本配置導致極小的數據量就能跑出很高的tpmC,最關(guān)鍵的是它將測試模型大大簡(jiǎn)化為工具直連DB測試,完全沒(méi)有遵守TPC-C測試標準規范。
在標準定義中,測試系統可以分為RTE(Remote Terminal Emulator)和SUT兩部分,但實(shí)際上從角色上看SUT可以進(jìn)一步拆分為兩部分:WAS(web application server)和DB Server。
這其中DB Server是每個(gè)測試廠(chǎng)商的數據庫服務(wù);RTE扮演的角色是測試模型中的客戶(hù)終端,事務(wù)的觸發(fā)、RT的統計等都在這里完成;標準明確要求每一個(gè)用戶(hù)terminal都必須保持一個(gè)長(cháng)連接,顯然在海量Warehouse時(shí)DB是無(wú)法承受這么多連接的,WAS就是RTE和DB之間橋梁,標準定義可以使用連接池,在保證對應用透明的情況下它可以做所有請求的管理。
這三個(gè)角色中,WAS和DB是必須商業(yè)化可購買(mǎi)且提供支付服務(wù)的,OceanBase這次是使用了OpenResty作為WAS供應商。而RTE則一般由各個(gè)參測廠(chǎng)商自行根據標準實(shí)現,但所有實(shí)現代碼必須經(jīng)過(guò)審計的嚴格審計,OceanBase這次完整的實(shí)現了一整套完全合規的RTE,并且支持在大規模測試系統中部署。要知道在實(shí)際的TPC-C測試流程中,不只是對DB端能力的考驗,RTE端同樣存在極大的資源消耗和壓力。以這次6088w tpmC測試結果看,我們一共在64臺64c128G的云服務(wù)器上運行了960個(gè)RTE客戶(hù)端,來(lái)模擬總計47942400個(gè)用戶(hù)terminal,最后還需要基于這么多RTE統計結果進(jìn)行一致性和持久化審計驗證。
雖然只是測試客戶(hù)端,但RTE的中同樣有大量的可能導致最后測試失敗的小細節,比如大家可能注意不到的所有事務(wù)都因為用了web端模擬終端后需要增加的100毫秒rt,又比如為了模擬用戶(hù)終端輸出顯示的100毫秒延時(shí)。
測試規劃
TPC-C從來(lái)都不是一個(gè)簡(jiǎn)單的測試,它很科學(xué)并沒(méi)有給出強制的軟硬件配置,只是給出測試規范和各種審計檢查限制標準,所有數據庫廠(chǎng)商可以根據自己的特性充分調優(yōu)來(lái)拿到一個(gè)最好的性能或性?xún)r(jià)比。但這同時(shí)也對所有參測廠(chǎng)商提出了一個(gè)巨大的難題,如何對已有的資源進(jìn)行合理規劃來(lái)保證順利完成一次對TPC-C榜單的沖擊。
1. 硬件選型,這里不僅要對數據庫服務(wù)器選型,還需要對RTE以及WAS服務(wù)器選型。這之前需要先期進(jìn)行大量的測試和調優(yōu),來(lái)摸出在保證性?xún)r(jià)比的前提下每個(gè)角色服務(wù)器的資源配置是多少剛好。這次OceanBase測試最大的優(yōu)勢就是全部使用了云化資源,我們不需要再關(guān)注最底層機房、機柜、布線(xiàn)這些細節,只需要通過(guò)快速的規格調整來(lái)拿到我們需要的機型。
2. 參數選擇,如何選擇合適的配置參數是一個(gè)非常令人頭疼的問(wèn)題。舉個(gè)例子,一個(gè)最典型的問(wèn)題就是我們最終要跑多少個(gè)Warehouse,每個(gè)數據庫服務(wù)器上承載多少Warehouse。TPC-C標準為了盡可能模擬真實(shí)業(yè)務(wù)場(chǎng)景,通過(guò)每個(gè)事務(wù)限定不同的think time和keying time保證了一個(gè)warehouse的數據最多能夠提供12.86tpmC值,因此數據庫廠(chǎng)商想要拿到更高的成績(jì)就必須裝載更多的warehouse,但是另一方面單機的存儲空間又有預計80%(經(jīng)驗值)需要預留給60天增量存儲。在分布式數據庫架構下,為了能讓每個(gè)數據庫服務(wù)器跑滿(mǎn)又能充分利用本地存儲空間,讓每個(gè)服務(wù)器的CPU、內存、IO能力、存儲空間的資源最大化利用,我們前后調整優(yōu)化了近一個(gè)月時(shí)間。
性能壓測
最受關(guān)注的性能壓測部分在TPC-C標準中規定了以下三個(gè)狀態(tài):
1. Ramp-up,標準允許每個(gè)數據庫進(jìn)行一定時(shí)間的預熱來(lái)達到穩定狀態(tài),但是ramp-up階段的所有配置必須和最終報告配置保持一致。
2. Steady state,保證ACID及可串行化隔離級別前提下,數據庫需要能夠以最終報告tpmC值在穩定狀態(tài)無(wú)任何人工干預前提下保持運行8小時(shí)以上,每隔半小時(shí)需要完成一次checkpoint。
3. Measurement Interval,標準規定了需要能夠支持8小時(shí)穩定運行,但性能采集階段只需要保設置2小時(shí)以上即可。這個(gè)階段還需要保證累計tpmC波動(dòng)不能超過(guò)2%,并且必須完成至少4個(gè)以上的checkpoint。
所以之前一般數據庫進(jìn)行性能壓測一般是以下的流程,先進(jìn)行一段時(shí)間的預熱到達穩態(tài),等待穩定運行一段時(shí)間并完成一個(gè)checkpoint后開(kāi)始進(jìn)入2小時(shí)的性能采集階段。
而OceanBase這次是使用了TPC-C測試迄今以來(lái)最嚴苛的一個(gè)流程來(lái)完成這個(gè)性能測試的,我們首先使用了10分鐘進(jìn)行預熱,然后在6088w tpmC穩態(tài)保持運行25分鐘并完成一個(gè)檢查點(diǎn),再繼續跑了完整的8小時(shí)性能壓測采集階段,總耗時(shí)超過(guò)8個(gè)半小時(shí),中間性能最大波動(dòng)不到0.5%,最終結果也讓審計員異常興奮。
整個(gè)性能測試前后,審計員還需要進(jìn)行數據及事務(wù)隨機分布檢查,簡(jiǎn)單說(shuō)來(lái)就是大量全表掃描和統計sql,最大的一條sql需要訪(fǎng)問(wèn)超過(guò)萬(wàn)億行的order_line表結果,可以算是TPC-C里的“TPC-H測試”?,F場(chǎng)審計第一次遇到這些sql時(shí)我們也大量的出現sql執行超時(shí)情況,但后續基于OceanBase2.2版本最新的并行執行框架我們還是很快搞定了這些大sql,所以要順利完成TPC-C測試并不能只是一個(gè)偏科生,保持自身沒(méi)有短板才是真正意義上的通用關(guān)系數據庫,從這點(diǎn)上說(shuō)Oracle仍是OceanBase學(xué)習的榜樣。
ACID
1. A測試,通過(guò)提交和回滾payment事務(wù)來(lái)確認數據庫對原子性支持,和I測試一樣,OceanBase的A測試跑了兩遍,分別應對分布式事務(wù)和本地事務(wù)。
2. C測試,標準里的C測試一共包含12個(gè)case,前四個(gè)是必須要完成驗證的,每個(gè)case其實(shí)都可以認為是一個(gè)復雜的大sql,而對于分布式數據庫來(lái)說(shuō)重點(diǎn)是需要始終保證全局一致。
3. I測試,標準要求TPC-C模型里5個(gè)事務(wù)除了StockLevel事務(wù)都需要滿(mǎn)足最高的可串行化隔離級別,并構造了9個(gè)case來(lái)驗證隔離性。對于分布式數據庫而言,這個(gè)要求并沒(méi)有那么容易實(shí)現,所幸OceanBase在2.x版本中提供了全局時(shí)間戳的支持,所以的I測試都在審計員的特別要求下跑完了全本地和全分布式兩種模式的兩輪測試,這也應該是TPC-C測試中首次有數據庫廠(chǎng)商需要做兩輪I測試跑18個(gè)case的,也許在不久后TPC-C標準定義也會(huì )因為OceanBase的這次測試而帶來(lái)針對分布式數據庫的相關(guān)更新。
4. D測試,OceanBase在這個(gè)場(chǎng)景其實(shí)相對傳統數據庫是有較大天生優(yōu)勢的,OceanBase每個(gè)Warehouse數據有兩份數據三份日志,通過(guò)paxos強同步,保證RPO=0的前提下只有秒級RTO。
面對D測試標準中最嚴格的一項-部分存儲介質(zhì)永久故障,OceanBase還使用了最嚴苛的測試場(chǎng)景,在使用超出標準要求的全量6000W tpmC壓力下,我們強行銷(xiāo)毀了一個(gè)云服務(wù)器節點(diǎn),整體tpmC在兩分鐘內恢復到6000w并持續跑到測試時(shí)間結束,這些表現都是遠遠超過(guò)TPC-C規范要求的,相比較而言其它傳統數據庫基本面對有日志的存儲介質(zhì)故障D測試場(chǎng)景都是依賴(lài)磁盤(pán)RAID來(lái)恢復,OceanBase應該算是首個(gè)沒(méi)有raid完全依賴(lài)數據庫自身恢復機制完成全部D測試的數據庫廠(chǎng)商了。
同時(shí)我們在D測試中是連續殺掉了兩臺服務(wù)器節點(diǎn),首先殺掉一個(gè)數據節點(diǎn),等待tpmC恢復且穩定5分鐘后,再次殺掉了rootserver leader節點(diǎn),tpmC仍然快速恢復。
二、TPC-C基準測試之SQL優(yōu)化
對TPC-C有所了解人都知道,TPC-C是一個(gè)典型的OLTP (On-Line Transaction Processing) 場(chǎng)景測試,考察的是數據庫在高并發(fā)壓力場(chǎng)景下的事務(wù)處理能力,最終的性能指標以tpmC(transaction per minute,也即每分鐘系統處理TPC-C模型中的new order事務(wù)的數量)和平均到每tpmC的系統成本作為衡量標準。在OLTP場(chǎng)景中,每條請求的響應時(shí)間都是極短的。因此,各個(gè)數據庫廠(chǎng)商在進(jìn)行TPC-C測試時(shí),都會(huì )盡一切可能將每一個(gè)操作時(shí)間壓縮到最短,不夸張的說(shuō),在TPC-C的測試中,一些關(guān)鍵操作的優(yōu)化往往需要細化到CPU指令級。
在進(jìn)入我們的主題前,我們先來(lái)談?wù)凾PC-C中的事務(wù)模型,主要分為五種事務(wù),訂單創(chuàng )建、訂單支付、訂單查詢(xún)、訂單發(fā)貨以及庫存查詢(xún),這五種事務(wù)按照一定的比例發(fā)生,測試最終衡量的是每分鐘訂單創(chuàng )建事務(wù)的執行個(gè)數。大家知道,每一個(gè)數據庫的事務(wù),其實(shí)就是由一定邏輯關(guān)系關(guān)聯(lián)的若干條SQL語(yǔ)句組成,他們在一個(gè)事務(wù)中,要么全部成功,要么全部失敗,這個(gè)在數據庫中稱(chēng)為“原子性”,也就是ACID中的“A”。那么TPC-C中的一個(gè)事務(wù)的耗時(shí)大約是多久呢?看一下報告就很清楚了——只有十幾個(gè)毫秒??紤]到一個(gè)事務(wù)由多條SQL構成,那么每一條SQL的平均耗時(shí)都不到1毫秒!
在C/S(client-server)模型中,一條SQL語(yǔ)句從發(fā)起到執行完成需要經(jīng)歷從客戶(hù)端輸入、網(wǎng)絡(luò )傳輸、SQL優(yōu)化、執行、結果返回到客戶(hù)端這樣一個(gè)流程。而具體每一條SQL的執行可能只是做一個(gè)字段的更新,所需要的執行時(shí)間是非常短暫的,從整個(gè)鏈路的角度來(lái)看,大量的時(shí)間會(huì )花費在與客戶(hù)端的交互過(guò)程中,造成資源的浪費和耗時(shí)的增加。那么如何解決這個(gè)問(wèn)題的呢?
答案就是使用存儲過(guò)程。
存儲過(guò)程 所謂“存儲過(guò)程”就是數據庫為用戶(hù)提供的一種面向過(guò)程的編程語(yǔ)言?;谶@種語(yǔ)言,用戶(hù)可以將應用程序的邏輯封裝為一個(gè)可調用的過(guò)程(procedure)存放在數據庫中并隨時(shí)進(jìn)行調用。通過(guò)這種方式,用戶(hù)可以將本來(lái)需要與數據庫進(jìn)行多次交互才能完成的工作通過(guò)一次交互完成,省去了中間網(wǎng)絡(luò )的傳輸和等待時(shí)間(參見(jiàn)圖1)。假如一條事務(wù)的網(wǎng)絡(luò )開(kāi)銷(xiāo)平均是30%,也就是說(shuō)30%的CPU都花在了網(wǎng)絡(luò )的收發(fā)和解析上。那么在6千萬(wàn)規模tpmC測試中節省下來(lái)30%的CPU資源換算成系統處理能力是驚人的。使用存儲過(guò)程還可以帶來(lái)事務(wù)響應時(shí)間的下降,導致數據庫內核中事務(wù)鎖的臨界區縮短,間接的提升了系統CPU利用率,整個(gè)吞吐量也隨之提高。存儲過(guò)程在縮短應用端的等待耗時(shí)上同樣有很大作用。
圖1 傳統的C/S模型與使用存儲過(guò)程的執行方式對比
在TPC-C中,存儲過(guò)程對于整個(gè)系統的執行效率提升是至關(guān)重要的。OceanBase 的2.2版本不僅全面支持了存儲過(guò)程,而且對存儲過(guò)程的執行效率做了大量極致的優(yōu)化。
編譯執行
存儲過(guò)程作為一種面向過(guò)程的高級語(yǔ)言,需要轉換成機器碼才能夠執行。這個(gè)過(guò)程一般可以分為“編譯執行”和“解釋執行”兩種,一般來(lái)說(shuō),編譯執行相比解釋執行有代碼優(yōu)化充分、執行效率高等特點(diǎn)。OceanBase利用近兩年逐漸成熟的LLVM編譯器框架實(shí)現了一個(gè)支持存儲過(guò)程的編譯器,通過(guò)動(dòng)態(tài)編譯(Just-in-Time Compilation)的方式將存儲過(guò)程翻譯成高效的二進(jìn)制可執行代碼,在執行效率上獲得了數量級的提升。同時(shí),過(guò)程中LLVM框架將存儲過(guò)程轉換為與機器無(wú)關(guān)的中間代碼,使得存儲過(guò)程也自然而然地獲得了跨平臺的編譯執行能力,LLVM內置的優(yōu)化過(guò)程確保我們在各種不同的硬件平臺上都可以獲得正確、高效的可執行代碼。
Array Binding
另外一個(gè)在TPC-C測試中發(fā)揮了重要作用的功能就是對DML語(yǔ)句進(jìn)行批量處理的能力,在Oracle中該功能也稱(chēng)為“Array Binding”。一條SQL在數據庫中的執行過(guò)程大致上可以分為“計劃生成”和“執行”兩個(gè)階段。盡管我們對SQL的執行計劃做了高速緩存,但找到一個(gè)合適的執行計劃在整個(gè)執行過(guò)程中仍然是比較耗時(shí)的一個(gè)部分。那有沒(méi)有辦法省去這個(gè)時(shí)間呢?當一組SQL的執行計劃完全一樣而只有執行參數不同時(shí),在存儲過(guò)程中我們可以通過(guò)特定的語(yǔ)法將他們的執行做成一個(gè)批量處理的過(guò)程,此時(shí)“計劃生成”只需要做一次即可,這就是所謂的“Array Binding”。
在A(yíng)rray Binding中,數據庫會(huì )首先找到需要使用的計劃,然后執行該計劃,并在每次執行完畢后,重新執行參數綁定(binding)的過(guò)程。打個(gè)比方,這就像是在一個(gè)C語(yǔ)言的for循環(huán)中,反復賦值而不是重新定義一個(gè)數據結構。Array Binding的使用受用戶(hù)控制,需要在存儲過(guò)程中使用FORALL關(guān)鍵字來(lái)觸發(fā)這一功能,在TPC-C的測試過(guò)程中,我們多次使用了Array Binding來(lái)提升系統的處理能力,效果非常明顯。
Prepared Statement與執行計劃緩存
Prepared Statement是一種二進(jìn)制的請求交互協(xié)議,可以大大降低系統的交互成本。OceanBase不僅支持用戶(hù)程序與數據庫間使用Prepared Statement, 也支持在存儲過(guò)程引擎調用SQL引擎執行時(shí)使用這種交互方式。存儲過(guò)程在對SQL進(jìn)行一次Prepare操作并獲取唯一id后, 后續的每次執行僅需要傳入該id和對應的參數,系統可以通過(guò)高速緩存找到對應的存儲過(guò)程或SQL計劃開(kāi)始執行。該過(guò)程相比使用SQL文本的交互方式,省去了大量請求文本解析的CPU開(kāi)銷(xiāo)。
OceanBase內部實(shí)現了高速緩存來(lái)緩存存儲過(guò)程的可執行代碼及SQL執行計劃,不同參數的存儲過(guò)程和SQL可以通過(guò)這一高速緩存快速獲取需要的執行對象, 耗時(shí)一般在幾十微秒以?xún)? 有效避免了重新編譯帶來(lái)的毫秒級的延遲和CPU消耗。
可更新視圖
在OLTP場(chǎng)景中,通過(guò)減少應用與數據庫的交互次數來(lái)實(shí)現性能提升的例子很多,可更新視圖就是其中之一。我們常見(jiàn)的數據庫視圖通常是只讀的,通過(guò)定義視圖,用戶(hù)可以定義自己感興趣的數據以及其獲取接口,但視圖同時(shí)也可以作為更新操作的入口,比如在TPC-C的new order創(chuàng )建場(chǎng)景中,應用需要得到商品信息,更新庫存并得到更新后的值。一般可以通過(guò)兩條SQL實(shí)現這一過(guò)程:
select i_price,i_name, i_data from item where i_id = ?;
UPDATE stock
SET s_order_cnt = s_order_cnt + 1,
s_ytd = s_ytd + ?,
s_remote_cnt = s_remote_cnt + ?,
s_quantity = (CASE WHEN s_quantity< ? + 10 THEN s_quantity + 91 ELSE s_quantity END) - ?
WHERE s_i_id = ?
AND s_w_id = ?
RETURNING s_quantity, s_dist_01,
CASE WHEN i_data NOT LIKE'%ORIGINAL%' THEN 'G' ELSE (CASE WHEN s_data NOT LIKE '%ORIGINAL%' THEN 'G'ELSE 'B' END) END
BULK COLLECT INTO ...;
但通過(guò)建立一個(gè)可更新視圖:
CREATE VIEW stock_item AS
SELECT i_price, i_name, i_data, s_i_id,s_w_id, s_order_cnt, s_ytd, s_remote_cnt, s_quantity, s_data, s_dist_01
FROM stock s, item i WHERE s.s_i_id =i.i_id;
我們就可以通過(guò)一條語(yǔ)句更新庫存并得到商品和庫存信息:
UPDATE stock_item
SET s_order_cnt = s_order_cnt + 1,
s_ytd = s_ytd + ?,
s_remote_cnt = s_remote_cnt + ?,
s_quantity = (CASE WHEN s_quantity< ? + 10 THEN s_quantity + 91 ELSE s_quantity END) - ?
WHERE s_i_id = ?
AND s_w_id = ?
RETURNING i_price, i_name, s_quantity,s_dist_01,
CASE WHEN i_data NOT LIKE'%ORIGINAL%' THEN 'G' ELSE (CASE WHEN s_data NOT LIKE '%ORIGINAL%' THEN 'G'ELSE 'B' END) END
BULK COLLECT INTO ...;
這樣就省去了一條語(yǔ)句的交互,并且更新邏輯更加直觀(guān)??筛乱晥D允許用戶(hù)可以像普通表一樣操作視圖,但不是所有視圖都可以定義為可更新視圖。比如帶distinct, group by的視圖,具體更新哪些行語(yǔ)義是不明確的,因此不能允許更新。具體到上面的stock_item兩表join的視圖,需要滿(mǎn)足所更新表的unique key在join之后保持unique(key-preserved table),即item.i_id必須是唯一的這個(gè)前提。
需要強調,TPC-C規范禁止使用物化視圖,而可更新視圖并沒(méi)有改變底層數據表格的存儲形式,是符合規范的。
因為T(mén)PC-C的設計原則是盡可能的“真實(shí)”反應一個(gè)OLTP系統的運行場(chǎng)景,我們所做的很多優(yōu)化都具有廣泛的適用性。例如,對于一個(gè)高并發(fā)的OLTP系統來(lái)說(shuō),大部分的SQL請求的耗時(shí)是非常短的,采用純粹的C/S交互模型的后果必然使系統的時(shí)間浪費在應用與數據庫的頻繁交互中,而使用存儲過(guò)程可以大大緩解這種交互的耗時(shí),并且增強系統對于網(wǎng)絡(luò )抖動(dòng)的免疫力,這種核心能力對于一個(gè)分布式OLTP數據庫是不可或缺的。
在這次的TPC-C測試中,我們采用了OceanBase 2.0版本開(kāi)始支持的Oracle兼容模式,存儲過(guò)程和SQL全部使用了兼容Oracle的數據類(lèi)型和語(yǔ)法,這樣做也是為了在追求極致優(yōu)化的同時(shí),確保產(chǎn)品迭代可以沿著(zhù)通用和正規的方向發(fā)展。
三、TPC-C基準測試之數據庫事務(wù)引擎的挑戰
OceanBase這次TPC-C測試與榜單上Oracle和DB2等其他數據庫在硬件使用上有非常大的不同,OceanBase的數據庫服務(wù)器使用的是204+3臺型號是ecs.i2.16xlarge阿里云ECS服務(wù)器,其中204臺作為data node,還有3臺作為root node,每位讀者都可以在阿里云網(wǎng)站上輕松按需購買(mǎi)。如果讀者翻看Oracle和DB2的TPC-C測試報告會(huì )發(fā)現,這些數據庫都會(huì )使用專(zhuān)用的存儲設備,例如前最高記錄保持者Oracle在2010年的測試,使用了97臺COMSTAR專(zhuān)用的存儲設備,其中28臺用來(lái)存儲數據庫的重做日志(Redo Log)。
硬件的差異給軟件架構提出了完全不同的挑戰,專(zhuān)用的存儲設備其內部通過(guò)硬件冗余實(shí)現了設備自身的可靠保證,數據庫軟件在使用這樣的存儲設備時(shí)就天然的預設了數據不會(huì )丟失。但是,這種方式帶來(lái)了成本的極大消耗,專(zhuān)用的存儲設備的價(jià)格都是特別昂貴的。
OceanBase使用通用的ECS服務(wù)器提供數據庫服務(wù),并且只使用ECS機器自帶的本地硬盤(pán)做數據存儲,這是最通用的硬件條件。但是這種方式對軟件架構提出了很大的挑戰,因為單個(gè)ECS服務(wù)器的不如專(zhuān)用的存儲設備可靠性高。這也對OceanBase的事務(wù)引擎提出了很大的挑戰,OceanBase是在普通的ECS服務(wù)器上就可以實(shí)現ACID特性。
TPC-C測試是對事務(wù)ACID特性有完整并且嚴格的要求。下面分別介紹OceanBase針對事務(wù)ACID的特性的解決方案。
Paxos日志同步保證持久性(Durability)
OceanBase數據庫的事務(wù)持久性(Durability)保證是依賴(lài)事務(wù)重做日志(Redo Log)的持久性來(lái)達成的。所有的 Redo Log 會(huì )實(shí)時(shí)強同步到另外兩臺數據庫服務(wù)機器上,包含產(chǎn)生 Redo Log 的機器在內,總共會(huì )有三臺機器在硬盤(pán)中持久化 Redo Log。
OceanBase 采用了 Paxos 一致性同步協(xié)議來(lái)協(xié)調這三臺機器上 Redo Log 的持久化,Paxos協(xié)議采用超過(guò)半數(也叫“多數派”)成功即算成功的算法(三個(gè)副本時(shí),兩個(gè)成功即超過(guò)半數),當其中兩臺機器完成持久化后,事務(wù)即可完成提交,剩下的一臺機器的 Redo Log 在通常情況下,也是立即就持久化完成了。但如果這臺機器碰巧出現異常,也不會(huì )影響事務(wù)的提交,系統會(huì )在其恢復后自動(dòng)補齊所缺失的 Redo Log。如果機器永久故障,系統會(huì )將故障機器所應負責同步的數據分散給集群內的其他機器,這些機器會(huì )自動(dòng)補齊所缺失內容,并跟上最新的 Redo Log 寫(xiě)入。
使用Paxos一致性協(xié)議的最大優(yōu)勢是數據持久化和數據庫服務(wù)可用性的完美平衡。當使用三個(gè)副本時(shí),任何時(shí)候壞掉一個(gè)副本時(shí)至少還有另一個(gè)副本有數據,并且寫(xiě)入還可以持續,因為還剩下兩個(gè)副本,后續的寫(xiě)入也不受影響。
所以,OceanBase 在保證了事務(wù)持久性的同時(shí),也大大提升了數據庫的連續服務(wù)能力。TPC組織的審計員在現場(chǎng)審計OceanBase持久性能力時(shí),在客戶(hù)端持續產(chǎn)生壓力的情況下,從OceanBase集群中隨意挑選了一臺機器做了強制斷電操作,發(fā)現數據庫的數據不僅沒(méi)丟,數據庫不需要任何人工干預還能持續的提供服務(wù),審計員們都很吃驚,并且對OceanBase大為贊賞。
依靠自動(dòng)兩階段提交解決原子性(Atomicity)
TPC-C測試模型的五種事務(wù)中的“訂單創(chuàng )建”和“訂單支付”兩個(gè)事務(wù)分別會(huì )對很多數據做修改,是其中相對復雜的兩個(gè)事務(wù)。TPC-C標準對事務(wù)的原子性(Atomicity)是強制性的要求,要求一個(gè)事務(wù)內部對倉庫、訂單、用戶(hù)等表格的修改一定要原子的生效,不允許出現只有一半成功的情況。
OceanBase的數據是按照倉庫ID(Warehouse_ID)拆分到多臺機器上的,如果所有的事務(wù)都是發(fā)生在同一個(gè)倉庫內部,那么無(wú)論數據量有多大,事務(wù)的修改都只會(huì )涉及一臺機器的數據,也就是在一臺機器上完成事務(wù)提交,這是一種完美的線(xiàn)形擴展的場(chǎng)景。但是這不符合實(shí)際的業(yè)務(wù)場(chǎng)景,大多數的實(shí)際業(yè)務(wù)都會(huì )有很多不同維度之間的數據交互。TPC-C測試標準也是對此認真考慮,所以對于事務(wù)操作數據的隨機性規則提出了要求,最終要保證產(chǎn)生10%的“訂單創(chuàng )建”事務(wù)和15%的“訂單支付”事務(wù)要操作兩個(gè)及以上的倉庫。在OceanBase數據庫內,這樣就產(chǎn)生了跨機器的事務(wù)操作,而這必須使用兩階段提交協(xié)議來(lái)保證原子性。
OceanBase會(huì )自動(dòng)跟蹤一個(gè)事務(wù)內所有SQL語(yǔ)句操作的數據,根據實(shí)際數據修改的位置自動(dòng)確定兩階段提交的參與者,事務(wù)開(kāi)始提交時(shí),OceanBase自動(dòng)選擇第一個(gè)參與者作為協(xié)調者,協(xié)調者會(huì )給所有參與者發(fā)送Prepare消息,每個(gè)參與者都需要寫(xiě)各自的Redo Log和Prepare Log(也意味著(zhù)每個(gè)參與者各自做自己的Paxos同步),等協(xié)調者確認所有參與者的Redo Log和Prepare Log完成后,然后再給所有參與者發(fā)送Commit消息,再等所有參與者的Commit工作完成。整個(gè)協(xié)議是在事務(wù)提交過(guò)程中自動(dòng)完成,對用戶(hù)完全透明。OceanBase為每一個(gè)兩階段提交事務(wù)自動(dòng)選擇一個(gè)協(xié)調者,整個(gè)系統任何機器都可以分擔協(xié)調者工作,所以OceanBase可以將事務(wù)處理能力進(jìn)行線(xiàn)形擴展。
多版本并發(fā)控制保證事務(wù)的隔離性(Isolation)
TPC-C標準里要求“訂單創(chuàng )建”、“訂單支付”、“訂單配送”、“訂單支付”事務(wù)之間都是串行化隔離級別(Serializable)。OceanBase采用的方法是基于多版本的并發(fā)控制機制。事務(wù)提交時(shí)會(huì )申請一個(gè)事務(wù)的提交時(shí)間戳,事務(wù)內的修改以新的版本寫(xiě)入存儲引擎,并且保證之前版本的數據不受影響。事務(wù)開(kāi)始時(shí)會(huì )獲取一個(gè)讀取時(shí)間戳,整個(gè)事務(wù)內數據的讀取操作只會(huì )看到基于讀取時(shí)間戳的已提交數據。所以,事務(wù)的讀取不會(huì )遇到臟數據、不可重復讀數據以及幻讀數據。同時(shí),事務(wù)的修改會(huì )在修改的數據行上持有行鎖,保證兩個(gè)并發(fā)的修改相同行的事務(wù)會(huì )互斥。
OceanBase的全局時(shí)間戳生成器也是由多副本組成,可以獨立部署在三臺機器上,也可以像這次TPC-C評測中一樣部署在root node機器上,與root node共享資源。全局時(shí)間戳的三副本是一種極高可用的架構,任何一次時(shí)間戳的獲取操作都至少在三臺機器上的兩臺獲得了確認,所以任意一臺機器出現故障,獲取時(shí)間戳的操作不會(huì )有一點(diǎn)影響。
按照TPC-C標準,OceanBase準備了9種不同的場(chǎng)景測試有讀-讀、讀-寫(xiě)沖突時(shí)事務(wù)的隔離性,最終都完美通過(guò)了審計員的審計。
一致性保證(Consistency)
在有了上述的事務(wù)能力后,OceanBase可以完美的保證各種數據的一致性的約束。TPC-C標準里提出了12種不同的一致性測試場(chǎng)景在各種測試運行前后對數據庫內的數據進(jìn)行一致性校驗。因為OceanBase此次測試數據規模龐大,一致性校驗的SQL需要核對大量的數據,所以一致性校驗的挑戰在于校驗的SQL本身運行的效率?;贠ceanBase的并行查詢(xún)能力,發(fā)揮整個(gè)集群所有的計算資源,校驗SQL的運行時(shí)間均縮短了幾個(gè)數量級,很好的完成一致性功能的審計工作。
復制表
TPC-C測試模型中有一張商品(ITEM)表,這張表的內容是測試所模擬的銷(xiāo)售公司所有售賣(mài)的商品信息,包含了商品的名字、價(jià)格等信息。“訂單創(chuàng )建”事務(wù)執行中需要請求這張表內的數據來(lái)確定訂單的價(jià)格信息,如果商品表的數據只存放在一臺機器上,那么所有機器上發(fā)生的“訂單創(chuàng )建”事務(wù)都會(huì )請求包含商品表的機器,這臺機器就會(huì )成為瓶頸。OceanBase支持復制表功能,將商品表設置為復制表后,商品表的數據會(huì )自動(dòng)復制到集群中的每一臺機器上。
TPC-C標準不限制數據的副本數,但是不管數據的組織形式,標準里要求事務(wù)的ACID一定要保證。OceanBase使用特殊的廣播協(xié)議保證復制表的所有副本的ACID特性,當復制表發(fā)生修改時(shí),所有的副本會(huì )同時(shí)修改。并且,當有機器出現故障時(shí),復制表的邏輯會(huì )自動(dòng)剔除無(wú)效的副本,保證數據修改過(guò)程中不會(huì )因為機器故障出現無(wú)謂的等待。復制表在很多業(yè)務(wù)場(chǎng)景中都有使用,例如很多業(yè)務(wù)中存儲關(guān)鍵信息的字典表,還有金融業(yè)務(wù)中存儲匯率信息的表。
四、TPC-C基準測試之存儲優(yōu)化
TPC-C規范要求被測數據庫的性能(tpmC)與數據量成正比。TPC-C的基本數據單元是倉庫(warehouse),每個(gè)倉庫的數據量通常在70MB左右(與具體實(shí)現有關(guān))。TPC-C規定每個(gè)倉庫所獲得的tpmC上限是12.86(假設數據庫響應時(shí)間為0)。
假設某系統獲得150萬(wàn)tpmC,大約對應12萬(wàn)個(gè)倉庫,按照70MB/倉庫計算,數據量約為8.4TB。某些廠(chǎng)商采用修改過(guò)的不符合審計要求的TPC-C測試,不限制單個(gè)warehouse的tpmC上限,測試幾百到幾千個(gè)warehouse全部裝載到內存的性能,這是沒(méi)有意義的,也不可能通過(guò)審計。在真實(shí)的TPC-C測試中,存儲的消耗占了很大一部分。OceanBase作為第一款基于shared nothing架構登上TPC-C榜首的數據庫,同時(shí)也作為第一款使用LSM Tree存儲引擎架構登上TPC-C榜首的數據庫,在存儲架構上有如下關(guān)鍵點(diǎn):
1. 為了保證可靠性,OceanBase存儲了兩個(gè)數據副本和三個(gè)日志副本,而傳統的集中式數據庫測試TPC-C只存儲一份數據;
2. 由于OceanBase存儲兩個(gè)數據副本,再加上OceanBase TPC-C測試采用了和生產(chǎn)系統完全一樣的阿里云服務(wù)器i2機型,SSD硬盤(pán)的存儲容量成為瓶頸。OceanBase采用在線(xiàn)壓縮的方式緩解這個(gè)問(wèn)題,進(jìn)一步增加了CPU使用;相應地,集中式數據庫測試存儲一份數據,不需要打開(kāi)壓縮;
3. OceanBase LSM引擎定期需要在后臺做compaction操作,而TPC-C要求測試至少運行8小時(shí)且2小時(shí)之內抖動(dòng)小于2%,因此,OceanBase存儲需要解決LSM引擎后臺操作導致的抖動(dòng)問(wèn)題;
兩份數據
為了保證可靠性和不丟數據(RPO=0),有兩種不同的方案:一種方案是在硬件層面容錯,另一種方案是在軟件層面容錯。OceanBase選擇在軟件層面容錯,優(yōu)勢是硬件成本更低,帶來(lái)的問(wèn)題是需要冗余存儲多個(gè)副本的數據。OceanBase使用Paxos協(xié)議保證在單機故障下數據的強一致。在Paxos協(xié)議中,一份數據需要被同步到多數派(超過(guò)一半),才被認為是寫(xiě)入成功,所以一般來(lái)說(shuō)副本個(gè)數總是奇數,出于成本考慮最常見(jiàn)的部署規格是三副本。
三副本帶來(lái)的首要問(wèn)題就是存儲成本的上升,之前商業(yè)數據庫的TPC-C測試大多基于磁盤(pán)陣列,而TPC-C規范中明確對磁盤(pán)陣列不做容災要求,使用相對于傳統數據庫三倍的存儲空間進(jìn)行TPC-C測試顯然難以接受。
我們注意到這樣一個(gè)事實(shí),通過(guò)Paxos協(xié)議同步的只是日志,日志需要寫(xiě)三份,但數據不是,數據只需要有兩份就可以完成單機故障的容災了,當一份數據由于服務(wù)器宕機不可用時(shí),另一份數據只要通過(guò)日志把數據補齊,就可以繼續對外提供訪(fǎng)問(wèn)。
和數據存儲相比,日志的存儲量比較小。我們將數據與日志分開(kāi),定義了三種不同的副本類(lèi)型:F副本既包含數據又同步日志,并對外提供讀寫(xiě)服務(wù);D副本既包含數據又同步日志,但對外不提供讀寫(xiě)服務(wù);L副本只同步日志,不存儲數據。當F副本出現故障時(shí),D副本可以轉換為F副本,補齊數據后對外提供服務(wù)。在TPC-C測試中我們使用FDL模式進(jìn)行部署(一個(gè)F副本,一個(gè)D副本,一個(gè)L副本),使用了兩倍數據副本的存儲空間。無(wú)論是D副本還是L副本,都需要回放日志,D副本還需要同步數據,這些都是都會(huì )消耗網(wǎng)絡(luò )和CPU。 在線(xiàn)壓縮 在sharednothing架構下,OceanBase至少需要存儲兩份數據才可以滿(mǎn)足容災的要求,這意味著(zhù)OceanBase需要比傳統數據庫多耗費一倍的存儲空間。
為了緩解這個(gè)問(wèn)題,OceanBaseTPC-C測試選擇對數據進(jìn)行在線(xiàn)壓縮,Oracle數據庫中一個(gè)warehouse的存儲容量接近70MB,而OceanBase壓縮后存儲容量只有50MB左右,大幅降低了存儲空間。TPC-C規范要求磁盤(pán)空間能夠滿(mǎn)足60天數據量的存儲,對于OceanBase,由于需要保存兩份數據,雖然可靠性更好,但需要保存相當于120天的數據量,這些存儲成本都要計入總體價(jià)格。
OceanBase使用了204臺ECS i2云服務(wù)器存儲數據,服務(wù)器規格和線(xiàn)上真實(shí)業(yè)務(wù)應用保持一致。每臺服務(wù)器的日志盤(pán)1TB,數據盤(pán)接近13TB。計算兩份壓縮后的數據60天的存儲空間之后,服務(wù)器的數據盤(pán)基本沒(méi)有太多余量,從服務(wù)器的資源成本消耗來(lái)看,已經(jīng)達到了比較好的平衡。如果OceanBase的單機性能tpmC進(jìn)一步提升,磁盤(pán)容量將成為瓶頸。OceanBase LSM引擎是append-only的,它的優(yōu)勢是沒(méi)有隨機修改,能夠在線(xiàn)壓縮。無(wú)論是TPC-C測試,還是最核心的OLTP生產(chǎn)系統(例如支付寶交易支付),OceanBase都會(huì )打開(kāi)在線(xiàn)壓縮,通過(guò)CPU換存儲空間。 存儲性能平滑 TPC-C測試很大的挑戰在于在整個(gè)壓測過(guò)程中性能曲線(xiàn)要求是絕對平滑的,曲線(xiàn)上的波動(dòng)幅度不能超過(guò)2%,這對于傳統數據庫來(lái)說(shuō)都是一件困難的事情,因為這要求對于所有后臺任務(wù)的精細控制,不能由于某個(gè)后臺任務(wù)的資源過(guò)度使用導致前臺請求的阻塞積壓。而對于OceanBase而言,事情變得更為困難,因為OceanBase的存儲引擎是基于LSM Tree的,在LSM Tree要定期執行compaction操作。Compaction是個(gè)非常重的后臺操作,會(huì )占用大量CPU和磁盤(pán)IO資源,這對前臺的用戶(hù)查詢(xún)和寫(xiě)入天然就會(huì )造成影響。我們做了一些優(yōu)化,來(lái)平滑后臺任務(wù)對性能的影響,從最終的測試結果來(lái)看,性能曲線(xiàn)在整個(gè)8小時(shí)壓測過(guò)程中的抖動(dòng)小于0.5%。
分層轉儲
在LSMTree中,數據首先被寫(xiě)入內存中的MemTable,在一定時(shí)候為了釋放內存,MemTable中的數據需要與磁盤(pán)中的SSTable進(jìn)行合并,這個(gè)過(guò)程被稱(chēng)為compaction。在很多基于LSM Tree的存儲系統中,為了解決寫(xiě)入的性能問(wèn)題,通常會(huì )將SSTable分為多層,當一層的SSTable個(gè)數或者大小達到某個(gè)閾值時(shí),合并入下一層SSTable。多層SSTable解決了寫(xiě)入的問(wèn)題,但是SSTable的個(gè)數過(guò)多,會(huì )極大拖慢查詢(xún)的性能。OceanBase同樣借鑒了分層的思路,但同時(shí)使用了更加靈活的compaction策略,確保SSTable總數不會(huì )太多,從而在讀取和寫(xiě)入性能之間做了更好的平衡。
資源隔離
Compaction等后臺任務(wù)需要消耗大量的服務(wù)器資源,為了減少后臺任務(wù)對用戶(hù)查詢(xún)和寫(xiě)入的影響,我們在CPU、內存、磁盤(pán)IO和網(wǎng)絡(luò )IO四個(gè)方面對前后臺任務(wù)做了資源隔離。在CPU方面,我們將后臺任務(wù)和用戶(hù)請求分為不同的線(xiàn)程池,并按照CPU親和性做了隔離。在內存方面,對前后臺請求做了不同的內存管理。在磁盤(pán)IO方面,我們控制后臺任務(wù)IO請求的IOPS,使用deadline算法進(jìn)行流控。在網(wǎng)絡(luò )IO方面,我們將后臺任務(wù)RPC和用戶(hù)請求RPC分為不同隊列,并對后臺任務(wù)RPC的帶寬使用進(jìn)行流控
。
存儲CPU占用 TPC-C基準測試主要考察整體性能tpmC,很多人也會(huì )關(guān)注單核的tpmC。然而,這個(gè)指標只有在相同架構下才有意義。對于存儲模塊的CPU占用,有如下三點(diǎn):
1. 對于集中式架構,除了數據庫使用CPU之外,專(zhuān)用存儲設備也需要使用CPU。例如,第二名Oracle 3000多萬(wàn)tpmC的測試中,數據庫使用了108顆T3SPARC處理器,共有1728個(gè)物理核心和13824個(gè)執行線(xiàn)程,同時(shí)存儲設備使用的是Intel服務(wù)器作為機頭,總共使用了97臺服務(wù)器,194顆Intel X5670 CPU,2328個(gè)物理核心。
2. 集中式數據庫使用高可靠硬件,只需要存儲一個(gè)副本,而OceanBase通過(guò)軟件層面容錯,雖然硬件成本更低但需要兩個(gè)數據副本和三個(gè)日志副本,維護多個(gè)副本需要耗費大量CPU;
3. OceanBase在TPC-C測試和生產(chǎn)系統中都打開(kāi)了在線(xiàn)壓縮,進(jìn)一步增加了CPU使用; 因此,簡(jiǎn)單地對比OceanBase和Oracle的CPU核是不科學(xué)的,還需要算上共享存儲設備的CPU核,以及OceanBase存儲多副本和在線(xiàn)壓縮帶來(lái)的CPU開(kāi)銷(xiāo)。TPC-C推薦的方案是不關(guān)注具體的軟件架構和硬件架構,關(guān)注硬件總體成本。在OceanBase的測試中,硬件成本只占整體成本的18%左右,只考慮硬件的性?xún)r(jià)比大幅優(yōu)于集中式數據庫。
后續發(fā)展
OceanBase的優(yōu)勢在于采用分布式架構,硬件成本更低,可用性更好且能夠做到線(xiàn)性擴展,但是,OceanBase單機的性能離Oracle、DB2還有不小的差距,后續需要重點(diǎn)優(yōu)化單機存儲性能。另外,OceanBase的定位是在同一套引擎同時(shí)支持OLTP業(yè)務(wù)和OLAP業(yè)務(wù),而目前OceanBase的OLAP處理能力還不如Oracle,后續需要加強存儲模塊對大查詢(xún)的處理能力,支持將OLAP算子下壓到存儲層甚至在壓縮后的數據上直接做OLAP計算。
作者:陽(yáng)振坤(OceanBase創(chuàng )始人)曹暉(OceanBase技術(shù)專(zhuān)家)陳萌萌(OceanBase資深技術(shù)專(zhuān)家)潘毅(OceanBase資深技術(shù)專(zhuān)家)韓富晟(OceanBase資深技術(shù)專(zhuān)家)趙裕眾(OceanBase高級技術(shù)專(zhuān)家)
原文轉自:http://database.51cto.com/art/201910/603908.htm