姓名:郭金? ? 學(xué)號:17101223407
轉(zhuǎn)載自:https://www.cnblogs.com/LiJianBlog/p/4779934.html
【嵌牛導(dǎo)讀】:雙11阿里的成交額又創(chuàng)新高,1682億,支付峰值為25.6萬筆/秒。
? ? ? 從阿里的公布各種宣傳稿來看,有一個細(xì)節(jié),首次公布了數(shù)據(jù)庫處理峰值為4200萬次/秒。
? ? ? 螞蟻金服首席技術(shù)架構(gòu)師、副總裁胡喜介紹,支付寶之所以在今年首次公布“數(shù)據(jù)庫處理峰值”,是因?yàn)榻衲觌p11,支付寶首次把包括賬務(wù)庫在內(nèi)的所有核心數(shù)據(jù)鏈,全部搬到了螞蟻金服自主研發(fā)的數(shù)據(jù)庫OceanBase上。
【嵌牛鼻子】:OceanBase 、 MergeServer
【嵌牛提問】: 為什么OceanBase特別適合雙十一?修改增量在內(nèi)存,大概需要多大的內(nèi)存?
【嵌牛正文】:
? ? ? OceanBase吹了好多年了,終于用到核心庫里面去了,說明內(nèi)部覺得足夠成熟了,可喜可賀。
? ? 網(wǎng)上收集了下OceanBase的資料,分享給大家。
1為什么OceanBase特別適合雙十一
(以下內(nèi)容來源網(wǎng)上阿里正詳?shù)慕獯穑?/p>
? ? ? 其實(shí),雖然不是刻意設(shè)計(jì)的,但OceanBase確實(shí)比傳統(tǒng)數(shù)據(jù)庫更適合像雙十一、聚劃算、秒殺以及銀行國庫券銷售等短時間突發(fā)大流量的場景:
·短時間內(nèi)大量用戶涌入
·短時間內(nèi)業(yè)務(wù)流量非常大,數(shù)據(jù)庫系統(tǒng)壓力非常大
·一段時間(幾秒鐘、幾分鐘、或半個小時等)后業(yè)務(wù)流量迅速或明顯回落
雖然2010年設(shè)計(jì)OceanBase架構(gòu)時,其實(shí)并沒有特別考慮到這個突發(fā)大流量的因素。讓我們從OceanBase的架構(gòu)說起。
OceanBase是“基線數(shù)據(jù)(硬盤)”+“修改增量(內(nèi)存)”的架構(gòu),如下圖所示:

即整個數(shù)據(jù)庫以硬盤(通常是SSD)為載體,新近的增、刪、改數(shù)據(jù)(“修改增量”)在內(nèi)存,而基線數(shù)據(jù)在保存在硬盤上,因此OceanBase可以看成一個準(zhǔn)內(nèi)存數(shù)據(jù)庫。這樣的好處是:
·寫事務(wù)在內(nèi)存(除事務(wù)日志必須落盤外),性能大大提升
·沒有隨機(jī)寫硬盤,硬盤隨機(jī)讀不受干擾,高峰期系統(tǒng)性能提升明顯;對于傳統(tǒng)數(shù)據(jù)庫,業(yè)務(wù)高峰期通常也是大量隨機(jī)寫盤(刷臟頁)的高峰期,大量隨機(jī)寫盤消耗了大量的IO,特別是考慮到SSD的寫入放大,對于讀寫性能都有較大的影響
·基線數(shù)據(jù)只讀,緩存(cache)簡單且效果提升
·線上OceanBase的內(nèi)存配置是支撐平常兩天的修改增量(從OceanBase 1.0開始,每臺OceanBase都可以寫入,都承載著部分的修改增量),因此即使突發(fā)大流量為平日的10-20倍,也可支撐1~2個小時以上。

一個問題是:修改增量在內(nèi)存,大概需要多大的內(nèi)存?即使按雙11全天的支付筆數(shù)10.5億筆,假設(shè)每筆1KB,總共需要的內(nèi)存大約是1TB,平均到10臺服務(wù)器,100GB/臺。
另一個問題是:在類似雙十一這種流量特別大的場景中,就像前面說到的,OceanBase內(nèi)存能夠支持峰值業(yè)務(wù)寫入1~2個小時以上,之后OceanBase必須把內(nèi)存中的增刪改數(shù)據(jù)(“修改增量”)盡快整合到硬盤并釋放內(nèi)存,以便業(yè)務(wù)的持續(xù)寫入。整合內(nèi)存中的修改增量到硬盤,OceanBase稱為每日合并,必然涉及到大量的硬盤讀寫(IO),因此可能對業(yè)務(wù)的吞吐量和事務(wù)響應(yīng)時間(RT)產(chǎn)生影響。如何避免每日合并對業(yè)務(wù)的影響呢?OceanBase通過“輪轉(zhuǎn)合并”解決了這個問題。
眾所周知,出于高可用的考慮,OceanBase是三機(jī)群(zone)部署:

根據(jù)配置和部署的不同,業(yè)務(wù)高峰時可以一個機(jī)群(zone)、兩個機(jī)群(zone)或者三個機(jī)群(zone)提供讀寫服務(wù)。OceanBase的輪轉(zhuǎn)合并就是對每個機(jī)群(zone)輪轉(zhuǎn)地進(jìn)行每日合并,在對一個機(jī)群(zone)進(jìn)行每日合并之前,先把該機(jī)群(zone)上的業(yè)務(wù)讀寫流量切換到另外的一個或兩個機(jī)群(zone),然后對該機(jī)群(zone)進(jìn)行全速的每日合并。因此在每日合并期間,合并進(jìn)行中的機(jī)群(zone)沒有業(yè)務(wù)流量,僅僅接收事務(wù)日志并且參與Paxos投票,業(yè)務(wù)訪問OceanBase的事務(wù)響應(yīng)時間完全不受每日合并的影響,僅僅是OceanBase的總吞吐量有所下降:如果先前是三個機(jī)群(zone)都提供服務(wù)則總吞吐量下降1/3,如果先前只有一個或兩個機(jī)群(zone)提供服務(wù)則總吞吐量沒有變化。
輪轉(zhuǎn)合并使得OceanBase對SSD十分友好,避免了大量隨機(jī)寫盤對SSD壽命的影響,因此OceanBase可以使用相對廉價的“讀密集型”SSD來代替?zhèn)鹘y(tǒng)數(shù)據(jù)庫使用的相對昂貴的“讀寫型”SSD,而不影響性能。此外由于輪轉(zhuǎn)合并對服務(wù)器的CPU使用、硬盤IO使用以及耗時長短都不敏感(高峰期的傳統(tǒng)數(shù)據(jù)庫在刷臟頁的同時還要優(yōu)先保證業(yè)務(wù)訪問的吞吐量和事務(wù)響應(yīng)時間,刷臟頁的CPU及IO資源都非常受限),因此OceanBase在每日合并時可以采用更加高效的壓縮或者編碼算法(比如壓縮或編碼速度略慢,但壓縮率較高、解壓縮很快的算法),從而進(jìn)一步降低存儲成本并提升性能。
2OceanBase設(shè)計(jì)思路
OceanBase的目標(biāo)是支持?jǐn)?shù)百TB的數(shù)據(jù)量以及數(shù)十萬TPS、數(shù)百萬QPS的訪問量,無論是數(shù)據(jù)量還是訪問量,即使采用非常昂貴的小型機(jī)甚至是大型機(jī),單臺關(guān)系數(shù)據(jù)庫系統(tǒng)都無法承受。
一種常見的做法是根據(jù)業(yè)務(wù)特點(diǎn)對數(shù)據(jù)庫進(jìn)行水平拆分,通常的做法是根據(jù)某個業(yè)務(wù)字段(通常取用戶編號,user_id)哈希后取模,根據(jù)取模的結(jié)果將數(shù)據(jù)分布到不同的數(shù)據(jù)庫服務(wù)器上,客戶端請求通過數(shù)據(jù)庫中間層路由到不同的分區(qū)。這種方式目前還存在一定的弊端,如下所示:
數(shù)據(jù)和負(fù)載增加后添加機(jī)器的操作比較復(fù)雜,往往需要人工介入;
有些范圍查詢需要訪問幾乎所有的分區(qū),例如,按照user_id分區(qū),查詢收藏了一個商品的所有用戶需要訪問所有的分區(qū);
目前廣泛使用的關(guān)系數(shù)據(jù)庫存儲引擎都是針對機(jī)械硬盤的特點(diǎn)設(shè)計(jì)的,不能夠完全發(fā)揮新硬件(SSD)的能力。
另外一種做法是參考分布式表格系統(tǒng)的做法,例如Google Bigtable系統(tǒng),將大表劃分為幾萬、幾十萬甚至幾百萬個子表,子表之間按照主鍵有序,如果某臺服務(wù)器發(fā)生故障,它上面服務(wù)的數(shù)據(jù)能夠在很短的時間內(nèi)自動遷移到集群中所有的其他服務(wù)器。這種方式解決了可擴(kuò)展性的問題,少量突發(fā)的服務(wù)器故障或者增加服務(wù)器對使用者基本是透明的,能夠輕松應(yīng)對促銷或者熱點(diǎn)事件等突發(fā)流量增長。另外,由于子表是按照主鍵有序分布的,很好地解決了范圍查詢的問題。
萬事有其利必有一弊,分布式表格系統(tǒng)雖然解決了可擴(kuò)展性問題,但往往無法支持事務(wù),例如Bigtable只支持單行事務(wù),針對同一個user_id下的多條記錄的操作都無法保證原子性。而OceanBase希望能夠支持跨行跨表事務(wù),這樣使用起來會比較方便。
最直接的做法是在Bigtable開源實(shí)現(xiàn)(如HBase或者Hypertable)的基礎(chǔ)上引入兩階段提交(Two-phase Commit)協(xié)議支持分布式事務(wù),這種思路在Google的Percolator系統(tǒng)中得到了體現(xiàn)。然而,Percolator系統(tǒng)中事務(wù)的平均響應(yīng)時間達(dá)到2~5秒,只能應(yīng)用在類似網(wǎng)頁建庫這樣的半線上業(yè)務(wù)中。另外,Bigtable的開源實(shí)現(xiàn)也不夠成熟,單臺服務(wù)器能夠支持的數(shù)據(jù)量有限,單個請求的最大響應(yīng)時間很難得到保證,機(jī)器故障等異常處理機(jī)制也有很多比較嚴(yán)重的問題??傮w上看,這種做法的工作量和難度超出了項(xiàng)目組的承受能力,因此,我們需要根據(jù)業(yè)務(wù)特點(diǎn)做一些定制。
通過分析,我們發(fā)現(xiàn),雖然在線業(yè)務(wù)的數(shù)據(jù)量十分龐大,例如幾十億條、上百億條甚至更多記錄,但最近一段時間(例如一天)的修改量往往并不多,通常不超過幾千萬條到幾億條,因此,OceanBase決定采用單臺更新服務(wù)器來記錄最近一段時間的修改增量,而以前的數(shù)據(jù)保持不變,以前的數(shù)據(jù)稱為基線數(shù)據(jù)?;€數(shù)據(jù)以類似分布式文件系統(tǒng)的方式存儲于多臺基線數(shù)據(jù)服務(wù)器中,每次查詢都需要把基線數(shù)據(jù)和增量數(shù)據(jù)融合后返回給客戶端。這樣,寫事務(wù)都集中在單臺更新服務(wù)器上,避免了復(fù)雜的分布式事務(wù),高效地實(shí)現(xiàn)了跨行跨表事務(wù);另外,更新服務(wù)器上的修改增量能夠定期分發(fā)到多臺基線數(shù)據(jù)服務(wù)器中,避免成為瓶頸,實(shí)現(xiàn)了良好的擴(kuò)展性。
當(dāng)然,單臺更新服務(wù)器的處理能力總是有一定的限制。因此,更新服務(wù)器的硬件配置相對較好,如內(nèi)存較大、網(wǎng)卡及CPU較好;另外,最近一段時間的更新操作往往總是能夠存放在內(nèi)存中,在軟件層面也針對這種場景做了大量的優(yōu)化。
3OceanBase系統(tǒng)架構(gòu)
整體架構(gòu)圖如下:

OceanBase由如下幾個部分組成:
客戶端:用戶使用OceanBase的方式和MySQL數(shù)據(jù)庫完全相同,支持JDBC、 C客戶端訪問,等等。基于MySQL數(shù)據(jù)庫開發(fā)的應(yīng)用程序、工具能夠直接遷移到OceanBase。
RootServer:管理集群中的所有服務(wù)器,子表(tablet)數(shù)據(jù)分布以及副本管理。 RootServer一般為一主一備,主備之間數(shù)據(jù)強(qiáng)同步。
UpdateServer:存儲OceanBase系統(tǒng)的增量更新數(shù)據(jù)。UpdateServer一般為一主一備,主備之間可以配置不同的同步模式。部署時,UpdateServer進(jìn)程和RootServer進(jìn)程往往共用物理服務(wù)器。
ChunkServer:存儲OceanBase系統(tǒng)的基線數(shù)據(jù)?;€數(shù)據(jù)一般存儲兩份或者三份,可配置。
MergeServer:接收并解析用戶的SQL請求,經(jīng)過詞法分析、語法分析、查詢優(yōu)化等一系列操作后轉(zhuǎn)發(fā)給相應(yīng)的ChunkServer或者UpdateServer。如果請求的數(shù)據(jù)分布在多臺ChunkServer上,MergeServer還需要對多臺ChunkServer返回的結(jié)果進(jìn)行合并??蛻舳撕蚆ergeServer之間采用原生的MySQL通信協(xié)議,MySQL客戶端可以直接訪問MergeServer。
OceanBase支持部署多個機(jī)房,每個機(jī)房部署一個包含RootServer、MergeServer、ChunkServer以及UpdateServer的完整OceanBase集群,每個集群由各自的RootServer負(fù)責(zé)數(shù)據(jù)劃分、負(fù)載均衡、集群服務(wù)器管理等操作,集群之間數(shù)據(jù)同步通過主集群的主UpdateServer往備集群同步增量更新操作日志實(shí)現(xiàn)??蛻舳伺渲昧硕鄠€集群的RootServer地址列表,使用者可以設(shè)置每個集群的流量分配比例,客戶端根據(jù)這個比例將讀寫操作發(fā)往不同的集群,如下圖:

客服端
1)請求RootServer獲取集群中MergeServer的地址列表。
2)按照一定的策略選擇某臺MergeServer發(fā)送讀寫請求??蛻舳伺cMergeServer之間的通信協(xié)議兼容原生的MySQL協(xié)議,因此,只需要調(diào)用MySQL JDBC Driver或者M(jìn)ySQL C客戶端這樣的標(biāo)準(zhǔn)庫即可。客戶端支持的策略主要有兩種:隨機(jī)以及一致性哈希。一致性哈希的主要目的是將相同的SQL請求發(fā)送到同一臺MergeServer,方便MergeServer對查詢結(jié)果進(jìn)行緩存。
3)如果請求MergeServer失敗,則從MergeServer列表中重新選擇一臺MergeServer重試;如果請求某臺MergeServer失敗超過一定的次數(shù),將這臺MergeServer加入黑名單并從MergeServer列表中刪除。另外,客戶端會定期請求RootServer更新MergeServer地址列表。
如果OceanBase部署多個集群,客戶端還需要處理多個集群的流量分配問題。使用者可以設(shè)置多個集群之間的流量分配比例,客戶端獲取到流量分配比例后,按照這個比例將請求發(fā)送到不同的集群。
RootServer
RootServer的功能主要包括:集群管理、數(shù)據(jù)分布以及副本管理。
RootServer管理集群中的所有MergeServer、ChunkServer以及UpdateServer。每個集群內(nèi)部同一時刻只允許一個UpdateServer提供寫服務(wù),這個UpdateServer成為主UpdateServer。這種方式通過犧牲一定的可用性獲取了強(qiáng)一致性。RootServer通過租約(Lease)機(jī)制選擇唯一的主UpdateServer,當(dāng)原先的主UpdateServer發(fā)生故障后,RootServer能夠在原先的租約失效后選擇一臺新的UpdateServer作為主UpdateServer。另外,RootServer與MergeServer&ChunkServer之間保持心跳(heartbeat),從而能夠感知到在線和已經(jīng)下線的MergeServer&ChunkServer機(jī)器列表。
OceanBase內(nèi)部使用主鍵對表格中的數(shù)據(jù)進(jìn)行排序和存儲,主鍵由若干列組成并且具有唯一性。在OceanBase內(nèi)部,基線數(shù)據(jù)按照主鍵排序并且劃分為數(shù)據(jù)量大致相等的數(shù)據(jù)范圍,稱為子表(tablet)。每個子表的默認(rèn)大小是256MB(可配置)。OceanBase的數(shù)據(jù)分布方式與Bigtable一樣采用順序分布,不同的是,OceanBase沒有采用根表(RootTable)+元數(shù)據(jù)表(MetaTable)兩級索引結(jié)構(gòu),而是采用根表一級索引結(jié)構(gòu)。
如圖所示,主鍵值在[1,100]之間的表格被劃分為四個子表:1~25,26~50,51~80以及81~100。RootServer中的根表記錄了每個子表所在的ChunkServer位置信息,每個子表包含多個副本(一般為三個副本,可配置),分布在多臺ChunkServer中。當(dāng)其中某臺ChunkServer發(fā)生故障時,RootServer能夠檢測到,并且觸發(fā)對這臺ChunkServer上的子表增加副本的操作;另外,RootServer也會定期執(zhí)行負(fù)載均衡,選擇某些子表從負(fù)載較高的機(jī)器遷移到負(fù)載較低的機(jī)器上。
RootServer采用一主一備的結(jié)構(gòu),主備之間數(shù)據(jù)強(qiáng)同步,并通過Linux HA(http://www.linux-ha.org)軟件實(shí)現(xiàn)高可用性。主備RootServer之間共享VIP,當(dāng)主RootServer發(fā)生故障后,VIP能夠自動漂移到備RootServer所在的機(jī)器,備RootServer檢測到以后切換為主RootServer提供服務(wù)。
MergeServer
MergeServer的功能主要包括:協(xié)議解析、SQL解析、請求轉(zhuǎn)發(fā)、結(jié)果合并、多表操作等。
OceanBase客戶端與MergeServer之間的協(xié)議為MySQL協(xié)議。MergeServer首先解析MySQL協(xié)議,從中提取出用戶發(fā)送的SQL語句,接著進(jìn)行詞法分析和語法分析,生成SQL語句的邏輯查詢計(jì)劃和物理查詢計(jì)劃,最后根據(jù)物理查詢計(jì)劃調(diào)用OceanBase內(nèi)部的各種操作符。
MergeServer緩存了子表分布信息,根據(jù)請求涉及的子表將請求轉(zhuǎn)發(fā)給該子表所在的ChunkServer。如果是寫操作,還會轉(zhuǎn)發(fā)給UpdateServer。某些請求需要跨多個子表,此時MergeServer會將請求拆分后發(fā)送給多臺ChunkServer,并合并這些ChunkServer返回的結(jié)果。如果請求涉及多個表格,MergeServer需要首先從ChunkServer獲取每個表格的數(shù)據(jù),接著再執(zhí)行多表關(guān)聯(lián)或者嵌套查詢等操作。
MergeServer支持并發(fā)請求多臺ChunkServer,即將多個請求發(fā)給多臺ChunkServer,再一次性等待所有請求的應(yīng)答。另外,在SQL執(zhí)行過程中,如果某個子表所在的ChunkServer出現(xiàn)故障,MergeServer會將請求轉(zhuǎn)發(fā)給該子表的其他副本所在的ChunkServer。這樣,ChunkServer故障是不會影響用戶查詢的。
MergeServer本身是沒有狀態(tài)的,因此,MergeServer宕機(jī)不會對使用者產(chǎn)生影響,客戶端會自動將發(fā)生故障的MergeServer屏蔽掉。
ChunkServer
ChunkServer的功能包括:存儲多個子表,提供讀取服務(wù),執(zhí)行定期合并以及數(shù)據(jù)分發(fā)。
OceanBase將大表劃分為大小約為256MB的子表,每個子表由一個或者多個SSTable組成(一般為一個),每個SSTable由多個塊(Block,大小為4KB~64KB之間,可配置)組成,數(shù)據(jù)在SSTable中按照主鍵有序存儲。查找某一行數(shù)據(jù)時,需要首先定位這一行所屬的子表,接著在相應(yīng)的SSTable中執(zhí)行二分查找。SSTable支持兩種緩存模式,塊緩存(Block Cache)以及行緩存(Row Cache)。塊緩存以塊為單位緩存最近讀取的數(shù)據(jù),行緩存以行為單位緩存最近讀取的數(shù)據(jù)。
MergeServer將每個子表的讀取請求發(fā)送到子表所在的ChunkServer,ChunkServer首先讀取SSTable中包含的基線數(shù)據(jù),接著請求UpdateServer獲取相應(yīng)的增量更新數(shù)據(jù),并將基線數(shù)據(jù)與增量更新融合后得到最終結(jié)果。
由于每次讀取都需要從UpdateServer中獲取最新的增量更新,為了保證讀取性能,需要限制UpdateServer中增量更新的數(shù)據(jù)量,最好能夠全部存放在內(nèi)存中。OceanBase內(nèi)部會定期觸發(fā)合并或者數(shù)據(jù)分發(fā)操作,在這個過程中,ChunkServer將從UpdateServer獲取一段時間之前的更新操作。通常情況下,OceanBase集群會在每天的服務(wù)低峰期(凌晨1:00開始,可配置)執(zhí)行一次合并操作。這個合并操作往往也稱為每日合并。
UpdateServer
UpdateServer是集群中唯一能夠接受寫入的模塊,每個集群中只有一個主Update-Server。UpdateServer中的更新操作首先寫入到內(nèi)存表,當(dāng)內(nèi)存表的數(shù)據(jù)量超過一定值時,可以生成快照文件并轉(zhuǎn)儲到SSD中。快照文件的組織方式與ChunkServer中的SSTable類似,因此,這些快照文件也稱為SSTable。另外,由于數(shù)據(jù)行的某些列被更新,某些列沒被更新,SSTable中存儲的數(shù)據(jù)行是稀疏的,稱為稀疏型SSTable。
為了保證可靠性,主UpdateServer更新內(nèi)存表之前需要首先寫操作日志,并同步到備UpdateServer。當(dāng)主UpdateServer發(fā)生故障時,RootServer上維護(hù)的租約將失效,此時,RootServer將從備UpdateServer列表中選擇一臺最新的備UpdateServer切換為主UpdateServer繼續(xù)提供寫服務(wù)。UpdateServer宕機(jī)重啟后需要首先加載轉(zhuǎn)儲的快照文件(SSTable文件),接著回放快照點(diǎn)之后的操作日志。
由于集群中只有一臺主UpdateServer提供寫服務(wù),因此,OceanBase很容易地實(shí)現(xiàn)了跨行跨表事務(wù),而不需要采用傳統(tǒng)的兩階段提交協(xié)議。當(dāng)然,這樣也帶來了一系列的問題。由于整個集群所有的讀寫操作都必須經(jīng)過UpdateServer,UpdateServer的性能至關(guān)重要。OceanBase集群通過定期合并和數(shù)據(jù)分發(fā)這兩種機(jī)制將UpdateServer一段時間之前的增量更新源源不斷地分散到ChunkServer,而UpdateServer只需要服務(wù)最新一小段時間新增的數(shù)據(jù),這些數(shù)據(jù)往往可以全部存放在內(nèi)存中。另外,系統(tǒng)實(shí)現(xiàn)時也需要對UpdateServer的內(nèi)存操作、網(wǎng)絡(luò)框架、磁盤操作做大量的優(yōu)化。
定期合并&數(shù)據(jù)分發(fā)
定期合并和數(shù)據(jù)分發(fā)都是將UpdateServer中的增量更新分發(fā)到ChunkServer中的手段,二者的整體流程比較類似:
1)UpdateServer凍結(jié)當(dāng)前的活躍內(nèi)存表(Active MemTable),生成凍結(jié)內(nèi)存表,并開啟新的活躍內(nèi)存表,后續(xù)的更新操作都寫入新的活躍內(nèi)存表。
2)UpdateServer通知RootServer數(shù)據(jù)版本發(fā)生了變化,之后RootServer通過心跳消息通知ChunkServer。
3)每臺ChunkServer啟動定期合并或者數(shù)據(jù)分發(fā)操作,從UpdateServer獲取每個子表對應(yīng)的增量更新數(shù)據(jù)。
定期合并與數(shù)據(jù)分發(fā)兩者之間的不同點(diǎn)在于,數(shù)據(jù)分發(fā)過程中ChunkServer只是將UpdateServer中凍結(jié)內(nèi)存表中的增量更新數(shù)據(jù)緩存到本地,而定期合并過程中ChunkServer需要將本地SSTable中的基線數(shù)據(jù)與凍結(jié)內(nèi)存表的增量更新數(shù)據(jù)執(zhí)行一次多路歸并,融合后生成新的基線數(shù)據(jù)并存放到新的SSTable中。定期合并對系統(tǒng)服務(wù)能力影響很大,往往安排在每天服務(wù)低峰期執(zhí)行(例如凌晨1點(diǎn)開始),而數(shù)據(jù)分發(fā)可以不受限制。
單點(diǎn)性能
OceanBase架構(gòu)的優(yōu)勢在于既支持跨行跨表事務(wù),又支持存儲服務(wù)器線性擴(kuò)展。當(dāng)然,這個架構(gòu)也有一個明顯的缺陷:UpdateServer單點(diǎn),這個問題限制了OceanBase集群的整體讀寫性能。下面從內(nèi)存容量、網(wǎng)絡(luò)、磁盤等幾個方面分析UpdateServer的讀寫性能。其實(shí)大部分?jǐn)?shù)據(jù)庫每天的修改次數(shù)相當(dāng)有限,只有少數(shù)修改比較頻繁的數(shù)據(jù)庫才有每天幾億次的修改次數(shù)。另外,數(shù)據(jù)庫平均每次修改涉及的數(shù)據(jù)量很少,很多時候只有幾十個字節(jié)到幾百個字節(jié)。假設(shè)數(shù)據(jù)庫每天更新1億次,平均每次需要消耗100字節(jié),每天插入1000萬次,平均每次需要消耗1000字節(jié),那么,一天的修改量為:1億×100+1000萬×1000=20GB,如果內(nèi)存數(shù)據(jù)結(jié)構(gòu)膨脹2倍,占用內(nèi)存只有40GB。而當(dāng)前主流的服務(wù)器都可以配置96GB內(nèi)存,一些高檔的服務(wù)器甚至可以配置192GB、384GB乃至更多內(nèi)存。
從上面的分析可以看出,UpdateServer的內(nèi)存容量一般不會成為瓶頸。然而,服務(wù)器的內(nèi)存畢竟有限,實(shí)際應(yīng)用中仍然可能出現(xiàn)修改量超出內(nèi)存的情況。例如,淘寶雙11網(wǎng)購節(jié)數(shù)據(jù)庫修改量暴漲,某些特殊應(yīng)用每天的修改次數(shù)特別多或者每次修改的數(shù)據(jù)量特別大,DBA數(shù)據(jù)訂正時一次性寫入大量數(shù)據(jù)。為此,UpdateServer設(shè)計(jì)實(shí)現(xiàn)了幾種方式解決內(nèi)存容量問題,UpdateServer的內(nèi)存表達(dá)到一定大小時,可自動或者手工凍結(jié)并轉(zhuǎn)儲到SSD中,另外,OceanBase支持通過定期合并或者數(shù)據(jù)分發(fā)的方式將UpdateServer的數(shù)據(jù)分散到集群中所有的ChunkServer機(jī)器中,這樣不僅避免了UpdateServer單機(jī)數(shù)據(jù)容量問題,還能夠使得讀取操作往往只需要訪問UpdateServer內(nèi)存中的數(shù)據(jù),避免訪問SSD磁盤,提高了讀取性能。
從網(wǎng)絡(luò)角度看,假設(shè)每秒的讀取次數(shù)為20萬次,每次需要從UpdateServer中獲取100字節(jié),那么,讀取操作占用的UpdateServer出口帶寬為:20萬×100=20MB,遠(yuǎn)遠(yuǎn)沒有達(dá)到千兆網(wǎng)卡帶寬上限。另外,UpdateServer還可以配置多塊千兆網(wǎng)卡或者萬兆網(wǎng)卡,例如,OceanBase線上集群一般給UpdateServer配置4塊千兆網(wǎng)卡。當(dāng)然,如果軟件層面沒有做好,硬件特性將得不到充分發(fā)揮。針對UpdateServer全內(nèi)存、收發(fā)的網(wǎng)絡(luò)包一般比較小的特點(diǎn),開發(fā)團(tuán)隊(duì)對UpdateServer的網(wǎng)絡(luò)框架做了專門的優(yōu)化,大大提高了每秒收發(fā)網(wǎng)絡(luò)包的個數(shù),使得網(wǎng)絡(luò)不會成為瓶頸。
從磁盤的角度看,數(shù)據(jù)庫事務(wù)需要首先將操作日志寫入磁盤。如果每次寫入都需要將數(shù)據(jù)刷入磁盤,而一塊SAS磁盤每秒支持的IOPS很難超過300,磁盤將很快成為瓶頸。為了解決這個問題,UpdateServer在硬件上會配置一塊帶有緩存模塊的RAID卡,UpdateServer寫操作日志只需要寫入到RAID卡的緩存模塊即可,延時可以控制在1毫秒之內(nèi)。RAID卡帶電池,如果UpdateServer發(fā)生故障,比如機(jī)器突然停電,RAID卡能夠確保將緩存中的數(shù)據(jù)刷入磁盤,不會出現(xiàn)丟數(shù)據(jù)的情況。另外,UpdateServer還實(shí)現(xiàn)了寫事務(wù)的成組提交機(jī)制,將多個用戶寫操作湊成一批一次性提交,進(jìn)一步減少磁盤IO次數(shù)。
磁盤隨機(jī)IO是存儲系統(tǒng)性能的決定因素,傳統(tǒng)的SAS盤能夠提供的IOPS不超過300。關(guān)系數(shù)據(jù)庫一般采用高速緩存(Buffer Cache)[注釋]的方式緩解這個問題,讀取操作將磁盤中的頁面緩存到高速緩存中,并通過LRU或者類似的方式淘汰不經(jīng)常訪問的頁面;同樣,寫入操作也是將數(shù)據(jù)寫入到高速緩存中,由高速緩存按照一定的策略將內(nèi)存中頁面的內(nèi)容刷入磁盤。這種方式面臨一些問題,例如,Cache冷啟動問題,即數(shù)據(jù)庫剛啟動時性能很差,需要將讀取流量逐步切入。另外,這種方式不適合寫入特別多的場景。
最近幾年,SSD磁盤取得了很大的進(jìn)展,它不僅提供了非常好的隨機(jī)讀取性能,功耗也非常低,大有取代傳統(tǒng)機(jī)械磁盤之勢。一塊普通的SSD磁盤可以提供35000 IOPS甚至更高,并提供300MB/s或以上的讀出帶寬。然而,SSD盤的隨機(jī)寫性能并不理想。這是因?yàn)?,盡管SSD的讀和寫以頁(page,例如4KB,8KB等)為單位,但SSD寫入前需要首先擦除已有內(nèi)容,而擦除以塊(block)為單位,一個塊由若干個連續(xù)的頁組成,大小通常在512KB~2MB。假如寫入的頁有內(nèi)容,即使只寫入一個字節(jié),SSD也需要擦除整個512KB~2MB大小的塊,然后再寫入整個頁的內(nèi)容,這就是SSD的寫入放大效應(yīng)。雖然SSD硬件廠商都針對這個問題做了一些優(yōu)化,但整體上看,隨機(jī)寫入不能發(fā)揮SSD的優(yōu)勢。
OceanBase設(shè)計(jì)之初就認(rèn)為SSD為大勢所趨,整個系統(tǒng)設(shè)計(jì)時完全摒棄了隨機(jī)寫,除了操作日志總是順序追加寫入到普通SAS盤上,剩下的寫請求都是對響應(yīng)時間要求不是很高的批量順序?qū)?,SSD盤可以輕松應(yīng)對,而大量查詢請求的隨機(jī)讀,則發(fā)揮了SSD良好的隨機(jī)讀的特性。摒棄隨機(jī)寫,采用批量的順序?qū)懀彩沟霉虘B(tài)盤的使用壽命不再成為問題,主流SSD盤使用MLC SSD芯片,而MLC號稱可以擦寫1萬次(SLC可以擦寫10萬次,但因成本高而較少使用),即使按最保守的2500次擦寫次數(shù)計(jì)算,而且每天全部擦寫一遍,其使用壽命為2500/365=6.8年。
數(shù)據(jù)正確性
數(shù)據(jù)丟失或者數(shù)據(jù)錯誤對于存儲系統(tǒng)來說是一種災(zāi)難。OceanBase設(shè)計(jì)為強(qiáng)一致性系統(tǒng),設(shè)計(jì)方案上保證不丟數(shù)據(jù)。然而,TCP協(xié)議傳輸、磁盤讀寫都可能出現(xiàn)數(shù)據(jù)錯誤,程序Bug則更為常見。為了防止各種因素導(dǎo)致的數(shù)據(jù)損毀,OceanBase采取了以下數(shù)據(jù)校驗(yàn)措施:
? ? 數(shù)據(jù)存儲校驗(yàn)。每個存儲記錄(通常是幾KB到幾十KB)同時保存64位CRC校驗(yàn)碼,數(shù)據(jù)被訪問時,重新計(jì)算和比對校驗(yàn)碼。
? ? 數(shù)據(jù)傳輸校驗(yàn)。每個傳輸記錄同時傳輸64位CRC校驗(yàn)碼,數(shù)據(jù)被接收后,重新計(jì)算和比對校驗(yàn)碼。
? ? 數(shù)據(jù)鏡像校驗(yàn)。UpdateServer在機(jī)群內(nèi)有主UpdateServer和備UpdateServer,集群間有主集群和備集群,這些UpdateServer的內(nèi)存表(MemTable)必須保持一致。為此,UpdateServer為MemTable生成一個校驗(yàn)碼,MemTable每次更新時,校驗(yàn)碼同步更新并記錄在對應(yīng)的操作日志中。備UpdateServer收到操作日志并重放到MemTable時,也同步更新MemTable校驗(yàn)碼并與接收到的校驗(yàn)碼對照。UpdateServer重新啟動后重放日志恢復(fù)MemTable時也同步更新MemTable校驗(yàn)碼并與保存在每條操作日志中的校驗(yàn)碼對照。
? ? 數(shù)據(jù)副本校驗(yàn)。定期合并時,新的子表由各個ChunkServer獨(dú)立地融合舊的子表中的SSTable與凍結(jié)的MemTable而生成,如果發(fā)生任何異常或者錯誤(比如程序bug),同一子表的多個副本可能不一致,則這種不一致可能隨著定期合并而逐步累積或擴(kuò)散且很難被發(fā)現(xiàn),即使被察覺,也可能因?yàn)樾枰匪葺^長時間而難以定位到源頭。為了防止這種情況出現(xiàn),ChunkServer在定期合并生成新的子表時,也同時為每個子表生成一個校驗(yàn)碼,并隨新子表匯報給RootServer,以便RootServer核對同一子表不同副本的校驗(yàn)碼。