TiDB / TiSpark 在易果集團實時數倉中的創新實踐

項目背景

目前企業大多數的數據分析場景的解決方案底層都是圍繞 Hadoop 大數據生態展開的,常見的如 HDFS + Hive + Spark + Presto + Kylin,在易果集團,咱們初期也是採起這種思路,可是隨着業務規模的快速增加和需求的不斷變化,一些實時或者準實時的需求變得愈來愈多,這類業務除了有實時的 OLTP 需求,還伴隨着一些有必定複雜度的 OLAP 的需求,單純地使用 Hadoop 已經沒法知足需求。git

現有的準實時系統運行在 SQL Server 之上,經過開發人員編寫和維護相應的存儲過程來實現。因爲數據量不大,SQL Server 可以知足需求,可是隨着業務的發展,數據量隨之增加,SQL Server 愈來愈不能知足需求,當數據量到達必定的階段,性能便會出現拐點。這個時候,這套方案已徹底沒法支撐業務,不得不從新設計新的方案。github

選型評估

在評估初期,Greenplum、Kudu、TiDB 都進入了咱們的視野,對於新的實時系統,咱們有主要考慮點:算法

  • 首先,系統既要知足 OLAP 還要知足 OLTP 的基本需求;sql

  • 其次,新系統要儘可能下降業務的使用要求;數據庫

  • 最後,新系統最好可以與現有的 Hadoop 體系相結合。緩存

Greenplum 是一套基於 PostgreSQL 分析爲主的 MPP 引擎,大多用在併發度不高的離線分析場景,但在 OLTP 方面,咱們的初步測試發現其對比 TiDB 的性能差不少。架構

再說說 Kudu。Kudu 是 CDH 2015年發佈的一套介於 Hbase 和 HDFS 中間的一套存儲系統,目前在國內主要是小米公司應用的較多,在測試中,咱們發現其在 OLTP 表現大體與 TiDB 至關,可是一些中等數據量下,其分析性能相比 TiDB 有必定差距。另外咱們的查詢目前主要以 Presto 爲主,Presto 對接 Kudu 和 PostgreSQL 都是須要考慮兼容性的問題,而 TiDB 兼容 MySQL 協議,在應用初期能夠直接使用 Presto-MySQL 進行統一查詢,下一步再考慮專門開發 Presto-TiDB。併發

另外,咱們但願將來的實時系統和離線系統可以通用,一套代碼在兩個系統中都可以徹底兼容,目前 Tispark 和 SparkSQL 已經很大程度上實現了這點,這支持咱們在之後離線上的小時級任務能夠直接切換到 TiDB上,在 TiDB 上實現實時業務的同時,若是有 T+1 的需求也可以直接指 HDFS 便可,不用二次開發,這是 Kudu 和 GP 暫時實現不了的。app

最後,TiSpark 是創建在 Spark 引擎之上,Spark 在機器學習領域裏有諸如 Mllib 等諸多成熟的項目,對比 GP 和 Kudu,算法工程師們使用 TiSpark 去操做 TiDB 的門檻很是低,同時也會大大提高算法工程師們的效率。運維

通過綜合的考慮,咱們最終決定使用 TiDB 做爲新的實時系統。同時,目前 TiDB 的社區活躍度很是好,這也是咱們考慮的一個很重要的方面。

TiDB 簡介

在這裏介紹一下 TiDB 的相關特性:TiDB 是基於 Google Spanner/F1 論文啓發開源的一套 NewSQL 數據庫,它具有以下 NewSQL 核心特性:

  • SQL支持 (TiDB 是 MySQL 兼容的)

  • 水平線性彈性擴展

  • 分佈式事務

  • 數據強一致性保證

  • 故障自恢復的高可用

同時,TiDB 還有一套豐富的生態工具,例如:快速部署的 TiDB-Ansible、無縫遷移 MySQL 的 Syncer、異構數據遷移工具 Wormhole、以及 TiDB-Binlog、Backup & Recovery 等。

SQL Server 遷移到 TiDB

因爲咱們公司的架構是 .NET + SQL Server 架構,因此咱們沒法像大多數公司同樣去使用 MySQL Binlog 去作數據同步,固然也就沒法使用 TiDB 官方提供的 Syncer 工具了。所以咱們採用了 Flume + Kafka 的架構,咱們本身開發了基於 Flume 的 SQL Server Source 去實時監控 SQL Server 數據變化,進行捕捉並寫入 Kafka 中,同時,咱們使用 Spark Streaming 去讀取 Kafka 中的數據並寫入 TiDB,同時咱們將以前 SQL Server 的存儲過程改形成定時調度的 MySQL 腳本。

圖:SQL Server 數據遷移到 TiDB

TiDB 前期測試

在測試初期,咱們採用 TiDB 的版本爲 RC4,在測試過程當中曾經在同時對一張表進行讀寫時,出現 Region is stale 的錯誤,在 GitHub 上提出 Issue 後,TiDB 官方很快在 Pre-GA 版本中進行了修復。在測試環境,咱們是手動經過二進制包的形式來部署 TiDB ,雖然比較簡單,可是當 TiDB 發佈 GA 版本以後,版本升級倒是一個比較大的問題,因爲早期沒有使用 TiDB-ansible 安裝,官方製做的升級腳本沒法使用,而手動進行滾動升級等操做很是麻煩。因爲當時是測試環境,在聽取了 TiDB 官方的建議以後,咱們從新利用 TiDB 官方提供的 TiDB-ansible 部署了 TiDB 的 GA 版本。只須要下載官方提供的包,修改相應的配置,就能完成安裝和部署。官方也提供了升級腳本,可以在相鄰的 TiDB 版本以前完成無縫滾動升級。同時 TiDB-ansible 默認會提供 Prometheus + Grafana 的監控安裝,官方提供了很是豐富完善的 Grafana 模板,省去了運維不少監控配置的工做量,藉着 TiDB 部署監控的契機,咱們也完成了諸如 Redis,RabbitMQ,Elasticsearch 等不少應用程序的監控由 Zabbix 往 Prometheus 的遷移。這裏須要注意的是,若是是用官方提供的部署工具部署 Prometheus 和 Grafana,在執行官方的中止腳本時切記跳過相應的組件,以避免干擾其餘程序的監控。

TiDB 上線過程

在10月中旬,隨着新機器的採購到位,咱們正式將 TiDB 部署到生產環境進行測試,整個架構爲 3 臺機器,3TiKV+3PD+2TiDB 的架構。在生產環境中的大數據量場景下,遇到了一些新的問題。

首先遇到的問題是 OLTP 方面,Spark Streaming 程序設置的 5 秒一個窗口,當 5 秒以內不能處理完當前批次的數據,就會產生延遲,同時 Streaming 在這個批次結束後會立刻啓動下一個批次,可是隨着時間的積累,延遲的數據就會愈來愈多,最後甚至延遲了 8 小時之久;另外一方面,因爲咱們使用的是機械硬盤,所以寫入的效率十分不穩定,這也是形成寫入延遲的一個很主要的因素。

出現問題以後咱們當即與 TiDB 官方取得聯繫,確認 TiDB 總體架構主要基於 SSD 存儲性能之上進行設計的。咱們將 3 臺機器的硬盤都換成了 SSD;與此同時,咱們的工程師也開發了相應的同步程序來替代 Spark Streaming,隨着硬件的更新以及程序的替換,寫入方面逐漸穩定,程序運行的方式也和 Streaming 程序相似,多程序同時指定一個 Kafka 的 Group ID,同時鏈接不一樣機器的 TiDB 以達到寫入效率最大化,同時也實現了 HA,保證了即便一個進程掛掉也不影響總體數據的寫入。

在 OLTP 優化結束以後,隨之而來的是分析方面的需求。因爲咱們對 TiDB 的定位是實時數據倉庫,這樣就會像 Hadoop 同樣存在不少 ETL 的流程,在 Hadoop 的流程中,以 T+1 爲主的任務佔據了絕大多數,而這些任務廣泛在凌晨啓動執行,所以只能用於對時間延遲比較大的場景,對實時性要求比較高的場景則不適合,而 TiDB 則能很好的知足實時或者準實時的需求,在咱們的業務場景下,不少任務以 5-10 分鐘爲執行週期,所以,必須確保任務的執行時長在間隔週期內完成。

咱們取了兩個在 SQL Server 上跑的比較慢的重要腳本作了遷移,相比於 SQL Server/MySQL 遷移至 Hadoop,從 SQL Server 遷移至 TiDB 的改動很是小,SQL Server 的 Merge 操做在 TiDB 裏也經過 replace into 可以完成,其他一些 SQL Server 的特性,也可以經過 TiDB 的多行事務得以實現,在這一方面,TiDB 的 GA 版本已經作的很是完善,高度兼容 MySQL,所以遷移的成本很是小,從而使咱們可以將大部分精力放在了調優方面。

在腳本遷移完畢以後,一些簡單的腳本可以在秒級完成達到了咱們的預期。可是一些複雜的腳本的表如今初期並沒表現出優點,一些腳本與 SQL Server 持平甚至更慢,其中最大的腳本 SQL 代碼量一共 1000 多行,涉及將近 20 張中間表。在以前的 SQL Server 上,隨着數據量慢慢增大,天天的執行時長逐漸由 1-2 分鐘增加到 5-6 分鐘甚至更久,在雙11當天凌晨,隨着單量的涌入和其餘任務的干擾延遲到 20 分鐘甚至以上。在遷移至 TiDB 初期,在半天的數據量下 TiDB 的執行時長大體爲 15 分鐘左右,與 SQL Server 大體相同,可是並不能知足咱們的預期。咱們參考了 TiDB 的相關文檔對查詢參數作了一些調優,幾個重要參數爲:tidb_distsql_scan_concurrency,tidb_index_serial_scan_concurrency,tidb_index_join_batch_size(TiDB 提供了很好的並行計算能力)。通過驗證,調整參數後,一些 SQL 可以縮短一倍的執行時間,但這裏依舊不能徹底知足咱們的需求。

引入 TiSpark

隨後,咱們把目光轉向了 TiDB 的一個子項目 TiSpark,用官網的介紹來說 TiSpark 就是藉助 Spark 平臺,同時融合 TiKV 分佈式集羣的優點,和 TiDB 一塊兒解決 HTAP 的需求。TiDB-ansible 中也帶有 TiSpark 的配置,因爲咱們已經擁有了 Spark 集羣,因此直接在現有的 Spark 集羣中集成了 TiSpark。雖然該項目開發不久,可是通過測試,收益很是明顯。

TiSpark 的配置很是簡單,只須要把 TiSprak 相關的 jar 包放入 Spark 集羣中的 jars 文件夾中就能引入 TiSpark,同時官方也提供了 3 個腳本,其中兩個是啓動和中止 TiSpark 的 Thrift Server,另外一個是提供的 TiSpark 的 cli 客戶端,這樣咱們就能像使用 Hive 同樣使用 TiSpark 去作查詢。

在初步使用以後,咱們發現一些諸如 select count(*) from table 等 SQL 相比於 TiDB 有很是明顯的提高,一些簡單的 OLAP 的查詢基本上都可以在 5 秒以內返回結果。通過初步測試,大體在 OLAP 的結論以下:一些簡單的查詢 SQL,在數據量百萬級左右,TiDB 的執行效率可能會比 TiSpark 更好,在數據量增多以後 TiSpark 的執行效率會超過 TiDB,固然這也看 TiKV 的配置、表結構等。在 TiSpark 的使用過程當中,咱們發現 TiSpark 的查詢結果在百萬級時,執行時間都很是穩定,而 TiDB 的查詢時間則會隨着數據量的增加而增加(通過與 TiDB 官方溝通,這個狀況主要是由於沒有比較好的索引進行數據篩選)。針對咱們的訂單表作測試,在數據量爲近百萬級時,TiDB 的執行時間爲 2 秒左右,TiSpark 的執行時間爲 7 秒;當數據量增加爲近千萬級時,TiDB 的執行時間大體爲 12 秒(不考慮緩存),TiSpark 依舊爲 7 秒,很是穩定。

所以,咱們決定將一些複雜的 ETL 腳本用 TiSpark 來實現,對上述的複雜腳本進行分析後,咱們發現,大多數腳本中間表不少,在 SQL Server 中是經過 SQL Server 內存表實現,而遷移至 TiDB,每張中間表都要刪除和插入落地,這些開銷大大增長了執行時長(據官方答覆 TiDB 很快也會支持 View、內存表)。在有了 TiSpark 以後,咱們便利用 TiSpark 將中間表緩存爲 Spark 的內存表,只須要將最後的數據落地回 TiDB,再執行 Merge 操做便可,這樣省掉了不少中間數據的落地,大大節省了不少腳本執行的時間。

在查詢速度解決以後,咱們發現腳本中會有不少針對中間表 update 和 delete 的語句。目前 TiSpark 暫時不支持 update 和 delete 的操做(和 TiSpark 做者溝通,後續會考慮支持這兩個操做),咱們便嘗試了兩種方案,一部分執行相似於 Hive,採用 insert into 一張新表的方式來解決;另一部分,咱們引入了 Spark 中的 Snappydata 做爲一部份內存表存儲,在 Snappydata 中進行 update 和 delete,以達到想要的目的。由於都是 Spark 的項目,所以在融合兩個項目的時候仍是比較輕鬆的。

最後,關於實時的調度工具,目前咱們是和離線調度一塊兒進行調度,這也帶來了一些問題,每次腳本都會初始化一些 Spark 參數等,這也至關耗時。在將來,咱們打算採用 Spark Streaming 做爲調度工具,每次執行完成以後記錄時間戳,Spark Streaming 只需監控時間戳變化便可,可以避免屢次初始化的耗時,經過 Spark 監控,咱們也可以清楚的看到任務的延遲和一些狀態,這一部分將在將來進行測試。

TiDB 官方支持

在遷移過程當中,咱們獲得了 TiDB 官方很好的支持,其中也包括 TiSpark 相關的技術負責人,一些 TiSpark 的 Corner Case 及使用問題,咱們都會在羣裏拋出,TiDB 的官方人員會很是及時的幫助咱們解決問題,在官方支持下,咱們遷移至 TiSpark 的過程很順利,沒有受到什麼太大的技術阻礙。

實時數倉 TiDB / TiSpark

在遷移完成以後,其中一條複雜的 SQL,一共 Join 了 12 張表(最大表數量億級,部分表百萬級),在平時小批量的狀況下,執行時間會在 5 分鐘左右,咱們也拿了雙11全量的數據進行了測試,執行時間在 9 分鐘以上,而採用了 TiSpark 的方式去執行,雙11全量的數據也僅僅花了 1 分鐘,性能提高了 9 倍。整個大腳本在 SQL Server 上運行雙11的全量數據之前至少要消耗 30 分鐘,利用 TiDB 去執行大體須要 20 分鐘左右,利用 TiSpark 只須要 8 分鐘左右,相對 SQL Server 性能提高 4 倍,也就是說,每一年數據量最高峯的處理能力達到了分鐘級,很好的知足了咱們的需求。

最後,無論是用 TiDB 仍是用 TiSpark 都會有一部分中間表以及與原表進行 Merge 的操做,這裏因爲 TiDB 對事務進行的限制,咱們也採用以萬條爲單批次進行批量的插入和 Merge,既避免了超過事務的報錯又符合 TiDB 的設計理念,可以達到最佳實踐。

有了 TiSpark 這個項目,TiDB 與 Hadoop 的生態體系獲得進一步的融合,在沒有 TiSpark 以前,咱們的系統設計以下:

圖:多套數倉並存

能夠發現,實時數倉與 T+1 異步數倉是兩個相對獨立的系統,並無任何交集,咱們須要進行數據實時的同步,同時也會在夜晚作一次異步同步,無論是 Datax 仍是 Sqoop 讀取關係型數據庫的效率都遠遠達不到 TiSpark 的速度,而在有了 TiSpark 以後,咱們能夠對 T+1 異步數倉進行整合,因而咱們的架構進化爲以下:

圖:TiDB / TiSpark 實時數倉平臺

這樣就可以利用 TiSpark 將 TiDB 和 Hadoop 很好的串聯起來,互爲補充,TiDB 的功能也由單純的實時數倉變成可以提供以下幾個功能混合數據庫:

  1. 實時數倉,上游 OLTP 的數據經過 TiDB 實時寫入,下游 OLAP 的業務經過 TiDB / TiSpark 實時分析。

  2. T+1 的抽取可以從 TiDB 中利用 TiSpark 進行抽取。

  • TiSpark 速度遠遠超過 Datax 和 Sqoop 讀取關係型數據庫的速度;

  • 抽取工具也不用維護多個系統庫,只須要維護一個 TiDB 便可,大大方便了業務的統一使用,還節省了屢次維護成本。

  • TiDB 自然分佈式的設計也保證了系統的穩定、高可用。

  1. TiDB 分佈式特性能夠很好的平衡熱點數據,能夠用它做爲業務庫熱點數據的一個備份庫,或者直接遷入 TiDB 。

上面這三點也是咱們從此去努力的方向,因而可知,TiSpark 不只對於 ETL 腳本起到了很重要的做用,在咱們從此的架構中也起到了舉足輕重的做用,爲咱們建立一個實時的統一的混合數據庫提供了可能。

與此同時,咱們也獲得 TiDB 官方人員的確認,TiDB 將於近期支持視圖、分區表,並會持續加強 SQL 優化器,同時也會提供一款名爲 TiDB Wormhole 的異構平臺數據實時遷移工具來便捷的支持用戶的多元化遷移需求。咱們也計劃將更多的產品線逐步遷入 TiDB。

總結

同時解決 OLAP 和 OLTP 是一件至關困難的事情,TiDB 和 TiSpark 雖然推出不久,可是已經知足不少應用場景,同時在易用性和技術支持上也很是值得稱讚,相信 TiDB 必定可以在愈來愈多的企業中獲得普遍應用。

做者簡介:羅瑞星,曾就任於前程無憂,參加過 Elasticsearch 官方文檔中文翻譯工做,現就任於易果集團,擔任資深大數據工程師,負責易果集團數據分析架構設計等工做。

相關文章
相關標籤/搜索