新一代資料庫TiDB在美團的實踐

美團技術團隊發表於2018-11-28

1. 背景和現狀

近幾年,基於MySQL構建的傳統關係型資料庫服務,已經很難支撐美團業務的爆發式增長,這就促使我們去探索更合理的資料儲存方案和實踐新的運維方式。而隨著分散式資料庫大放異彩,美團DBA團隊聯合基礎架構儲存團隊,於 2018年初啟動了分散式資料庫專案。

新一代資料庫TiDB在美團的實踐
圖 1 美團點評產品展示圖

在立項之初,我們進行了大量解決方案的對比,深入瞭解了業界的 scale-out(橫向擴充套件)、scale-up(縱向擴充套件)等解決方案。但考慮到技術架構的前瞻性、發展潛力、社群活躍度以及服務本身與 MySQL 的相容性,我們最終敲定了基於 TiDB 資料庫進行二次開發的整體方案,並與 PingCAP 官方和開源社群進行深入合作的開發模式。

美團業務線眾多,我們根據業務特點及重要程度逐步推進上線,到截稿為止,已經上線了 10 個叢集,近 200 個物理節點,大部分是 OLTP 型別的應用,除了上線初期遇到了一些小問題,目前均已穩定執行。初期上線的叢集,已經分別服務於配送、出行、閃付、酒旅等業務。雖然 TiDB 的架構分層相對比較清晰,服務也是比較平穩和流暢,但在美團當前的資料量規模和已有穩定的儲存體系的基礎上,推廣新的儲存服務體系,需要對周邊工具和系統進行一系列改造和適配,從初期探索到整合落地,仍然還需要走很遠的路。下面將從以下幾個方面分別進行介紹:

  • 從 0 到 1 的突破,重點考慮做哪些事情。
  • 如何規劃實施不同業務場景的接入和已有業務的遷移。
  • 上線後遇到的一些典型問題介紹。
  • 後續規劃和對未來的展望。

2. 前期調研測試

2.1  對 TiDB 的定位

我們對於 TiDB 的定位,前期在於重點解決 MySQL 的單機效能和容量無法線性和靈活擴充套件的問題,與 MySQL 形成互補。業界分散式方案很多,我們為何選擇了 TiDB 呢?考慮到公司業務規模的快速增長,以及公司內關聯式資料庫以 MySQL 為主的現狀,因此我們在調研階段,對以下技術特性進行了重點考慮:

  • 協議相容 MySQL:這個是必要項。
  • 可線上擴充套件:資料通常要有分片,分片要支援分裂和自動遷移,並且遷移過程要儘量對業務無感知。
  • 強一致的分散式事務:事務可以跨分片、跨節點執行,並且強一致。
  • 支援二級索引:為相容 MySQL 的業務,這個是必須的。
  • 效能:MySQL 的業務特性,高併發的 OLTP 效能必須滿足。
  • 跨機房服務:需要保證任何一個機房當機,服務能自動切換。
  • 跨機房雙寫:支援跨機房雙寫是資料庫領域一大難題,是我們對分散式資料庫的一個重要期待,也是美團下一階段重要的需求。

業界的一些傳統方案雖然支援分片,但無法自動分裂、遷移,不支援分散式事務,還有一些在傳統 MySQL 上開發一致性協議的方案,但它無法實現線性擴充套件,最終我們選擇了與我們的需求最為接近的 TiDB。與 MySQL 語法和特性高度相容,具有靈活的線上擴容縮容特性,支援 ACID 的強一致性事務,可以跨機房部署實現跨機房容災,支援多節點寫入,對業務又能像單機 MySQL 一樣使用。

2.2  測試

針對官方聲稱的以上優點,我們進行了大量的研究、測試和驗證。

首先,我們需要知道擴容、Region 分裂轉移的細節、Schema 到 KV 的對映、分散式事務的實現原理。而 TiDB 的方案,參考了較多的 Google 論文,我們進行了閱讀,這有助於我們理解 TiDB 的儲存結構、事務演算法、安全性等,包括:

  • Spanner: Google’s Globally-Distributed Database
  • Large-scale Incremental Processing Using Distributed Transactions and Notifications
  • In Search of an Understandable Consensus Algorithm
  • Online, Asynchronous Schema Change in F1

我們也進行了常規的效能和功能測試,用來與 MySQL 的指標進行對比,其中一個比較特別的測試,是證明 3 副本跨機房部署,確實能保證每個機房分佈一個副本,從而保證任何一個機房當機不會導致丟失超過半數副本。我們從以下幾個點進行了測試:

  • Raft 擴容時是否支援 Learner 節點,從而保證單機房當機不會丟失 2/3 的副本。
  • TiKV 上的標籤優先順序是否可靠,保證當機房的機器不平均時,能否保證每個機房的副本數依然是絕對平均的。
  • 實際測試,單機房當機,TiDB 在高併發下,QPS、響應時間、報錯數量,以及最終資料是否有丟失。
  • 手動 Balance 一個 Region 到其他機房,是否會自動回來。

從測試結果來看,一切都符合我們的預期。

3. 儲存生態建設

美團的產品線豐富,業務體量也比較大,業務對線上儲存的服務質量要求也非常高。因此,從早期做好服務體系的規劃非常重要。下面從業務接入層、監控報警、服務部署等維度,來分別介紹一下我們所做的工作。

3.1  業務接入層

當前 MySQL 的業務接入方式主要有兩種,DNS 接入和 Zebra 客戶端接入。在前期調研階段,我們選擇了 DNS + 負載均衡元件的接入方式,TiDB-Server 節點當機,15s 可以被負載均衡識別到,簡單且有效。業務架構如下圖所示:

新一代資料庫TiDB在美團的實踐
圖 2 業務架構圖

後面,我們會逐漸過渡到當前大量使用的 Zebra 接入方式來訪問 TiDB,從而保持與訪問 MySQL 的方式一致,一方面減少業務改造的成本,另一方面儘量實現從 MySQL 到 TiDB 的透明遷移。

3.2  監控報警

美團目前使用 Mt-Falcon 平臺負責監控報警,通過在 Mt-Falcon 上配置不同的外掛,可以實現對多種元件的自定義監控。另外也會結合 Puppet 識別不同使用者的許可權、檔案的下發。只要我們編寫好外掛指令碼、需要的檔案,裝機和許可權控制就可以完成了。監控架構如下圖所示:

新一代資料庫TiDB在美團的實踐
圖 3 監控架構圖

而 TiDB 有豐富的監控指標,使用流行的 Prometheus + Grafana,一套叢集有 700+ 的 Metric。從官方的架構圖可以看出,每個元件會推送自己的 Metric 給 PushGateWay,Prometheus 會直接到 PushGateWay 去抓資料。

由於我們需要元件收斂,原生的 TiDB 每個叢集一套 Prometheus 的方式不利於監控的彙總、分析、配置,而報警已經在 Mt-Falcon 上實現的比較好了,在 AlertManager 上再造一個也沒有必要。因此我們需要想辦法把監控和報警彙總到 Mt-Falcon 上面,包括如下幾種方式:

  • 方案一:修改原始碼,將 Metric 直接推送到 Falcon,由於 Metric 散落在程式碼的不同位置,而且 TiDB 程式碼迭代太快,把精力消耗在不停調整監控埋點上不太合適。
  • 方案二:在 PushGateWay 是彙總後的,可以直接抓取,但 PushGateWay 是個單點,不好維護。
  • 方案三:通過各個元件(TiDB、PD、TiKV)的本地 API 直接抓取,優點是元件當機不會影響其他元件,實現也比較簡單。

我們最終選擇了方案三。該方案的難點是需要把 Prometheus 的資料格式轉化為 Mt-Falcon 可識別的格式,因為 Prometheus 支援 Counter、Gauge、Histogram、Summary 四種資料型別,而 Mt-Falcon 只支援基本的 Counter 和 Gauge,同時 Mt-Falcon 的計算表示式比較少,因此需要在監控指令碼中進行轉換和計算。

3.3  批量部署

TiDB 使用 Ansible 實現自動化部署。迭代快,是 TiDB 的一個特點,有問題能快速進行解決,但也造成 Ansible 工程、TiDB 版本更新過快,我們對 Ansible 的改動,也只會增加新的程式碼,不會改動已有的程式碼。因此線上可能同時需要部署、維護多個版本的叢集。如果每個叢集一個 Ansible 目錄,造成空間的浪費。

我們採用的維護方式是,在中控機中,每個版本一個 Ansible 目錄,每個版本中通過不同 inventory 檔案來維護。這裡需要跟 PingCAP 提出的是,Ansible 只考慮了單叢集部署,大量部署會有些麻煩,像一些依賴的配置檔案,都不能根據叢集單獨配置(諮詢官方得知,PingCAP 目前正在基於 Cloud TiDB 打造一站式 HTAP 平臺,會提供批量部署、多租戶等功能,後續會比較好地解決這個問題)。

3.4  自動化運維平臺

隨著線上叢集數量的增加,打造運維平臺提上了日程,而美團對 TiDB 和 MySQL 的使用方式基本相同,因此 MySQL 平臺上具有的大部分元件,TiDB 平臺也需要建設。典型的底層元件和方案:SQL 稽核模組、DTS、資料備份方案等。自動化運維平臺展示如下圖所示:

新一代資料庫TiDB在美團的實踐
圖 4 自動化運維平臺展示圖

3.5  上下游異構資料同步

TiDB 是線上儲存體系中的一環,它同時也需要融入到公司現有的資料流中,因此需要一些工具來做銜接。PingCAP 官方標配了相關的元件。

公司目前 MySQL 和 Hive 結合的比較重,而 TiDB 要代替 MySQL 的部分功能,需要解決 2 個問題:

  • MySQL to TiDB
    • MySQL 到 TiDB 的遷移,需要解決資料遷移以及增量的實時同步,也就是 DTS,Mydumper + Loader 解決存量資料的同步,官方提供了 DM 工具可以很好的解決增量同步問題。
    • MySQL 大量使用了自增 ID 作為主鍵。分庫分表 MySQL 合併到 TiDB 時,需要解決自增 ID 衝突的問題。這個通過在 TiDB 端去掉自增 ID 建立自己的唯一主鍵來解決。新版 DM 也提供分表合併過程主鍵自動處理的功能。
  • Hive to TiDB & TiDB to Hive
    • Hive to TiDB 比較好解決,這體現了 TiDB 和 MySQL 高度相容的好處,insert 語句可以不用調整,基於 Hive to MySQL 簡單改造即可。
    • TiDB to Hive 則需要基於官方 Pump + Drainer 元件,Drainer 可以消費到 Kafka、MySQL、TiDB,我們初步考慮用圖 5 中的方案通過使用 Drainer 的 Kafka 輸出模式同步到 Hive。

新一代資料庫TiDB在美團的實踐
圖 5 TiDB to Hive 方案圖

4. 線上使用磨合

對於初期上線的業務,我們比較謹慎,基本的原則是:離線業務 -> 非核心業務 -> 核心業務。TiDB 已經發布兩年多,且前期經歷了大量的測試,我們也深入瞭解了其它公司的測試和使用情況,可以預期的是 TiDB 上線會比較穩定,但依然遇到了一些小問題。總體來看,在安全性、資料一致性等關鍵點上沒有出現問題。其他一些效能抖動問題,引數調優的問題,也都得到了快速妥善的解決。這裡給 PingCAP 的同學點個大大的贊,問題響應速度非常快,與我們美團內部研發的合作也非常融洽。

4.1  寫入量大、讀 QPS 高的離線業務

我們上線的最大的一個業務,每天有數百 G 的寫入量,在前期,我們也遇到了較多的問題。

業務場景:

  • 穩定的寫入,每個事務操作 100~200 行不等,每秒 6W 的資料寫入。
  • 每天的寫入量超過 500G,以後會逐步提量到每天 3T。
  • 每 15 分鐘的定時讀 Job,5000 QPS(高頻量小)。
  • 不定時的查詢(低頻量大)。

之前使用 MySQL 作為儲存,但 MySQL 到達了容量和效能瓶頸,而業務的容量未來會 10 倍的增長。初期調研測試了 ClickHouse,滿足了容量的需求,測試發現執行低頻 SQL 沒有問題,但高頻 SQL 的大併發查詢無法滿足需求,只在 ClickHouse 跑全量的低頻 SQL 又會 overkill,最終選擇使用 TiDB。

測試期間模擬寫入了一天的真實資料,非常穩定,高頻低頻兩種查詢也都滿足需求,定向優化後 OLAP 的 SQL 比 MySQL 效能提高四倍。但上線後,陸續發現了一些問題,典型的如下:

4.1.1  TiKV 發生 Write Stall

TiKV 底層有 2 個 RocksDB 作為儲存。新寫的資料寫入 L0 層,當 RocksDB 的 L0 層數量達到一定數量,就會發生減速,更高則發生 Stall,用來自我保護。TiKV 的預設配置:

  • level0-slowdown-writes-trigger = 20
  • level0-stop-writes-trigger = 36

遇到過的,發生 L0 檔案過多可能的原因有 2 個:

  • 寫入量大,Compact 完不成。
  • Snapshot 一直建立不完,導致堆積的副本一下釋放,RocksDB-Raft 建立大量的 L0 檔案,監控展示如下圖所示:

新一代資料庫TiDB在美團的實踐
圖 6 TiKV 發生 Write Stall 監控展示圖

我們通過以下措施,解決了 Write Stall 的問題:

  • 減緩 Raft Log Compact 頻率(增大 raft-log-gc-size-limit、raft-log-gc-count-limit)
  • 加快 Snapshot 速度(整體效能、包括硬體效能)
  • max-sub-compactions 調整為 3
  • max-background-jobs 調整為 12
  • level 0 的 3 個 Trigger 調整為 16、32、64

4.1.2  Delete 大量資料,GC 跟不上

現在 TiDB 的 GC 對於每個 kv-instance 是單執行緒的,當業務刪除資料的量非常大時,會導致 GC 速度較慢,很可能 GC 的速度跟不上寫入。

目前可以通過增多 TiKV 個數來解決,長期需要靠 GC 改為多執行緒執行,官方對此已經實現,即將釋出。

4.1.3  Insert 響應時間越來越慢

業務上線初期,insert 的響應時間 80 線(Duration 80 By Instance)在 20ms 左右,隨著執行時間增加,發現響應時間逐步增加到 200ms+。期間排查了多種可能原因,定位在由於 Region 數量快速上漲,Raftstore 裡面要做的事情變多了,而它又是單執行緒工作,每個 Region 定期都要 heartbeat,帶來了效能消耗。tikv-raft propose wait duration 指標持續增長。

解決問題的辦法:

  • 臨時解決。
  • 增加 Heartbeat 的週期,從 1s 改為 2s,效果比較明顯,監控展示如下圖所示:

新一代資料庫TiDB在美團的實踐
圖 7 insert 響應時間優化前後對比圖

  • 徹底解決。
  • 需要減少 Region 個數,Merge 掉空 Region,官方在 2.1 版本中已經實現了 Region Merge 功能,我們在升級到 2.1 後,得到了徹底解決。
  • 另外,等待 Raftstore 改為多執行緒,能進一步優化。(官方回覆相關開發已基本接近尾聲,將於 2.1 的下一個版本釋出。)

4.1.4  Truncate Table 空間無法完全回收

DBA Truncate 一張大表後,發現 2 個現象,一是空間回收較慢,二是最終也沒有完全回收。

  • 由於底層 RocksDB 的機制,很多資料落在 Level 6 上,有可能清不掉。這個需要開啟 cdynamic-level-bytes 會優化 Compaction 的策略,提高 Compact 回收空間的速度。
  • 由於 Truncate 使用 delete_files_in_range 介面,發給 TiKV 去刪 SST 檔案,這裡只刪除不相交的部分,而之前判斷是否相交的粒度是 Region,因此導致了大量 SST 無法及時刪除掉。
  • 考慮 Region 獨立 SST 可以解決交叉問題,但是隨之帶來的是磁碟佔用問題和 Split 延時問題。
  • 考慮使用 RocksDB 的 DeleteRange 介面,但需要等該介面穩定。
  • 目前最新的 2.1 版本優化為直接使用 DeleteFilesInRange 介面刪除整個表佔用的空間,然後清理少量殘留資料,目前已經解決。

4.1.5  開啟 Region Merge 功能

為了解決 region 過多的問題,我們在升級 2.1 版本後,開啟了 region merge 功能,但是 TiDB 的響應時間 80 線(Duration 80 By Instance)依然沒有恢復到當初,保持在 50ms 左右,排查發現 KV 層返回的響應時間還很快,和最初接近,那麼就定位了問題出現在 TiDB 層。研發人員和 PingCAP 定位在產生執行計劃時行為和 2.0 版本不一致了,目前已經優化。

4.2  線上 OLTP,對響應時間敏感的業務

除了分析查詢量大的離線業務場景,美團還有很多分庫分表的場景,雖然業界有很多分庫分表的方案,解決了單機效能、儲存瓶頸,但是對於業務還是有些不友好的地方:

  • 業務無法友好的執行分散式事務。
  • 跨庫的查詢,需要在中間層上組合,是比較重的方案。
  • 單庫如果容量不足,需要再次拆分,無論怎樣做,都很痛苦。
  • 業務需要關注資料分佈的規則,即使用了中間層,業務心裡還是沒底。

因此很多分庫分表的業務,以及即將無法在單機承載而正在設計分庫分表方案的業務,主動找到了我們,這和我們對於 TiDB 的定位是相符的。這些業務的特點是 SQL 語句小而頻繁,對一致性要求高,通常部分資料有時間屬性。在測試及上線後也遇到了一些問題,不過目前基本都有了解決辦法。

4.2.1  SQL  執行超時後,JDBC 報錯

業務偶爾報出 privilege check fail。

是由於業務在 JDBC 設定了 QueryTimeout,SQL 執行超過這個時間,會發行一個 kill query 命令,而 TiDB 執行這個命令需要 Super 許可權,業務是沒有許可權的。其實 kill 自己的查詢,並不需要額外的許可權,目前已經解決了這個問題: github.com/pingcap/tid…,不再需要 Super 許可權,已在 2.0.5 上線。

4.2.2  執行計劃偶爾不準

TiDB 的物理優化階段需要依靠統計資訊。在 2.0 版本統計資訊的收集從手動執行,優化為在達到一定條件時可以自動觸發:

  • 資料修改比例達到 tidb_auto_analyze_ratio。
  • 表一分鐘沒有變更(目前版本已經去掉這個條件)。

但是在沒有達到這些條件之前統計資訊是不準的,這樣就會導致物理優化出現偏差,在測試階段(2.0 版本)就出現了這樣一個案例:業務資料是有時間屬性的,業務的查詢有 2 個條件,比如:時間+商家 ID,但每天上午統計資訊可能不準,當天的資料已經有了,但統計資訊認為沒有。這時優化器就會建議使用時間列的索引,但實際上商家 ID 列的索引更優化。這個問題可以通過增加 Hint 解決。

在 2.1 版本對統計資訊和執行計劃的計算做了大量的優化,也穩定了基於 Query Feedback 更新統計資訊,也用於更新直方圖和 Count-Min Sketch,非常期待 2.1 的 GA。

5. 總結展望

經過前期的測試、各方的溝通協調,以及近半年對 TiDB 的使用,我們看好 TiDB 的發展,也對未來基於 TiDB 的合作充滿信心。

接下來,我們會加速推進 TiDB 在更多業務系統中的使用,同時也將 TiDB 納入了美團新一代資料庫的戰略選型中。當前,我們已經全職投入了 3 位 DBA 同學和多位儲存計算專家,從底層的儲存,中間層的計算,業務層的接入,再到儲存方案的選型和佈道,進行全方位和更深入的合作。

長期來看,結合美團不斷增長的業務規模,我們將與 PingCAP 官方合作打造更強大的生態體系:

  • Titan:Titan 是 TiDB 下一步比較大的動作,也是我們非常期待的下一代儲存引擎,它對大 Value 支援會更友好,將解決我們單行大小受限,單機 TiKV 最大支援儲存容量的問題,大大提升大規模部署的價效比。
  • Cloud TiDB (Based on Docker & K8s):雲端計算大勢所趨,PingCAP 在這塊也佈局比較早,今年 8 月份開源了 TiDB Operator,Cloud TiDB 不僅實現了資料庫的高度自動化運維,而且基於 Docker 硬體隔離,實現了資料庫比較完美的多租戶架構。我們和官方同學溝通,目前他們的私有云方案在國內也有重要體量的 POC,這也是美團看重的一個方向。
  • TiDB HTAP Platform:PingCAP 在原有 TiDB Server 計算引擎的基礎上,還構建 TiSpark 計算引擎,和他們官方溝通,他們在研發了一個基於列的儲存引擎,這樣就形成了下層行、列兩個儲存引擎、上層兩個計算引擎的完整混合資料庫(HTAP),這個架構不僅大大的節省了核心業務資料在整個公司業務週期裡的副本數量,還通過收斂技術棧,節省了大量的人力成本、技術成本、機器成本,同時還解決了困擾多年的 OLAP 的實效性。後面我們也會考慮將一些有實時、準實時的分析查詢系統接入 TiDB。

新一代資料庫TiDB在美團的實踐
<圖 8 TiDB HTAP Platform 整體架構圖

  • 後續的物理備份方案,跨機房多寫等也是我們接下來逐步推進的場景,總之,我們堅信未來 TiDB 在美團的使用場景會越來越多,發展也會越來越好。

目前,TiDB 在業務層面、技術合作層面都已經在美團揚帆起航,美團點評將攜手 PingCAP 開啟新一代資料庫深度實踐、探索之旅。後續,還有美團點評架構儲存團隊針對 TiDB 原始碼研究和改進的系列文章,敬請期待。

作者簡介

應鋼,美團點評研究員,資料庫專家。曾就職於百度、新浪、去哪兒網等,10年資料庫自動化運維開發、資料庫效能優化、大規模資料庫叢集技術保障和架構優化經驗。精通主流的SQL與NoSQL系統,現專注於公司業務在NewSQL領域的創新和落地。

李坤,2018年初加入美團,美團點評資料庫專家,多年基於MySQL、Hbase、Oracle的架構設計和維護、自動化開發經驗,目前主要負責分散式資料庫Blade的推動和落地,以及平臺和周邊元件的建設

昌俊,美團點評資料庫專家,曾就職於BOCO、去哪兒網,6年MySQL DBA從業經歷,積累了豐富的資料庫架構設計和效能優化、自動化開發經驗。目前專注於TiDB在美團點評業務場景的改造和落地。

新一代資料庫TiDB在美團的實踐

相關文章