做者:何志勇 本文轉載自公衆號「平安科技數據庫產品團隊」。mysql
2019 年 5 月 9 日,平安科技數據庫產品資深工程師何志勇在第十屆數據庫技術大會 DTCC 上分享了《TiDB 在平安核心系統的引入及應用》,經過對 TiDB 進行 POC 測試,詳細解析如何選擇適用於金融行業級別的開源分佈式數據庫,以及平安「財神節」活動中引入 TiDB 的全流程應用實踐案例分享。本文根據演講內容整理。redis
<center>何志勇 平安科技數據庫產品團隊 資深工程師</center>spring
做爲一名運維人員,引入一個新的數據庫產品前必需要明確幾點:sql
從業務的角度,引入的產品可否知足業務基本需求和使用場景。數據庫
從運維管理角度看,這產品必須是可運維、可管理的,而且咱們須要對其相應的功能與特性,要有一個很好的瞭解。編程
產品性能穩定。服務器
因此在咱們引入前從如下六個方面分別對 TiDB 進行測試驗證,其中功能與架構、配置與管理、備份與恢復都是針對咱們運維管理,SQL 特性、基準測試、應用場景測試則是應對業務需求和業務場景的。多線程
TiDB 事務隔級別爲 SI,支持 Spark 生態,支持動態擴容,跨數據中心部署。架構
這是 TiDB 官網最新的架構圖:併發
從左至右看,能夠經過 MySQL 或 MySQL 客戶端接入 TiDB,TiDB 有 TiDB、PD、TiKV 三個組件,組件之間功能相互獨立,需獨立部署,分別負責計算、調度、存儲功能;同時又相互協做,共同完成用戶請求處理。在 TiKV 層各節點是使用 Raft 協議保證節點間數據的一致性,同時它還提供 Spark 接口供大數據分析。
從上往下看,可經過 Data Miaration 工具從 MySQL 遷移到 TiDB,同時提供備份恢復功能、內部性能監控監測及診斷、支持容器化部署。
TiDB 從架構及生態上基本上具有了傳統數據庫應有的功能。
兼容 mysql 語法,2.0 版本不支持窗口函數、分區表、視圖、trigger 等。
支持在線 DDL,2.0 只支持串行的 DDL、不支持併發,在優化器上支持 RBO 與 CBO,能對單會話進行管理,能夠支持複雜的 SQL。
備份恢復工具均爲開源,支持多線程備份恢復,當前版本不支持物理備份,loader 恢復時間偏長。
TiDB 在單條 SQL 的性能較好,高併發場景下性能較穩定,但 DML 事務大小有限制。
支持標量子查詢,能支持很是複雜的查詢,查詢引擎可朔性強。
這個應用場景是咱們的產險的實際分析場景,表數據量不大可是 SQL 較爲複雜,是典型的星型查詢。在 Oracle 用了 134 秒,可是 TiDB 用了 50 分鐘,咱們以爲很詫異,與 TiDB 的同事諮詢後,他們經過現場支持咱們優化底層代碼後 34 秒能夠跑出來。
「財神節」是中國平安綜合性年度線上金融狂歡節。2019 年平安集團「財神節」活動於 1 月 8 日正式啓動,涉及壽險、產險、銀行、養老險、健康險、普惠、證券、基金、健康互聯、陸金所、壹錢包、互娛、不動產等多個領域,活動參與的 BU 數量與推廣的力度是歷年之最。單日成交額超過 1000 億,在單日交易額破千億背後是幾百個後臺數據庫實例的運維保障。
咱們看下活動業務場景的特色:
參與門檻低:暖寶保這個業務保費價格低至 19.9,因此人人均可以參與。
咱們的推廣力度很大:以微服務的方式對接如平安健康、好福利、平安銀行、陸金所等全部 APP 端,同時配合各類合做夥伴的宣傳。
典型的互聯網活動形式:如秒殺、紅包雨,因此對數據庫的要求是高併發、低延遲、高響應、高可用,2-5 年在線數據存儲量預計達到 20~50TB,而這些只是預估,有可能遠遠大於以上評估值。
平安在用的開源數據庫有不少,那在這麼多數據庫中,咱們選擇什麼數據庫呢?
綜合對比考量最終咱們選擇 TiDB,在選擇的同時也面臨着挑戰:
時間緊迫
2018 年 12 月 17 日~2019 年 1 月 7 日,20 天時間內完成開發測試到生產上線,時間短,風險大
開發零使用經驗
現有開發大都是基於傳統 Oracle 保險業務,對於 TiDB 沒有使用經驗
併發量與擴容
互聯網業務併發需求前期不可徹底需求,前期不能很好的以實際壓力進行測試,與資源準備
DB 運維管理
TiDB 還處於生產落地階段,一類系統還沒有使用過 TiDB,沒有大規模應用運維經驗
基於以上挑戰,咱們在 9 臺 PC 服務器上作了驗證測試,測試工具是 jmeter,TiKV 節點數咱們是逐步增長的,具體的測試過程以下:
總結一下,就是:
TiDB 吞吐:在 select 中即 point select,TiDB 的吞吐比較好。
彈性擴容:在 insert 場景下隨着節點數的增長,TPS 也會相應的增長,每增長 3 個節點 TPS 可提高 12%~20% 左右,同時在相同 TiKV 節點數下,TPS 與響應時間,此消彼長。
批量提交性能尤佳:業務中一個保單須要同時寫 7 個表,7 個表同時 commit 比單表 commit TPS 高,相同 TPS 場景下延遲更小。
初始化 region 分裂耗時長:因在測試時沒有預熱數據(表爲空表),對空表寫入前幾分鐘,響應時間會比較大,約 5~8 分鐘後響應時間趨於穩定。在前幾分鐘內響應時間大,是由於每一個表初始化完都是一個 region,大量 insert 進來後須要進行分裂,消耗時間比較大。
Raftstore cpu 高問題:因爲 Raftstore 仍是單線程,測試中從監控指標看到 CPU 達到瓶頸是raftrestore 線程。
TiKV 性能中的「木桶原理」:TiKV 中一個節點的寫入性能變慢會影響到整個集羣的 TPS 與響應時間。
上線時咱們作了如下兩方面改善:
1. 優化表的定義與索引
表定義:不使用自增加列(自增加的 rowid)做爲主鍵,避免大量 INSERT 時把數據集中寫入單個 Region,形成寫入熱點。
索引:使用有實際含義的列做爲主鍵,同時減小表沒必要要的索引,以加快寫入的速度。
2. 對錶的 region 進行強制分裂
查找表對應的 region:curl http://$tidb_ip:$status_port /tables/$schema/$table_name/regions
使用 pd-ctl 工具 split 對應表的 region:operator add split-region $region_id
打散表的隱式 id,打散表的數據分佈:alter table $table_name shard_row_id_bits=6;
咱們使用了 25 臺機器,後面還臨時準備了 10 臺機器去應對高併發的不時之需。
在使用過程當中遇到以下問題:
(1) 2.0.10 版本下 in 不能下推到表過渡問題
你們看到咱們兩個相同的表結構,同時寫入一些數據,在兩個表進行關聯的時候,發現過濾條件 t1.id=1 時,上面那個執行計劃能夠下推到兩個表進行過濾,兩個表能夠徹底精準的把數據取出來,可是下面把等號後改爲 in 的時候,對 t2 表進行全表掃描,若是 t2 表數據量很大時就會很慢,這是 TiDB 的一個 bug,解決方案就是不要用 in,在 2.1 版本修復了這個 bug。
(2) 2.0.10 下時區設置致使客戶端不能連
咱們在跑命令的時候沒有問題,而且結果是能夠的,可是跑完後就斷掉了,從後臺看也是有問題的,重啓 TiDB 組件也不行,後來找到代碼咱們發現這是一個 bug。
緣由:這個 bug 會在你鏈接時 check 這個時區,致使用戶不能鏈接。
解決辦法:咱們找研發同事從新編譯一個 tidb-server 登入服務器,把時區設置爲正確的,而後使用最初的 TiDB 組件登陸,2.1 版本後這個 bug 修復。
(3) Spring 框架下 TiDB 事務
這個問題是比較重要的問題,有個產品須要生成一個惟一的保單號,業務是批量生成的,當時在 TiDB 中咱們建了一個表,表中只有一條數據,可是咱們發現會有重複保單號出來。
緣由:TiDB 使用樂觀事務模型,在高併發執行 Update 語句對同一條記錄更新時,不一樣事務拿的版本值多是相同的,因爲不一樣事務只有在提交時,纔會檢查衝突,而不是像 Oracle、MySQL、PG 那樣,使用鎖機制來實現對一記錄的串行化更改。
解決辦法:Spring 開發框架下,對事務的管理是使用註解式的,沒法捕獲到 TiDB commit 時的返回狀態。所以須要將 spring 註解式事務改爲編程式事務,並對 commit 狀態進行捕獲,根據狀態來決定是重試機制,具體步驟:
利用 redis 實現分佈式鎖,執行 SQL。
捕獲事務 commit 狀態,並判斷更新成功仍是失敗:
失敗:影響行數爲 0 || 影響行數爲 1 && commit 時出現異常。
成功:影響行數爲 1 && commit 時無異常。