目前企業大多數的數據分析場景的解決方案底層都是圍繞 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 是基於 Google Spanner/F1 論文啓發開源的一套 NewSQL 數據庫,它具有以下 NewSQL 核心特性:
SQL支持 (TiDB 是 MySQL 兼容的)
水平線性彈性擴展
分佈式事務
數據強一致性保證
故障自恢復的高可用
同時,TiDB 還有一套豐富的生態工具,例如:快速部署的 TiDB-Ansible、無縫遷移 MySQL 的 Syncer、異構數據遷移工具 Wormhole、以及 TiDB-Binlog、Backup & Recovery 等。
因爲咱們公司的架構是 .NET + SQL Server 架構,因此咱們沒法像大多數公司同樣去使用 MySQL Binlog 去作數據同步,固然也就沒法使用 TiDB 官方提供的 Syncer 工具了。所以咱們採用了 Flume + Kafka 的架構,咱們本身開發了基於 Flume 的 SQL Server Source 去實時監控 SQL Server 數據變化,進行捕捉並寫入 Kafka 中,同時,咱們使用 Spark Streaming 去讀取 Kafka 中的數據並寫入 TiDB,同時咱們將以前 SQL Server 的存儲過程改形成定時調度的 MySQL 腳本。
在測試初期,咱們採用 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,在執行官方的中止腳本時切記跳過相應的組件,以避免干擾其餘程序的監控。
在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 可以縮短一倍的執行時間,但這裏依舊不能徹底知足咱們的需求。
隨後,咱們把目光轉向了 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 官方很好的支持,其中也包括 TiSpark 相關的技術負責人,一些 TiSpark 的 Corner Case 及使用問題,咱們都會在羣裏拋出,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 異步數倉進行整合,因而咱們的架構進化爲以下:
這樣就可以利用 TiSpark 將 TiDB 和 Hadoop 很好的串聯起來,互爲補充,TiDB 的功能也由單純的實時數倉變成可以提供以下幾個功能混合數據庫:
實時數倉,上游 OLTP 的數據經過 TiDB 實時寫入,下游 OLAP 的業務經過 TiDB / TiSpark 實時分析。
T+1 的抽取可以從 TiDB 中利用 TiSpark 進行抽取。
TiSpark 速度遠遠超過 Datax 和 Sqoop 讀取關係型數據庫的速度;
抽取工具也不用維護多個系統庫,只須要維護一個 TiDB 便可,大大方便了業務的統一使用,還節省了屢次維護成本。
TiDB 自然分佈式的設計也保證了系統的穩定、高可用。
上面這三點也是咱們從此去努力的方向,因而可知,TiSpark 不只對於 ETL 腳本起到了很重要的做用,在咱們從此的架構中也起到了舉足輕重的做用,爲咱們建立一個實時的統一的混合數據庫提供了可能。
與此同時,咱們也獲得 TiDB 官方人員的確認,TiDB 將於近期支持視圖、分區表,並會持續加強 SQL 優化器,同時也會提供一款名爲 TiDB Wormhole 的異構平臺數據實時遷移工具來便捷的支持用戶的多元化遷移需求。咱們也計劃將更多的產品線逐步遷入 TiDB。
同時解決 OLAP 和 OLTP 是一件至關困難的事情,TiDB 和 TiSpark 雖然推出不久,可是已經知足不少應用場景,同時在易用性和技術支持上也很是值得稱讚,相信 TiDB 必定可以在愈來愈多的企業中獲得普遍應用。
做者簡介:羅瑞星,曾就任於前程無憂,參加過 Elasticsearch 官方文檔中文翻譯工做,現就任於易果集團,擔任資深大數據工程師,負責易果集團數據分析架構設計等工做。