1. 程式人生 > 程式設計 >流量和延遲減半!挑戰分散式資料庫 TiDB 跨資料中心難題

流量和延遲減半!挑戰分散式資料庫 TiDB 跨資料中心難題

眾所周知,在對可用性要求極高的行業領域(比如金融、通訊),分散式資料庫需要跨地域的在多個資料中心之間建立容災以及多活的系統架構,同時需要保持資料完整可用。但這種方式同時也帶來了一些問題:

  1. 跨地域的網路延遲非常高,通常在幾十毫秒左右,洲際間更能達到幾百毫秒。
  2. 跨地域的網路專線頻寬昂貴、有限,且難於擴充套件。

在今年 TiDB Hackathon 的比賽過程中,我們針對以上問題做了一些有趣的事情,並獲得如下優化成果:

  1. 跨地域 SQL 查詢,延遲下降 50%(圖 1)。
  2. 跨節點訊息數減半,即網路流量減半(圖 2)。

圖 1 延遲對比

圖 1 延遲對比

圖 2 網路流量對比

圖 2 網路流量對比

“Google Spanner 高效能事務和強一致特性(跨區域甚至跨洲),是每一個做多資料中心架構設計的工程師心中所向往的目標。雖然當前 TiDB 在多資料中心部署時的表現同 Google Spanner 還有明顯的差距,但我們很高興的看到“多資料中心讀寫優化”專案讓 TiDB 向 Spanner 級別多資料中心能力邁出了堅實的一步。相信在社群小夥伴們的共同努力下,假以時日 TiDB 一定能夠為大家帶來 Google Spanner 級別的體驗。”

—— 孫曉光(知乎|技術平臺負責人)

“在官方推薦的具備同城多活能力的同城三中心五副本,以及兩地三中心五副本的部署方案中,三個資料中心按照 2:2:1 的方式分配副本,網路租用成本是該架構的主要投入,我們在一次壓力測試過程中,曾遇到過在極致的壓力下佔滿網路頻寬的情況。這個專案顯著優化了兩機房之間的頻寬佔用,可以為客戶節約更多的成本。”

—— 秦天爽(PingCAP|技術支援總監)

接下來我們將從技術原理分析是如何做到以上優化效果的。以下內容需要讀者具備 Raft 一致性協議 的一些預備知識,如果大家準備好了,就繼續往下看吧~

技術原理

如下圖所示,左右兩邊分別為兩個資料中心,並且為了方便起見,如圖 3 所示,左右兩邊分別為兩個資料中心,圖 3 左半部分為主資料中心(Master DC,假設在北京)TiKV 和 PD 的多數副本都部署在這裡,並且很重要的是 Leader 會被固定在這裡;圖 3 右半部分為從資料中心(Slave DC,假設在西安)裡面有 TiKV 和 TiDB。使用者只會在主資料中心進行資料寫入,但會在兩邊都進行資料讀取。

圖 3 主資料中心 & 從資料中心部署

圖 3 主資料中心 & 從資料中心部署

Follower Read Improvement

在 TiDB 裡面,當我們需要從西安這邊讀取資料的時候,一個典型的流程如下:

  1. 西安的 TiDB 向北京的 PD 發起獲取 TSO 請求,得到一個 start_ts(事務開始階段的 ID)。(1 RTT)

  2. 西安的 TiDB 為涉及到的每個 Region 向北京的 TiKV Leader 節點發起多個(並行)讀請求(如圖 4)。(1 RTT)

名詞解釋:

  • RTT(Round-Trip Time),可以簡單理解為傳送訊息方從傳送訊息到得知訊息到達所經過的時間。
  • TSO(Timestamp Oracle),用於表示分散式事務開始階段的 ID。

圖 4 不啟用 Follower Read 的讀流程

圖 4 不啟用 Follower Read 的讀流程

可以看到,雖然西安本地也有 TiKV 副本資料,但完全沒有參與這個過程。該實現存在兩個問題:

  • 跨地域網路寬頻佔用大。

  • 延遲高(2 RTT)。

下面我們分別闡述對這兩個問題的優化思路。

1. 跨地域網路寬頻佔用大

其實針對這個問題,TiDB 已經在 3.1 版本引入了 Follower Read 特性。開啟該特性後,TiKV Leader 上的節點從必須處理整個讀請求改為只用處理一次 read_index 請求(一次 read_index 通常只是位置資訊的互動,不涉及資料,所以輕量很多),負載壓力大幅降低,是一個很大的優化,如下圖所示。

圖 5 開啟 Follower Read 的讀流程

圖 5 開啟 Follower Read 的讀流程

2. 延遲高

在讀延遲上,TiDB 仍然需要 2 個跨地域的 RTT。這兩個 RTT 的延遲是由一次獲取 TSO 請求和多次(並行的)read_index 帶來的。簡單觀察後,我們不難發現,我們完全可以將上面兩個操作並行一起處理,如下圖所示。

圖 6 Follower Read 流程優化

圖 6 Follower Read 流程優化

通過這種優化方式,我們實現了跨資料中心讀請求 2RTT -> 1RTT 的提升,並且我們在模擬的高延遲網路環境中的 benchmark 證實了這一點:

圖 7 benchmark

圖 7 benchmark

考慮到沒有原子鐘的情況下想要保證線性一致性,一次獲取 TSO 的請求是無法避免的,因此可以認為 1RTT 已經是在目前的架構下最優的解決方案了。

用 Follower Replication 減少頻寬成本

接下來談一談如何用 Follower Replication 這種方式,減少跨資料中心的頻寬成本。

眾所周知 TiKV 叢集中的一致性是依靠 Raft 協議來保證的。在 Raft 協議中,所需要被共識一致的資料可以用 Entry 來表示。一個 Entry 被共識,需要 Leader 在接收到請求之後,廣播給其他 Follower 節點,之後通過不斷的訊息互動來使這個 Entry 被 commit。這裡可能會遇到一個問題:有些時候 TiKV 被部署在世界各地不同的資料中心中,資料中心之間的網路傳輸成本和延遲比較高,然而 Leader 只有一個,可想而知會發生很多次跨資料中心的訊息傳輸。

舉個例子,生產環境中可能需要 5 個副本來保證可用性,假設 3 個副本在北京分別是 A B C,2 個在西安分別是 D E,同時 Leader 為 A,那麼一條 Entry 需要北京的 Leader A,廣播給西安的 DE,那麼這次廣播至少需要兩次跨資料中心的網路傳輸,如下圖所示。

圖 8 正常的訊息廣播

圖 8 正常的訊息廣播

Follower Replication 的目標是將這個多次的跨資料中心傳輸儘量減少。要實現 Follower Replication,最關鍵的是需要讓 Leader 節點知道所有 Raft 節點與它所在的 資料中心的資訊。這裡我們引入了一個新概念 Group,每一個 Raft 節點都有一個對應的 Group ID,擁有相同 Group ID 的節點即在同一個資料中心中。既然有了每個 Raft 節點的 Group 資訊,Leader 就可以在廣播訊息時在每一個 Group 中選擇一個代理人節點(我們稱為 Follower  Delegate),將整個 Group 成員所需要的資訊發給這個代理人,代理人負責將資料同步給 Group 內的其他成員,如下圖所示。

圖 9 選擇代理人之後的訊息廣播

圖 9 選擇代理人之後的訊息廣播

通過使用 Follower Replication,Leader 減少了一半的資料傳送,既大大降低了跨資料中心頻寬的壓力,同時也減少了 Leader 在傳送網路訊息上的開銷。當然,實際 Follower Replication 的實現還是很複雜的,我們後續會專門寫一篇詳細的文章來介紹。

關於這個對 Raft 實現的改進,我們已經提交了 RFC 和實現的 PR,後續也會貢獻給 etcd,感興趣的同學可以參考:

總結

除了我們在 Hackathon 做的兩個優化,跨資料中心的場景有更多需要解決的問題和可以優化的點,我們的優化也遠非最終實現,一些不難想到的優化還有:

  1. Follower Read Improvement 能將一個非互動式的讀事務從 2RTT 降到 1RTT,但對於互動式的讀事務,由於事先不知道涉及到事務的 Region,無法預讀整個讀請求中所有 Region read_index,因此只有第一次讀請求和 get_tso 可以並行,將 n+1 RTT 優化到了 n RTT(n 為互動式事務中讀語句的數量),而如果我們能將 ts 和 committed index 的對應關係找到,並且定期維護每個 Region 的 safe ts(小於該 ts 的事務一定已經 committed or aborted),那麼我們就可以將互動式讀事務的延遲也降低到 1RTT。

  2. 跨資料中心的讀請求一個很常見的場景是並不需要是最新的資料,應該提供怎麼樣的語義來讓這種場景下的讀請求完全在本地 0RTT 地讀取資料,真正做到對主資料中心無依賴,做到資料中心級別的 scalability。

有句話是這樣說的,“對於基礎架構方向的軟硬體工程師而言,世界上最遠的距離,是你在聯通,我在電信 :D”軟體工程師做得越好,禿頂的硬體工程師就越少。希望我們的專案在切實落地之後,能夠大幅優化 TiDB 跨地域資料中心的延遲和網路流量,讓 TiDB 能夠滿足更多使用者的需求,成為分散式資料庫領域的事實標準。

作者介紹:.* team(成員:莊天翼、朱賀天、屈鵬、林豪翔)參加了 TiDB Hackathon 2019,他們專案「TiDB 跨資料中心方案的優化」斬獲了二等獎。