本文作者是矛盾螺旋隊的成員劉瑋,他們的專案
**TiEye
**在 TiDB Hackathon 2018 中獲得了三等獎。TiEye 是
Region 資訊變遷歷史視覺化工具,通過 PD記錄 Region 的Split、Merge、ConfChange、LeaderChange 等資訊,可以方便的回溯 Region 某個時間的具體狀態,為開發人員提供了方便的視覺化展示介面及查詢功能。
TiKV 的 Region
Region 是 TiKV 的一個資料排程單元,TiKV 將資料按照鍵值範圍劃分為很多個 Region,分在叢集的多臺機器上,通過排程 Region 來實現負載均衡以及資料儲存的擴充套件,同時一個 Region 也是一個 Raft Group,一個 Region 分佈在多個 TiKV 例項上(通常是 3 個或者 5 個),通過 Raft 演算法保證多副本的強一致性。
動機
這個專案的靈感是之前在查一些問題的時候想到的,因為我們很多時候需要去知道 Region 在某個時間的狀態,這就需要通過日誌從雜亂的資訊中提取出來有用的資訊來複原當時的場景,但實際並不是特別方便高效,尤其是在看多個 Region 之間的關係的時候。因此通過將 Region 資訊變化歷史視覺化,希望能為開發者們在定位問題的時候提供一個方便直觀的工具,同時還能通過它來分析 PD 的排程策略,以及排程帶來的寫放大問題等等。
實際方案
一開始我們考慮的是通過一個獨立的服務去解析 PD 的日誌來獲取 Region 資訊的變化歷史,後來討論後認為這樣做不僅依賴於 PD 中的日誌格式,造成系統耦合,同時 PD 的 leader 變遷導致日誌內容不連續,以及日誌中的資訊並不是特別充分等問題也增加了開發難度。因此我們最後決定直接修改 PD 的原始碼,在每次 PD 變更 Region 的時候,記錄下這些資訊並持久化。這樣既能保證在 PD 切換 leader 後的變化資訊的連續性,又提供了更加豐富的歷史資訊。同時,PD 新增相關的 API,以供前端進行查詢。
Hackathon 回顧
我們的團隊由三個人組成,分別是我(劉瑋)、周振靖和張博康,都畢業於北京郵電大學。我們在這次 Hackathon 之前就認識,因為大家都在北京,因此交流還是蠻方便的,在開賽大約一週前就確定了這個題目。其實我最初的想法是做一些有關於效能優化的事情,但是在跟隊友們交流後還是決定做 Region 歷史視覺化,其更具有實用性,也更適合在 Hackathon 上來做。
-
10:00 比賽正式開始。我們之前已經討論好了專案的大體架構,因此沒有再做過多的討論就各自開始碼程式碼了。博康負責後端框架以及 PD 相應的修改,我負責後端查詢 API,振靖負責前端視覺化。
-
12:15 午餐。休息片刻,繼續碼程式碼。
-
14:00 後端框架大體完成,已經可以在 PD 中收集 Region 相應的狀態變化;前端部分已經畫出簡單的 Region 分裂、合併等示意圖。
-
17:30 完成了最簡單的查詢邏輯,進行了第一次聯調,發現大家對於 Region 狀態的展示方式理解不一樣,於是再次討論統一了意見。
-
18:00 晚餐時間。
-
19:00 ~ 次日 2:30: 我們基本完成了後端開發,而前端這時還剩比較多的工作量。同時晚上在前端展示,後端查詢 API,資料持久化方面都發現了幾個 bug,大家一直忙到很晚才一一解決。
-
次日 9:00 返回賽場,抽籤確定 Demo 時間,最終為第四個出場。
-
次日 12:00 前端視覺化基本完善,為介面做最後的調整。
-
次日 12:00 ~ 12:30 午餐時間
-
次日 13:00 ~ 14:00 準備 PPT 和展示錄屏
-
次日 14:30 ~ 18:30 Demo Time(B 站直播)
TiEye 架構
我們採取了前後端分離的架構。
前端是 Vue.js 框架,使用 Typescript 語言開發。由於看上去現有的圖表庫啥的並不能很好地滿足我們的需求,所以前端同學決定手擼 SVG。
後端則是 PD 提供的 API。資料儲存目前暫時儲存在 etcd,將來會考慮其它方案來應對資料規模太大的情況。我們將 Region 的變化分成了以下四種:
-
LeaderChange:Raft Group 選舉(或者是主動移交)了新的 leader
-
ConfChange:Raft Group 成員變更
-
Split:當某個 Region 資料超過一定闕值時(或被手動干預時)會分裂成鍵值範圍相鄰的兩個 Region
-
Merge:兩個鍵值範圍連續的 Region 合併成一個
-
Bootstrap:一個新的叢集中第一個 Region 產生
在前端的表示方式如圖所示:
給 PD 新增的 API 則有如下幾種:
-
/pd/api/v1/history/list
,GET 方法,返回全部歷史。 -
返回結果:
[
{
"timestamp":1544286220000000,
"leader_store_id":0,
"event_type":"Bootstrap",
"Region":{
"id":2,
"start_key":"",
"end_key":"",
"Region_epoch":{
"conf_ver":1,
"version":1
},
"peers":[
{
"id":3,
"store_id":1
}
]
},
"parents":[],
"children":26
},
...]複製程式碼
/pd/api/v1/history/Region/{RegionId
,GET 方法,查詢某個 Region 的變化歷史,返回結果同上。
}/pd/api/v1/history/key/{key
,GET 方法,查詢某個 key 所屬 Region 的變化歷史,返回結果同上。
}
以上幾個 API 均可附加起止時間引數(時間戳),如:
/pd/api/v1/history/list?start=0&
end=1544286229000000複製程式碼
順便一提,前端部分原先打算作為 PD 的一部分來提供,與 PD 一起構建(於是前端的程式碼也放進了 PD 的一個單獨的資料夾裡)。但是後來覺得對於不涉及這些前端程式碼的開發者來說這樣做不太好,所以我們之後會抽時間將這些前端程式碼放進一個單獨的倉庫裡。
測試過程
測試的時候我們部署了1個 TiDB,6個 TiKV,3個 PD,通過 sysbench 匯入少量資料,最後通過開啟 random-merge-scheduler 來進行隨機合併 Region。下圖是我們的測試過程中的結果展示:
此時通過我們的工具還意外發現了一個 bug。
可以在上圖看到,在第一個紅框處 Region 2 合併進 Region 28,然後第二紅框那裡已經被 merge 進 Region 28 的 Region 2 莫名其妙地又連線了後面的 Region 40,顯然這裡是有問題的。經過通過日誌確認,這是由於 PD 收到了一個含有過期 Region 2 資訊的心跳導致的,追根溯源發現是 TiKV 中的 pd-client 的一個 Bug 導致了在與 PD 重連後會傳送一個過期的心跳資訊(Bug 地址在 github.com/tikv/tikv/i…
實際執行結果
- 橫軸表示時間,縱軸表示 Region 的儲存鍵值的順序(僅表示順序,不代表實際的資料量),矩形上的數字表示 Region id,為了便於理解,所有的 Region 的最終狀態都會在最後的時間點上展示出來(即使在這個時間點沒有發生 Region 的改變)。
- 點選右上角可以更改查下的時間範圍。
- 右上角可以設定按照 key 的範圍對齊,效果如下圖:
- 點選任何一個節點,會展示當時 Region 的詳細資訊。
- 拖動下方的框可以對區域性進行縮放(你也可以通過查詢更小的時間範圍達到同樣的效果)。
Hackathon Demo
我們團隊的 Demo 展示是博康負責的。一開始他還擔心如果演講的時候忘詞了怎麼辦,不過最後展示效果很不錯,整個 Demo show 進行得非常順利(P.S. 要是展示時間能多給幾分鐘就好了)。
在展示中,我們也看見了其他團隊的作品也都非常棒。這其中讓我最感興趣的是有個團隊做的是以 TiKV 作為資料儲存的 etcd。這個選題一開始我也考慮過,因為我在工作中實際已經遇到了這個問題,不過最後和隊友商量後還是選擇了現在這個題目。
總結
我們“矛盾螺旋”團隊最終獲得了三等獎,這對我來說簡直是意外之喜。在演示中,很多別的團隊也都做得十分優秀,我們在觀看其它團隊的演示時幾乎都覺得獲獎無望了。最後卻拿到了三等獎,實在是意料之外。這次我們之所以能夠獲獎,一方面是選題選得恰到好處,具有一定的實際作用,同時工作量又能保證在 Hackathon 期間完成。
最後感謝我的兩位隊友,謝謝導師,謝謝評委老師,謝謝 PingCAP 的所有工作人員為這次 Hackathon 所做的努力。
(?0:36:00 開始)矛盾螺旋隊 Demo 演示
TiDB Hackathon 2018 共評選出六個優秀專案,本系列文章將由這六個專案成員主筆,分享他們的參賽經驗和成果。我們非常希望本屆 Hackathon 誕生的優秀專案能夠在社群中延續下去,感興趣的小夥伴們可以加入進來哦。
延伸閱讀: