TiFlash 是 TiDB HTAP 形態的關鍵元件,它是 TiKV 的列存擴充套件,在提供了良好的隔離性的同時,也兼顧了強一致性。列存副本通過 Raft Learner 協議非同步複製,但是在讀取的時候通過 Raft 校對索引配合 MVCC 的方式獲得 Snapshot Isolation 的一致性隔離級別。這個架構很好地解決了 HTAP 場景的隔離性以及列存同步的問題。
使用 TiFlash 前,需要給表新增 TiFlash 副本。不少使用者反饋新增 TiFlash 副本的時候出現問題。TiFlash 副本始終處於不可用狀態官方文件總結了一些簡單的問題排查。
這篇文章將介紹目前版本(目前所有 release 的 4.x, 5.x 版本)下給 TiDB 中的表新增 TiFlash 副本的工作原理,主要供 DBA 同學們排查相關的問題時,可以從中參考先從哪些方面收集資訊及嘗試解決。
基本概念
在 PD 的視角里,TiFlash 例項與 TiKV 例項類似,都是一個 store,只是 TiFlash 的 store 會帶有 “key=engine, value=TiFlash” 的一個 label。新增 TiFlash 副本後,PD 把 region 排程到 TiFlash,並讓其中的 region 一直只以 learner 的形式存在,依賴的是 Placement Rules 功能。
TiFlash 例項中包含有一個修改版本的 TiKV 程式碼,主要負責與 TiKV 協同處理 Raft 層的操作,其輸出日誌與 TiKV 基本一致。TiUP 部署時,其日誌會輸出到 tiflash_tikv.log。
TiFlash 例項會定期啟動一個子程式來處理與 TiFlash 副本新增、刪除相關的操作。如果在程式列表中偶爾看到一個名為 tiflash_cluster_manager 的不常駐程式(在官網中稱為 “pd buddy”),屬於正常情況。其日誌會輸出到 tiflash_cluster_manager.log。
TiFlash 內部元件架構圖
新增 TiFlash 副本各階段叢集中元件的工作
新增 TiFlash 副本的時序圖
執行副本數修改 DDL
在 TiDB 中執行 alter tableset tiflash replica
時,這條語句作為 DDL 語句執行。
從 progress 0.0 到 1.0 的同步過程中
TiDB 提供 http 介面,其他元件可以通過此介面查詢哪些表存在 TiFlash 副本:curl http://:/tiflash/replica
。
TiFlash 有定期任務,負責:
- 從 TiDB 的 tiflash/replica 介面拉取哪些表/分割槽有 TiFlash 副本。對於未 available 的表,如果表在 PD 上沒有相應的 Placement Rules,該任務會負責設立相應的 rule,key range 為 [ t__r, t__ )。
- 對於未 available 的表,該任務會從 PD 拉取 key range 對應的 region_id,以及線上的所有 TiFlash store 中有多少已經同步的 region_id。
- 以 TiFlash store 中去重後的 region_id 個數 PD 中 region_id 個數,通過給 tiflash/replica 介面發 POST 請求的方式更新同步進度 progress。
- 如果 PD 中存在 placement-rules 但 tiflash/replica 中不存在相應的 table_id,說明該表/分割槽已經被 DROP 而且已經過了 GC 時間,會到 PD 中移除相應的 rule。
該元件的日誌輸出為 tiflash_cluster_manager.log。如果叢集中存在多個 TiFlash,會通過 PD 內建的 etcd 選出一個來負責上述任務。通過日誌排查時需要拿到該時間段內負責該工作的節點,或者拿全部 TiFlash 節點的相關日誌。
PD 的行為:接收到 placement-rules 後,PD 會:
- 先對 Region 進行切分,確保 Region 的邊界不會跨越 表資料 及 索引(因為 TiFlash 只同步表資料部分)
- 對 Region 的 Leader 下發 AddLearner 到 TiFlash store 的排程
TiKV 的行為:
- TiKV 中 Region 的 Leader 接受並執行 PD 的 AddLearner 命令
- Region Leader 以 Snapshot 形式把 Region 資料傳送到 TiFlash 的 Region peer
對於已經有 TiFlash 副本的分割槽表進行 Add partition 的過程
TiDB 對已經有 TiFlash 副本的分割槽表進行 Add partition 時,會在生成 partition 後(但對使用者不可見)block 並等待。直到 TiFlash 上報該 partition 對應的 partition_id 已經 available 後,DDL 才執行完成。(詳細內容可參考 TiDB 相關 PR)
對於 TiFlash 而言,給分割槽表新增一個 partition 與新增一個普通表是類似的操作,可以參考上文的流程。不同的是在此情況下,會額外在 PD 新增 accelerate-schedule 的操作,提升分割槽表 key range 相關 Region 的排程優先順序,以期望在叢集繁忙的情況下,縮短分割槽表的 available 速度,減少 DDL block 的時間。
為什麼需要 block 分割槽表的 Add partition 操作:
- 假如不 block Add partition 的 DDL 操作,在使用者執行查詢語句時(比如 count(*) ),如果查詢選擇了從 TiFlash 讀,但是新 partition 上的 region 還沒有建立起 TiFlash 副本,此時會導致使用者的查詢因為少數的 region 而失敗。表現出來為使用者在執行 Add partition 時,查詢該表不穩定,容易失敗。
- 為了避免造成查詢的不穩定,block 分割槽表的 Add partition 操作,待新建分割槽的 Region 建立完 TiFlash 副本 ready 後才允許讀到該分割槽。
不同階段出現問題時排查的方向(舉例)
執行 alter tableset tiflash replica
時卡住
通常來說,這句 DDL 操作僅修改 TiDB 中的元資訊,執行時不會阻塞太久。如果出現執行此語句卡住的問題,可以看是否有其他 DDL 操作 block 了該語句的執行(比如在同一個表上是否存在 add index 操作)。更多地可以參考其他 TiDB 中 DDL 卡住的經驗 [FAQ] DDL 卡住排查經驗 - TiDB 常見 FAQ。
副本數修改成功,但是 progress 一直為零,或者 progress 有進展,但是很 “慢”
- 先根據 TiFlash 副本始終處於不可用狀態確認下基本的問題
- 上述排查無誤的情況下,先檢查 tiflash_cluster_manager.log 的日誌。看是否與 TiDB 或 PD 連線出現異常,如果有異常,先確認是相關元件的 API 查詢超時(curl http://:10080/tiflash/replica,見TiDB 與 TiFlash 同步介面)還是網路連通性有問題。
- 再確認出現問題的表是否有建立 placement-rule (tiflash_cluster_manager.log 日誌中關鍵字 “Set placement rule … table--r”),上報給 TiDB 的進度資訊(id, region_count, flash_region_count)。確認 PD 上是否能夠查詢到相應表的 rule (參考Placement Rules 使用文件 )。
- 確認同步進度 “慢” 的具體表現。出問題的表,其 flash_region_count 是否很長時間”沒有變化”,還是隻是 “變化得慢” (比如幾分鐘還是會漲幾個 region)。
- 如果是 “沒有變化”,需要排查整個工作鏈路上什麼環節出現問題。
TiFlash 給 PD 設 rule -> PD 給 TiKV 中的 Region leader 下發 AddLearner 排程 -> TiKV 給 TiFlash 同步 Region 資料 這個鏈路是否有問題,收集相關元件的日誌進行排查。
可以檢查 tikv、tiflash-proxy 日誌中的 warn/error 資訊,確認是否存在網路隔離之類的錯誤。
- 如果是 “變化得慢”,可以排查 TiFlash 當前的負載、PD 的排程。
主要觀察 Grafana 中的 TiFlash-Summary 看板,Raft 中 “Applying snapshots Count”、“Snapshot Predecode Duration”、“Snapshot Flush Duration” 幾個圖,反映 TiFlash 通過 ApplySnapshot 接收資料的併發度、apply 耗費的時長;以及 Storage Write Stall 中的 “Write Stall Duration” 是否寫入太頻繁,導致出現了 Write Stall 現象;收集其他如CPU、磁碟IO負載等,以及 TiFlash 的日誌。
PD 相關的排程引數調整見:PD 排程引數。
對已經有 TiFlash 副本的分割槽表進行 Add partition 過程中卡住
根據 PR 中的 comment,如果是因為 TiFlash 沒有建立起副本而 block 住,會列印 “[ddl] partition replica check failed” 的日誌。接下來的排查方向,大概是當時的是否有較多 Region 在建立 TiFlash 副本、TiFlash apply snapshot 的壓力、PD 排程優先順序是否有生效等。
附錄:
一些過程中輔助排查的 API:
TiDB 中查詢 TiFlash 副本、進度等
select * from information_schema.tiflash_replica
檢視最近 執行 pending 的 DDL 任務
admin show ddl jobs
TiDB 中獲取 TiFlash 副本訊息的 API 介面(與 TiFlash 互動的主要介面)
curl http://:/tiflash/replica
TiDB 中查詢表的 Region 資訊
SHOW TABLEREGIONS;
查詢單個 TiFlash 節點上 table_id 對應的 Region 資訊
echo "DBGInvoke dump_all_region(,true)" | curl "http://:/?query=" --data-binary @-
PD 中查詢 Region 的資訊
tiup ctl pd -u http://:region
PD 中查詢 Placement-rules 資訊
tiup ctl pd -u http://:config placement-rules show