天天看點

Qunar 高速發展下資料庫的創新與發展

Qunar 高速發展下資料庫的創新與發展

本篇文章主要介紹 TiDB 在去哪兒的調研和實踐。

1、分布式資料庫誕生背景

随着網際網路的飛速發展,業務量可能在短短的時間内爆發式地增長,對應的資料量可能快速地從幾百 GB 漲到幾百個 TB,傳統的單機資料庫提供的服務,在系統的可擴充性、成本效益方面已經不再适用。随着業界相關分布式資料庫論文的釋出,分布式資料庫應運而生,可以預見分布式資料庫必将成為海量資料處理技術發展的又一個核心。

目前業界最流行的分布式資料庫有兩類,一個是以 Google Spanner 為代表,一個是以 AWS Auraro 為代表。

Spanner 是 shared nothing 的架構,内部維護了自動分片、分布式事務、彈性擴充能力,資料存儲還是需要 sharding,plan 計算也需要涉及多台機器,也就涉及了分布式計算和分布式事務。主要産品代表為 TiDB、CockroachDB、OceanBase 等。

Auraro 主要思想是計算和存儲分離架構,使用共享存儲技術,這樣就提高了容災和總容量的擴充。但是在協定層,隻要是不涉及到存儲的部分,本質還是單機執行個體的 MySQL,不涉及分布式存儲和分布式計算,這樣就和 MySQL 相容性非常高。主要産品代表為 PolarDB。

2、去哪兒資料存儲方案現狀

在去哪兒的 DBA 團隊,主要有三種資料存儲方案,分别是 MySQL、Redis 和 HBase。

MySQL 是去哪兒的最主要的資料存儲方案,絕大部分核心的資料都存儲在 MySQL 中。MySQL 的優點不用多說,缺點是沒法做到水準擴充。MySQL 要想能做到水準擴充,唯一的方法就業務層的分庫分表或者使用中間件等方案。是以幾年前就出現了各大公司重複造輪子,不斷湧現出中間層分庫分表解決方案,比如百度的 DDBS,淘寶的 TDDL,360 的 Atlas 等。但是,這些中間層方案也有很大局限性,執行計劃不是最優,分布式事務,跨節點 join,擴容複雜(這個心酸 DBA 應該相當清楚)等。 Redis 主要作為緩存使用,針對讀通路延時要求高的業務,使用場景有限。

HBase 因其分布式的特點,可以通過 RS 的增加線性提升系統的吞吐,HDFS 具有水準擴充容量的能力,主要用來進行大資料量的存儲,如日志、曆史資料、訂單快照等。HBase 底層存儲是 LSM-Tree 的資料結構,與 B+ Tree 比,LSM-Tree 犧牲了部分讀性能,用來大幅提升寫性能。 但在實際運維的過程中,HBase 也暴露了一些缺點:

(1) HBase 能提供很好地寫入性能,但讀性能就差很多,一是跟本身 LSM-Tree 資料結構有關。二是 HBase 因為要存儲大容量,我們采用的是 SAS 盤,用 SSD 成本代價太大。三是跟 HBase 自身架構有關,多次 RPC、JVM GC 和 HDFS 穩定性因素都會影響讀取性能。

(2) HBase 屬于 NoSQL,不支援 SQL,對于使用慣了關系 SQL 的人來說很不友善,另外在運維定位問題的時候也增加了不少難度。比如在運維 MySQL 過程中,可以很快通過慢查詢日志就識别出哪些 SQL 執行效率低,快速定位問題 SQL。而在 HBase 運維中,就很難直接識别出用戶端怎樣的操作很慢,為此我們還在源碼中增加了慢查詢 Patch,但終歸沒有直接識别 SQL 來的友善。

(3) HBase 的軟體棧是 Java,JVM 的 GC 是個很頭疼的問題,在運維過程中多次出現 RegionServer 因為 GC 挂掉的情況,另外很難通過優化來消除通路延時毛刺,給運維造成了很大的困擾。此外,HBase 在程式設計語言支援通路對 Java 友好,但是其他語言的通路需要通過 Thrift,有些限制。

(4) 架構設計上,HBase 本身不存儲資料,HBase 通過 RPC 跟底層的 HDFS 進行互動,增加了一次 RPC,多層的架構也多了維護成本。另外 ZooKeeper 的高可用也至關重要,它的不可用也就直接造成了所有 HBase 的不可用。

(5) HBase 不支援跨行事務。HBase 是 BigTable 的開源實作,BigTable 出現之後,Google 的内部就不停有團隊基于 BigTable 做分布式事務,是以誕生了一個産品叫 MegaStore,雖然延時很大,但禁不住好用,是以用的人也很多,BigTable 的作者也後悔當初沒有在 BigTable 中加入跨行事務。沒有了跨行事務,也就沒法實作二級索引,使用者隻能根據設計 rowkey 索引來進行查詢,去哪兒不少業務開發問過我 HBase 是否支援二級索引,結果也不得不因為這個限制放棄了使用 HBase。業界很多公司也在 HBase 上實作二級索引,比如小米、華為等,比較出名的是 Phoenix。我們當初也調研了 Phoenix 來支援二級索引,但在 HBase 本身層次已經很多,Phoenix 無疑又多了一層,在運維的過程中也感覺坑很多 , 此外何時用 Phoenix 何時用 HBase API 的問題也給我們造成很多困擾,最終放棄了這個方案。

綜上所述,為了解決現有資料存儲方案所遇到的問題,去哪兒 DBA 團隊從 2017 年上半年開始調研分布式資料庫,在分布式資料庫的産品選擇上,綜合各個方面因素考慮,最終選擇了 TiDB,具體原因不在這裡細說了,下面開始具體聊聊 TiDB。

3、TiDB 架構設計

如上圖,TiDB 架構主要分為三個元件:

(1) TiDB Server

負責接收 SQL 請求,處理 SQL 相關邏輯,通過 PD 找到所需資料的 TiKV 位址。TiDB Server 是無狀态的,本身不存儲資料,隻負責計算,可以無限水準擴充。TiDB 節點可以通過負載均衡元件 (如 LVS、HAProxy 或者 F5)對外提供統一入口,我個人覺得如果要能實作像 Elasticsearch 那樣自己的用戶端就更好。

(2) PD Server

Placement Driver (簡稱 PD) 是整個叢集的管理子產品,其主要工作有三個:

  • 一是存儲叢集元資訊(某個 Key 存儲在哪個 TiKV 節點);
  • 二是對 TiKV 叢集進行排程和負載均衡(資料遷移、Raft group leader 遷移等;
  • 三是配置設定全局唯一且遞增的事務 ID。

(3) TiKV Server

TiKV 負責存儲資料,存儲資料基本機關是 Region,每個 TiKV 節點負責管理多個 Region。TiKV 使用 Raft 協定做複制,保證資料一緻性和容災。資料在多個 TiKV 之間的負載均衡由 PD 排程,以 Region 為機關排程。

TiDB 最核心的特性是水準擴充和高可用。

(1) 水準擴充

TiDB Server 負責處理 SQL 請求,可以通過添加 TiDB Server 節點來擴充計算能力,以提供更高的吞吐。TiKV 負責存儲資料,随着資料量的增長,可以部署更多的 TiKV Server 節點來解決資料 Scale 的問題。

(2) 高可用

因 TiDB 是無狀态的,可以部署多個 TiDB 節點,前端通過負載均衡元件對外提供服務,這樣可以保證單點失效不影響服務。而 PD 和 TiKV 都是通過 Raft 協定來保證資料的一緻性和可用性。

4、TiDB 原理與實作

TiDB 架構是 SQL 層和 KV 存儲層分離,相當于 innodb 插件存儲引擎與 MySQL 的關系。從下圖可以看出整個系統是高度分層的,最底層選用了目前比較流行的存儲引擎 RocksDB,RockDB 性能很好但是是單機的,為了保證高可用是以寫多份(一般為 3 份),上層使用 Raft 協定來保證單機失效後資料不丢失不出錯。保證有了比較安全的 KV 存儲的基礎上再去建構多版本,再去建構分布式事務,這樣就構成了存儲層 TiKV。有了 TiKV,TiDB 層隻需要實作 SQL 層,再加上 MySQL 協定的支援,應用程式就能像通路 MySQL 那樣去通路 TiDB 了。

這裡還有個非常重要的概念叫做 Region。MySQL 分庫分表是将大的資料分成一張一張小表然後分散在多個叢集的多台機器上,以實作水準擴充。同理,分布式資料庫為了實作水準擴充,就需要對大的資料集進行分片,一個分片也就成為了一個 Region。資料分片有兩個典型的方案:一是按照 Key 來做 Hash,同樣 Hash 值的 Key 在同一個 Region 上,二是 Range,某一段連續的 Key 在同一個 Region 上,兩種分片各有優劣,TiKV 選擇了 Range partition。TiKV 以 Region 作為最小排程機關,分散在各個節點上,實作負載均衡。另外 TiKV 以 Region 為機關做資料複制,也就是一個 Region 保留多個副本,副本之間通過 Raft 來保持資料的一緻。每個 Region 的所有副本組成一個 Raft Group, 整個系統可以看到很多這樣的 Raft groups。

最後簡單說一下排程。 TiKV 節點會定期向 PD 彙報節點的整體資訊,每個 Region Raft Group 的 Leader 也會定期向 PD 彙報資訊,PD 不斷的通過這些心跳包收集資訊,獲得整個叢集的詳細資料,進而進行排程,實作負載均衡。

5、硬體選型和部署方案

在硬體的選型上,我們主要根據三個元件對硬體不同要求來考慮,具體選型如下:

因 TiDB 和 PD 對磁盤 IO 要求不高,是以隻需要普通磁盤即可。TiKV 對磁盤 IO 要求較高。TiKV 硬碟大小建議不超過 500G,以防止硬碟損害時,資料恢複耗時過長。綜合記憶體和硬碟考慮,我們采用了 4 塊 600G 的 SAS 盤,每個 TiKV 機器起 4 個 TiKV 執行個體,給節點配置 labels 并且通過在 PD 上配置 location-labels 來指明哪些 label 是位置辨別,保證同一個機器上的 4 個 TiKV 具有相同的位置辨別,同一台機器是多個執行個體也隻會保留一個 Replica。有條件的最好使用 SSD,這樣可以提供更好的性能。強烈推薦萬兆網卡。

TiDB 節點和 PD 節點部署在同台伺服器上,共 3 台,而 TiKV 節點獨立部署在伺服器上,最少 3 台,保持 3 副本,根據容量大小進行擴充。

部署工具使用了 TiDB-Ansible,TiDB-Ansible 是 PingCAP 基于 Ansible playbook 功能編寫了一個叢集部署工具叫 TiDB-Ansible。使用該工具可以快速部署一個完整的 TiDB 叢集(包括 PD、TiDB、TiKV 和叢集監控子產品),一鍵完成以下各項運維工作:

  • 初始化作業系統,包括建立部署使用者、設定 hostname 等
  • 部署元件
  • 滾動更新,滾動更新時支援子產品存活檢測
  • 資料清理
  • 環境清理
  • 配置監控子產品

6、監控方案

PingCAP 團隊給 TiDB 提供了一整套監控的方案,他們使用開源時序資料庫 Prometheus 作為監控和性能名額資訊存儲方案,使用 Grafana 作為可視化元件進行展示。具體如下圖,在 client 端程式中定制需要的 Metric 。Push GateWay 來接收 Client Push 上來的資料,統一供 Prometheus 主伺服器抓取。AlertManager 用來實作報警機制,使用 Grafana 來進行展示。

下圖是某個叢集的 Grafana 展示圖

7、TiDB 使用情況

對于 TiDB 的使用,我們采用大膽實踐、逐漸推廣的思路,一個産品是否經得起考驗,需要先用起來,在運維的過程中才能發現問題并不斷回報完善。是以,去哪兒 DBA 經過了充分調研後,8 月下旬開始,我們就先在非核心業務使用,一方面不會因為 TiDB 的問題對現有業務影響過大,另一方面 DBA 自身也積累運維經驗,随着産品自身的完善,叢集使用量和運維經驗的積累,後續我們再逐漸推廣到更重要的叢集中,解決業務上遇到的資料存儲的痛點。目前已經上線了兩個 TiDB 叢集。

(1) 機票離線叢集,主要是為了替換離線 MySQL 庫,用于資料統計。目前系統容量是 1.6T,每天以 10G 的增量進行增長,用 MySQL 存儲壓力較大,且沒法擴充,另外一些 OLAP 查詢也會影響線上的業務。

(2) 金融支付叢集,主要是想滿足兩方面需求,一是目前存儲在 MySQL 中的支付資訊表和訂單資訊表都是按月進行分表,營運或者開發人員想對整表進行查詢分析,現有的方案是查多個表查出來然後程式進行進一步統計 。二是有些查詢并不需要線上上進行查詢,隻需要是作為線下統計使用,這樣就沒有必要對線上表建立索引,隻需要離線庫建立索引即可,這樣可以避免降低寫性能。

目前的架構是用 syncer 從線上 MySQL 庫做分庫分表資料同步到 TiDB 中,然後開發可以在 TiDB 上進行 merge 單表查詢、連表 join 或者 OLAP。