1. 程式人生 > 其它 >騰訊會議核心資料庫TDSQL,如何做到快速無損線上擴容?

騰訊會議核心資料庫TDSQL,如何做到快速無損線上擴容?

引言
自去年12月底釋出後,騰訊會議40天更新14個版本,8天緊急擴容超過10萬臺雲主機,投入的計算資源超100萬核。疫情復工期間,每週都有數萬家企業和政府相關機構使用騰訊會議復工復產,通過騰訊會議開拓了雲簽約、雲招標、雲面試、雲培訓等雲上協同場景。

騰訊會議這款雲視訊會議產品,日活躍賬戶數已超1000萬,成為當前中國最多人使用的視訊會議專用應用。目前,騰訊會議國際版也已經在超過100個國家和地區上線,助力全球戰疫。

作為騰訊會議核心資料庫,近期騰訊分散式資料庫 TDSQL 持續支撐騰訊會議應對快速增長的儲存容量和效能需求,為使用者提供高速流暢、穩定可靠的服務,在平穩應對流量突增,實現讓使用者無感知的情況下進行快速無損線上擴容的場景方面提供了最佳實踐案例。

一、不停機無損線性水平擴容

面對流量突增場景,保障系統高可用的第一要務是進行系統擴容,滿足業務的效能和容量需求。

回顧騰訊會議資料庫面對流量突增的過程,作為騰訊會議的重要系統基礎支援,隨著流量的持續暴漲,優化之後 TDSQL 進行了一輪快速的資料庫機器水平擴容實踐:

通過 TDSQL 策略豐富的讀寫分離技術,資料庫層面快速響應了持續增長的容量和效能需求。
為了儘可能的將讀請求分離,進一步降低對主節點的影響,TDSQL通過讀寫賬號分離、災備只讀例項等措施,將純只讀業務分離出來,進一步降低主節點的壓力提高整體的吞吐量。最終,25%的複雜查詢根據讀寫分離策略發往只讀例項,快速達到降低主節點的負載的效果。
健壯的分佈事務能力支撐,持續不斷地進行效能優化。
SQLEngine 作為協調節點,無狀態,能滿足業務層幾乎無限制的水平擴容需求。
不停機無損線性水平擴容,保障系統高可用、高效能,資料庫技術架構如何做到?中間有哪些看不見的坑,有沒有經過了實際驗證的最佳方案?

數字化轉型全域性發展正在提速,流量洪峰漸成常態****,未來,我們需要怎樣的分散式技術架構系統?

以下我們一一拆解。

二、水平擴容的背景和挑戰

就擴容來說,比較常見的就是兩種方式,一種是垂直擴容,一種是水平擴容。這兩種有不同的特點,優缺點其實也非常明顯。

水平擴容即將資料從一臺機器上拆分到多臺機器,通過將一臺物理機的請求分散到多臺來實現吞吐量的提升。垂直擴容是將資料從一臺低規格的物理機遷移到一臺高規格的裝置,通過物理硬體的提升實現吞吐量的提升。

跟垂直擴容對比,分散式水平擴容最大的優點是解決了垂直擴容的瓶頸問題——理論上水平擴容可以進行無限擴容,它可以通過增加機器的方式來動態適應業務的需求。

水平擴容和垂直擴容相比,它可以解決垂直擴容的問題,但是會引入一些其他的問題。因為水平擴容比垂直擴容更加複雜,下面我們分析下可能遇見的問題,以及介紹TDSQL架構設計的解決方案:

第一,系統經過垂直擴容,其實資料總體還是存在一個節點,一主多備架構中,備機上也儲存著所有資料。而水平擴容過程中資料會進行拆分,這裡面臨的第一個問題是,資料如何進行拆分?因為如果拆分不好,當出現熱點資料時,儲存熱點資料的單獨節點也有可能成為效能的瓶頸。

第二,水平擴容會涉及到資料的搬遷、路由的改變。那麼整個過程中能否做到對業務沒有感知?或者是對業務的侵入如何儘可能地降低?

第三,擴過程中的諸多步驟,如果其中一步失敗了,如何進行回滾?同時,在整個擴容過程中,如何能保證切換過程中資料一致性?

第四,由於擴容後資料拆分到了各個節點,如何能保證擴容後的效能?在整個水平擴容的過程中,不同的架構或者不同的方式,對效能影響都比較大。

第五,當資料已經拆分成多份,如何繼續保證資料庫分散式的特性?在分散式架構裡,如何保證資料跨節點過程中的全域性的一致性?這個就會涉及到分散式事務。

綜上考慮,水平擴容的優點很明顯,它解決了垂直擴容機器的限制。但是它更復雜,引入了更多的問題。那麼 TDSQL 是如何進行水平擴容,又是如何解決上述問題的呢?

三、TDSQL水平擴容實踐

1. TDSQL架構
首先看TDSQL的架構。TDSQL簡單來說包含幾部分:

第一部分是SQL引擎層:主要是作為接入端,遮蔽整個 TDSQL 後端的資料儲存細節。對業務來說,業務訪問的是SQL引擎層。

接下來是由多個Set組成的資料儲存層:分散式資料庫中,資料儲存在各個節點上,每個Set我們當做一個數據單元,可以根據業務需要來部署一主兩備或者一主多備。對於對資料安全性要求更高的業務場景,可以一主三備甚至一主四備。

Scheduler模組:主要負責整個系統叢集的監控、控制。在系統進行擴容或者主備切換時,Scheduler模組相當於整個系統的大腦,來對系統進行控制。而對業務來說是無感知的,業務只需關注SQL引擎層,不需要關注Scheduler,不需要關注資料是怎麼跨節點,怎麼分成多少個節點等。

2. TDSQL水平擴容過程:一鍵擴容
整個擴容流程總結起來大概是:一開始資料都放在一個Set上,也就是在一個節點裡面。擴容則會把資料擴容到多個節點上。比如有256個Set,就會擴容到256臺機器上。整個擴容過程有幾個要點:

一開始雖然資料是在一個節點上,在一臺機器上,但是其實資料已經進行了拆分。
水平擴容,簡單來說是將這些分片遷移到其他的Set上,也就是其他的節點機器上,這樣就可以實現增加機器來提供系統性能。
總結來說,資料一開始已經切分好了,擴容過程相當於把分片遷到新的節點,整個擴容過程中,節點數是增加的,可以從1擴到2擴到4,甚至擴到最後可以到256,但是分片數是不變的。一開始256個分片在一個節點上,擴成兩個節點的話,有可能是每128個分片在一個節點上;擴到最後,可以擴到256個節點上,資料在256臺機器,每臺機器負責其中的一個分片。因此整個擴容簡單來說就是搬遷分片。

無論是在私有云或公有云上, TDSQL提供了一個統一的前臺頁面,方便使用者使用管理整個資料庫系統。

四、TDSQL水平擴容背後的設計原理

為了保證分散式資料庫系統的資料強一致性、快速線性水平擴容、高效能、高可用等,解決前文提到的問題,TDSQL架構方案進行了相應的設計。事實上,這些問題不管在哪個系統做水平擴容,都是需要解決的。

1. 設計原理:分割槽鍵選擇如何兼顧相容性與效能
水平擴容第一個問題是資料如何進行拆分。資料拆分是第一步,將影響後續整個使用過程。

在TDSQL中,資料拆分的邏輯放到一個建立表的語法裡面,需要業務去指定 “shardkey等於某個欄位”——業務在設計表結構時需要選擇一個欄位作為分割槽鍵,TDSQL會根據這個分割槽鍵進行資料拆分,而訪問會根據分割槽鍵進行資料聚合。

我們是希望業務在設計表結構的時候能夠參與進來,指定一個欄位作為shardkey。這樣一來,相容性與效能都能做到很好的平衡。

TDSQL也可以做到使用者建立表的時候不指定shardkey,由系統底層隨機選擇一個鍵進行資料拆分,但這個會影響後續的使用效率,比如不能特別好地發揮分散式資料庫的使用效能。因此,業務層如果在設計表結構時能有少量參與,可以帶來非常大的效能優勢,讓相容性和效能得到平衡。

除此之外,如果由業務來選擇shardkey——分割槽鍵,在業務設計表結構的時候,我們可以看到多個表,可以選擇相關的那一列作為shardkey,這樣可以保證資料拆分時,相關的資料是放在同一個節點上的,這樣可以避免很多分散式情況下的跨節點的資料互動。

2. 設計原理:擴容中的高可用和高可靠性

擴容流程比較複雜,那麼整個擴容過程能否保證高可用或者高可靠性,以及對業務無感知?TDSQL是怎麼做的呢?

(1)資料同步
第一步是資料同步階段。假設我們現在有兩個Set,然後我們發現其中一個Set現在的磁碟容量已經比較危險了,比如可能達到80%以上了,這個時候要對它進行擴容。

我們首先會新建一個例項,通過拷貝映象、新建例項、新建同步關係。建立同步的過程對業務無感知,而且這個過程是實時同步。

(2)資料校驗
第二階段,則是持續地追平資料,同時持續進行資料校驗。這個過程可能會持續一段時間,對於兩個同步之間的延時差無限接近時——比如我們定一個5秒的閾值,當我們發現已經追到5秒之內時,這個時候我們會進入第三個階段——路由更新階段。

(3)路由更新
路由更新階段當中,首先我們會凍結寫請求,這個時候如果業務有寫過來的話,我們會拒掉,讓業務兩秒後重試——這個時候對業務其實是有秒級的影響。但是這個時間會非常短。

凍結寫請求之後,第三個例項同步的時候很快就會發現資料全部追上來,並且校驗也沒問題,這個時候我們會修改路由,同時進行相關原子操作,在底層做到儲存層分割槽遮蔽,這樣就能保證SQL接入層在路由來不及更新的時資料也不會寫錯。因為底層做了改變,分割槽已經遮蔽了。這樣就可以保證資料的一致性。

路由一旦更新好以後,第三個Set就可以接收使用者的請求——到了這裡,因為第一個Set和第三個Set已經建立了同步,所以它們兩個是擁有全量資料的。

(4)刪除冗餘資料
最後一步則需要把這些冗餘資料刪掉。刪冗餘資料用的是延遲刪除,保證刪除過程中可以慢慢刪,也不會造成比較大的IO波動,影響現網的業務。

整個刪除過程中,我們做了分割槽遮蔽,同時會在SQL引擎層做SQL的改寫,這樣就能保證:我們在底層雖然有冗餘資料,但使用者來查的時候即使是一個全掃描,我們也能保證不會多一些資料。

可以看到整個擴容流程,資料同步,還有校驗和刪除冗餘這幾個階段,時間耗費相對來說會比較長,因為要建同步的話,如果資料量比較大,整個拷貝映象或者是追binlog這段時間相對比較長。

但是這幾個階段對業務其實沒有任何影響,業務根本就沒感知到現在新加了一個同步關係。那麼假如在建立同步關係時發現有問題,或者新建備機時出問題了,也完全可以再換一個備機,或者是經過重試,這個對業務沒有影響。

路由更新階段,理論上對業務寫請求難以避免會造成秒級的影響,但我們會將這個影響時間視窗期控制在非常短,因為本身凍結寫請求是需要保證同步已經在5秒之內這樣一個比較小的閾值,同步到這個階段以後,我們才能發起路由更新操作。

同時,我們對儲存層做了分割槽遮蔽來保證多個模組之間,如果有更新不同時也不會有資料錯亂的問題。這是一個我們如何保證擴容中的高可用跟高可靠性的,整個擴容對業務影響非常小的原理過程。

3. 設計原理:分散式事務

剛才講的是擴容階段大概的流程,以及TDSQL是如何解決問題的。接下來我們再看擴容完成以後,如何解決剛才說的水平擴容以後帶來的問題。

首先是分散式事務:原子性、去中心化、效能線性增長。

系統本來只有一個節點,擴容以後,資料是跨節點了,如何保證資料的原子性?我們基於兩階段的提交,實現了分散式事務。對業務遮蔽了整個處理邏輯背後的複雜性,對業務來說使用分散式資料庫就跟使用單機MySQL一樣。

如果業務這條SQL只訪問一個節點,那用普通的事務就可以;如果發現使用者的一條SQL或者一個事務操作了多個節點,我們會用兩階段提交。到最後會通過記日誌來保證整個分散式事務的原子性。

同時我們對整個分散式事務在實現過程中做到完全去中心化,可以通過多個SQL來做TM,效能也可實現線性增長。除此之外,TDSQL也做了大量的各種各樣的異常驗證機制,有非常健壯的異常處理和全域性的試錯機制,並且通過了TPCC的標準驗證。

4. 設計原理:如何實現擴容中效能線性增長
對於水平擴容來說,資料拆分到多個節點後主要帶來兩個問題:一個是事務原子性的問題,可以通過分散式事務來解決;此外還帶來了效能方面的問題。

垂直擴容中一般是通過更換更好的CPU等方法來實現效能線性增加。對於水平擴容,因為資料拆分到多個節點上,如何才能很好地利用到拆分下去的各個節點,進行平行計算,真正把水平分散式資料庫的優勢發揮出來,需要大量的操作、大量的優化措施。TDSQL做了這樣一些優化措施:

一是相關資料存在同一個節點上。建表結構的時候,我們希望業務能參與進來一部分,在設計表結構的時候指定相關的一些鍵作為shardkey,這樣我們就能保證後端的相關資料是在一個節點上的。如果對這些資料進行聯合查詢就不需要跨節點。

同樣,我們通過平行計算、流式聚合來實現效能提升——我們把SQL拆分分發到各個後臺的節點,然後通過每個節點平行計算,計算好以後再通過SQL引擎來做二次聚合,然後返回給使用者。

為了減少資料的拉取,我們會做一些下推的查詢——把更多的條件下推到DB上。此外我們也做了資料冗餘,通過資料冗餘保證儘量減少跨節點的資料互動。

我們簡單看一個聚合——TDSQL是如何做到水平擴容以後,對業務基本無感知,使用方式跟使用單機MySQL一樣的。

對業務來說,假設有7條資料,業務不用管這個表具體資料是存在一個節點還是多個節點,只需要插7條資料。系統會根據傳過來的SQL進行語法解析,並自動把這條資料進行改寫。7條資料,系統會根據分割槽鍵計算,發現這4個要發到第一個節點,另外3個發到第二個節點,然後進行改寫,改寫好之後插入這些資料。對使用者來說,就是執行了這麼一條,但是跨節點了,我們這邊會用到兩階段提交,從而變成多條SQL,進而保證一旦有問題兩邊會同時回滾。

資料插錄完以後,使用者如果要做一些查詢——事實上使用者不知道資料是拆分的,對他來說就是一個完整的表,他用類似聚合函式等進行查詢。同樣,這條SQL也會進行改寫,系統會把這條SQL發到兩個節點上,同時加一些平均函式,進行相應的轉換。到了各個節點,系統會先做資料聚合,到這邊再一次做聚合。

增加這個步驟的好處是,這邊過來的話,我們可以通過做聚合——相當於在這裡不需要快取太多的資料,並且做到流式計算,避免出現一次性消耗太多記憶體的情況。

以上是TDSQL水平擴容方案設計原理以及實踐過程的介紹。

結語
除了騰訊會議,疫情期間,TDSQL 還基於騰訊雲快速支援了多地區健康碼、市政防控平臺小程式等高併發、籌備時間短的專案應用順利上線、穩定執行,服務民眾數億,日均呼叫數十億次。

基礎技術的積累讓我們今天擁有順利應對一切突發變化的能力,未來基於新型業務形態,我們的底層基礎技術也將不斷迭代演進,開啟下一個數字化時代。