滴滴 NewSQL 演進之 Fusion 實踐

資料庫頻道發表於2019-05-17

本文根據滴滴資料庫儲存專家餘汶龍,在DTCC中國第十屆資料庫大會的演講整理而成。

餘汶龍

滴滴出行技術專家,曾經在VMware、淘寶、阿里雲從事虛擬網路及儲存領域的工作。現負責滴滴自研的NoSQL儲存、NewSQL儲存以及DTS專案。從零組建了Fusion儲存團隊,並帶領團隊完成了上述3個大型專案的架構設計、方案落地以及線上護航。

大家都知道,NewSQL 是對各種新型資料庫的簡稱,這類資料庫不僅具有NoSQL對海量資料處理的高擴充套件能力和高吞吐能力,還具有傳統資料庫的事務能力和SQL能力。

那麼在一套成熟的NoSQL系統上,是否可以孵化出NewSQL系統來呢?答案是肯定的。

因為在滴滴,就有這麼一個成熟的自研的NoSQL系統Fusion,基於他之上我們成功孵化了NewSQL系統。因此本次的分享大綱就分成3個部分,前面先講我們在NoSQL上取得的成功,然後講如何演變到NewSQL,最後講這個演進方案的缺陷,指出未來的演進方向。

滴滴 NewSQL 演進之 Fusion 實踐

接下來,先看本次分享的大綱概述,如下。

滴滴 NewSQL 演進之 Fusion 實踐

這塊是我們所有儲存產品的整體架構檢視,我們的產品都是在RocksDB引擎層基礎之上構建。首先增加了網路層、叢集管理層、接入層的工作,構建了我們的NoSQL儲存系統Fusion,然後在Fusion的基礎之上,我們整合了滴滴的排程系統和Hadoop計算平臺的能力,構建了我們的DTS服務FastLoad;第3塊是在Fusion的基礎上,增加了schema管理、二級索引、事務、binlog等能力,構建了我們的NewSQL儲存dise;第4塊是面向未來規劃的分散式資料庫。圍繞這些核心服務,我們做了一套完善的智慧管控系統,它是依託於salt-stack平臺,實現了使用者系統和運維繫統,分別解決了使用者接入問題和自動化運維的問題。

接下來,我們從NoSQL講起。

第一章:成熟的NoSQL儲存系統Fusion

這塊首先講Fusion的背景介紹。可以看到Fusion是用C++自研的分散式NoSQL資料庫,支援Redis協議,資料透過RocksDB落盤,現線上上業務已經接入400多個業務,覆蓋了全公司;當前線上規模是300多個叢集,全自動化運維跑著,沒有專門的OP人員參與,總資料量達到1500TB,峰值QPS超過1400W。

滴滴 NewSQL 演進之 Fusion 實踐

接下來講Fusion的架構,如下。講架構之前,先看Fusion的誕生背景,他誕生初期主要解決兩個業務的資料儲存:歷史訂單和司機行程軌跡。大家都知道滴滴是個每天訂單千萬級的業務,那麼歷史訂單很快就會突破百億級,而每條訂單都會對應一條司機行程軌跡,而且叫車距離越長,單條行程軌跡資料越大,這是一個比歷史訂單資料量更大的業務。在Fusion誕生之前,滴滴的儲存主要是用Redis和MySQL,很顯然在這種規模下的資料量,用Redis和MySQL並不是最優解。因此誕生了Fusion。

因為Redis的協議實現很簡單,且資料結構非常豐富,因此我們在磁碟上去實現了Redis的儲存結構,基於這樣的核心思想,我們實現了Fusion的叢集架構,從上往下分別是接入層、叢集管理層、持久層、高可用層。

滴滴 NewSQL 演進之 Fusion 實踐

接下來,總結了5個亮點,挑其中4個來說明Fusion的產品成熟度,如下:

滴滴 NewSQL 演進之 Fusion 實踐

亮點1:資料流動

第一個是資料流動能力。做為一個自研的儲存系統,他必須融入整個公司的開發生態,具備與其他儲存系統、中介軟體、離線計算、實時計算等平臺打通的能力,才能推廣開。因此,我們在這方面做了很多工作,其中挑hive到Fusion打通,以及Fusion與Fusion之間打通的例子來展開介紹。

滴滴 NewSQL 演進之 Fusion 實踐

為了解決離線hive到Fusion的資料流動,我們做了一站式DTS平臺FastLoad,其架構設計如下:

首先,他誕生初期是為了解決標籤平臺和特徵平臺的業務問題。這兩個業務的資料是透過離線計算產生,因此資料是存放在hive上,很顯然hive的優勢並不是OLTP。

因此他們希望有個儲存系統能夠滿足兩個需求:

1. 支撐每天數百億次的高速查詢;

2. 支援他們快速的從離線更新TB級別的資料到線上。

很顯然Fusion很容易滿足第一個需求。那麼第二個需求如何解決呢?業務很容易想到的辦法是:遍歷讀取hive的資料,然後構造成一條條Redis協議支援的KV資料,然後呼叫Redis客戶端寫到我們的VIP->proxy->Fusion。整個過程鏈路比較長,總結下有3個核心痛點:

  1. 浪費研發資源。凡是有從hive到Fusion資料打通的業務,都得維護一套相同邏輯的程式碼。

  2. 難以保證穩定性。離線平臺意味著高吞吐、高併發,用它往線上資料庫灌資料,顯然得注意流控和錯峰,因此穩定性難以保證。

  3. 生產效率低。業務使用Redis協議的方式灌庫,很多batch和壓縮能力都沒法用上。

滴滴 NewSQL 演進之 Fusion 實踐

基於上述的業務需求和核心痛點,我們做了FastLoad一站式DTS平臺。它主要給RD、產品經理等使用者提供服務,因此提供了兩種接入方式:web console和open API。使用者透過這兩種方式,把FastLoad任務上傳到我們伺服器,然後伺服器會註冊一個排程任務,該排程任務透過使用者傳入引數,判定資料來源,然後從資料來源撈取目標資料,再把目標資料分片透過may/reduce做排序,構建SST檔案,然後透過TCP協議的方式下載到Fusion儲存節點,繞過proxy,利用RocksDB的ingest功能,載入到Fusion當中,再通知使用者,使用者就可以透過Redis協議讀到匯入的資料了。

滴滴 NewSQL 演進之 Fusion 實踐


第二個流動能力是叢集遷移。

它是指一個Fusion叢集到另一個Fusion叢集的資料線上熱遷移,包括全量和增量,遷移過程是線上不停服的,對使用者無感知的,這個功能可以用於業務一建開城、機房遷移等。它實現了兩個異構叢集間節點的點對點資料遷移。遷移的過程大概是:首先源節點保留增量日誌,同時構建全量快照,然後遍歷快照生成臨時的SST,再以SST檔案的方式傳送到對端master,master收到後轉發到slave,待全量同步完成,再開啟增量日誌的同步,其他細節如下。

滴滴 NewSQL 演進之 Fusion 實踐

亮點2:降級容災

首先Fusion具有主庫降級能力,當業務流量高峰時,導致主庫響應慢,此時擴容已經來不及,因此我們在proxy上實現了讀寫分離能力,即犧牲一定的一致性,把一部分讀流量路由到從庫,達到保全主庫的目的。

然後是叢集容災。即Fusion底層實現了兩個叢集間的資料自動同步。正常情況,使用者透過VIP1訪問叢集1的資料,當叢集1不可用時,我們提供兩種切流方案:第一種是,需要使用者切換訪問鏈路到VIP2,這可能需要使用者重啟;第二種是假設VIP可用,我們可以透過一鍵切流平臺,把VIP1指向的Real Server改到叢集2。

滴滴 NewSQL 演進之 Fusion 實踐

接下來看看是如何實現叢集間資料同步的。

我們實現了異構叢集間節點的點對點資料傳輸,不依賴任何中介軟體,每個節點會感知對端叢集的路由資訊,且能適應兩端叢集的狀態變化,比如切主、擴容等,都能保證資料由正確的節點發起,然後同步到正確的節點。整個資料的可靠性是由滑動視窗來保證的,即我們用寫到Fusion的key的唯一seq做滑動視窗的元素,實現了一個send/ack機制,保證了順序傳送、順序重傳、可靠傳送。

另外,該方案還支援資料的自動補償。即當叢集1掛掉後,使用者把流量切到叢集2,在叢集1恢復之前的這部分增量資料,會在叢集1恢復之後,自動同步過去。

最後,這個方案也支援雙寫。我們利用RocksDB的merge功能,做了一個基於NTP的去重方案。

滴滴 NewSQL 演進之 Fusion 實踐

亮點3:極致效率

這塊是針對RocksDB的一些特性做些最佳化。第一個我們實現了key粒度且具有熱點預測功能的cache,解決RocksDB隨機讀問題,命中率能達到原生的3倍;第二個是實現了compact的24小時排程,磁碟能節約25%,延遲和毛刺均有大幅度降低;第三個最佳化記憶體佔用,比如slave的page-cache是無用的,需要GC,block-cache在低峰時期是無用的,也需要GC等。

滴滴 NewSQL 演進之 Fusion 實踐

亮點4:安全保障

第一個是升級時資料備份。常規升級時,我們都會備份二進位制檔案和配置檔案,但是對於資料並沒有備份。我們針對RocksDB的SST檔案特性,即只會被建立和刪除,而不會被修改,做了一個硬連結備份方案,該方案是寫時複製,因此備份速度非常快且磁碟空間佔用非常少。更關鍵的是,這個方案是實現在智慧管控平臺的升級流程裡面,不需要改服務端程式碼,只需要修改管控程式就可以了,因此很方便做到100%線上覆蓋,保證資料安全。

第二個是提供使用者級別快照,利用了RocksDB的checkpoint,可以做到秒級快照。

第三個是資料多版本存放。即在FastLoad場景裡面,我們會保留多版本資料,用於使用者隨時隨地的切換他需要的資料,比如A/Btest,資料回滾等。

滴滴 NewSQL 演進之 Fusion 實踐

第二章:基於Fusion的NewSQL探索實踐

接下來討論NewSQL探索實踐的細節。

首先,需要回答一個問題,我們為什麼要做NewSQL演進?我想大家的出發點都是一樣的,都是為了解決在大資料量儲存下的MySQL的幾個核心問題,即:靈活問題、擴充套件問題、成本問題。那麼對應的NewSQL,我認為就該具備這樣幾個能力:輕鬆加欄位、儲存不限量、更高價效比。

那要實現這樣的目標,面臨哪些挑戰呢?

  1. 如何在KV系統上感知使用者schema?

  2. 如何在KV系統上吐出相容MySQL的binlog?

  3. 如何實現二級索引的儲存和查詢?

  4. 如何實現事務和事務的互動?

滴滴 NewSQL 演進之 Fusion 實踐

接下來,給出我們的NewSQL架構圖。首先我們把使用者的DDL操作,收斂到控制檯,不讓使用者直接給DB發起DDL操作,使用者發起的DDL操作,改變的schema資訊,會儲存到配置中心,同時會推送給我們的proxy,所有proxy推送成功後,返回給使用者成功資訊。使用者在透過MySQL客戶端訪問我們的proxy,我們在原來Redis協議的proxy上,增加了SQL-parser等工作,並將接受到的使用者SQL請求,轉成KV,再寫到Fusion。Fusion服務端會生成MySQL格式的binlog,再吐出到MQ,我們的索引伺服器會非同步消費這部分資訊,然後根據使用者自定義的索引key,把他寫到索引儲存裡即可。

滴滴 NewSQL 演進之 Fusion 實踐

schema管理

這塊的核心思路,就是把DDL操作與資料流分離,透過配置中心來解耦。Proxy這邊重點需要解析SQL,轉換KV等。目前Fusion支援insert/replace/delete/select/update語句,它的定位是解決單表大表的儲存問題,與MySQL做一定程度的互補,因此在相容MySQL上做了較大的捨棄。

這裡給了一個SQL到KV轉換的例子,左邊是一個student表,三行四列,右邊是Redis的hash編碼,大key有表名加主鍵組成,field是列名,value是行列值。

滴滴 NewSQL 演進之 Fusion 實踐

binlog相容

這塊是講如何吐出binlog的,因為滴滴的通用binlog是需要原值的,而KV預設的log是隻有當前值,因此我們在產生log的時候,先判斷使用者的插入型別,如果是update就先取原值,再一起寫到log裡,如果是insert則不需要。


滴滴 NewSQL 演進之 Fusion 實踐

二級索引(唯一和非唯一)

上述binlog吐出到MQ之後,這裡的索引模組會來消費MQ,並非同步構建索引(因為效能考慮和不具備分散式事務能力,因此沒有做實時索引)。索引key的拼接方式如下兩種,這裡需要注意的是,看前面Fusion的架構圖,我們知道Fusion叢集的資料分片是透過hash實現的,因此分片之間是不連續的,無法做到跨節點scan,因此我們對同一個列索引,增加了一個分割槽健,即Redis協議的hash-tag,來保證同一個索引,必須存到同一個節點,方便我們做scan。

滴滴 NewSQL 演進之 Fusion 實踐

事務功能

事實上我們不支援分散式事務,還是透過redis的hash-tag,規避了分散式事務,即跟使用者約定,讓使用者把希望做事務保證的行的主鍵,帶上hash-tag,讓這些行放到同一個節點。分散式事務就轉成單機事務了。而單機事務,我們利用了RocksDB的事務引擎,因為RocksDB再給MyRocks提供引擎時,支援了完備的事務能力,因此我們直接加以利用。最後要解決的是事務互動問題,這裡我們透過lua來解決。

滴滴 NewSQL 演進之 Fusion 實踐

事務互動

原生Redis對於事務互動處理支援的並不好,比如不支援回滾等,因此我們想要透過Redis來實現事務互動,就得增加一些介面,但這些介面顯然不是標準SDK提供的,就很難推廣。好在Redis客戶端提供了lua的指令碼支援,那麼Fusion也實現lua直譯器的功能,就可以讓使用者透過lua指令碼傳遞任何介面過來,這個特性可以很好的解耦。同時使用者可以在lua指令碼里實現各種if/else等邏輯。那麼當我們把事務互動透過lua提供後,使用者跟Fusion互動時,就可以把相關邏輯放到Fusion來執行,整個過程是一階段事務,不需要複雜的begin/commit/rollback等。我們的proxy也不需要維護事務狀態,內部的鎖處理也更簡單,不需要關心長事務,更不用關心事務裡多個key是否分佈在不同節點。

那在MySQL協議這邊如何實現事務呢?我們是建議使用者把lua指令碼寫到MySQL的comment裡,透過接下comment的lua,來執行事務。

滴滴 NewSQL 演進之 Fusion 實踐

總結

最後,對我們的NewSQL方案做個小結。他的優點很明顯,直接在現有NoSQL架構上加以迭代即可快速上線,複用程度高,穩定性高;同時在不需要事務的場景下,確實很好的解決了擴充套件問題、靈活問題;另外,在前面提到的hive到Fusion的打通中,讓使用者使用更自然,因為原先的FastLoad是把SQL結構化的資料轉成非SQL結構的KV的,現在有了NewSQL之後,使用者就可以從SQL到SQL。

這個方案上線一年,當前存入資料超過了400TB,總QPS超過了200W;接入的業務超過了58個,平均每個業務儲存8TB以上資料,可以看到這個資料量是MySQL不太容易解決的一個量級。

滴滴 NewSQL 演進之 Fusion 實踐

第三章:分散式資料庫設計

前面只提到了NewSQL方案的優點,實際上,它還是有很多不足的地方,最核心的問題是,他是一個”偽分散式“方案,雖然資料做到了無限擴充套件,但是:

  1. 只實現了單機事務。

  2. 只實現了單機索引。因為叢集按hash分片,無法跨機scan。

  3. 只有非同步索引能力。因為沒有分散式事務保證,我們只實現了非同步索引。

  4. Join更是不支援的。

  5. 無彈性擴容能力scale out。

很顯然,在現有的NoSQL架構上,已經無法簡單的解決這些需求,需要徹底大改。因此,我們有了另起爐灶的專案——分散式資料庫。它首要解決的幾個問題是:

  1. 分散式事務。

  2. 資料和索引的真正無限擴充套件。

  3. 實時索引。

  4. 彈性擴容。

  5. 多副本強一致、高可用。

  6. SQL相容等。

滴滴 NewSQL 演進之 Fusion 實踐

架構設計

架構設計如下,事實上,這也是分散式儲存的經典架構,很多的系統都長在類似架構上面,它實現了range分割槽、強一致、彈性擴容、全域性scan等能力。細節就不多做展開了。

滴滴 NewSQL 演進之 Fusion 實踐

當前狀況

我們在這套架構上,實現了一個具備raft強一致、全域性scan、自動分裂等能力的分散式KV系統,下一步是做分散式事務。即先實現一個功能強大的KV系統,然後在這基礎上繼續做SQL的支援。

總結三部曲

最後是對整個演進過程做一個總結。

首先我們研發了NoSQL系統Fusion,鍛鍊了我們的基礎能力:分散式、持久化、高可用、資料流動等。

第二步是我們的NewSQL探索,我們做了一個快速解決業務問題的方案,這個方案有成功的地方,因為它解決了50多個業務的需求,也有失敗的地方,我們無法在這套系統上走得更遠,但這提升了我們的系統認知,這很重要。

第三步是未來演進,想要在海量資料OLTP這條路走的更遠,必須徹底革命,因此最後的演進是拋棄了現有系統架構,從頭設計我們的分散式資料庫。這個專案也是分期的,一期我們先做一個功能強大的KV系統,然後二期在他的基礎上增加SQL-parser,取代我們現有的NewSQL方案(功能比較簡單,很容易落地),然後三期才是高度的SQL相容。

整個演進過程遵循了兩個原則:避免過度設計和大躍進。即在現有穩定的架構上花最小的代價,解決最短板問題。整個過程做到了產品的持續交付,既快速響應業務需求,又不斷豐富自己的認知,最終朝著一個成本可控、穩定迭代的目標前進。

滴滴 NewSQL 演進之 Fusion 實踐

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

相關文章