VDL:唯品會強一致、高可用、高效能分散式日誌儲存 (質量篇)
這是VDL系列的第三篇,本文主要講述VDL在質量控制上的一些工作。
FIU測試
分散式系統,在正常情況下還是比較簡單的。異常情況才是分散式系統的難點,包括節點故障、磁碟異常、網路延時/丟包、網路分割槽等等。如何在這些異常或者異常組合的情況下保證VDL穩定正常,這是VDL的重難點之一。
FIU是Fault Injection Utility的縮寫,是我們為了更好地測試分散式系統(RDP/VDL)自研的一個小工具。FIU的主要目的是:自動化構造各種異常/錯誤,並且具備定製擴充套件的能力。
VDL使用FIU來模擬上述各種異常,並測試在異常情況下,VDL是否正常(表現是否符合預期)。我們先來簡單介紹一下FIU框架。
FIU框架
如上圖所示,FIU由三個元件組成:
-fiu_driver:driver是總控節點,是所有test case的發起端,為每一個test case準備所需的異常/錯誤等前提條件,然後執行設計的test case; fiu_driver和fiu_agent之間透過UDP協議通訊;
-fiu_agent:和測試的目標程式執行在相同機器上,負責接受fiu_driver的指令並在目標測試的機器上進行各種操作,完成這些操作一般透過編寫shell指令碼完成;FIU本身提供一些shell原型,使用者開發的shell原型會自動同步到fiu_driver端,所以測試行為可以靈活擴充套件;fiu_agent和fiu_engine之間透過named shared memory同步fiu_driver開啟的sync point;
-fiu_engine:以原始碼和so兩種方式嵌入到被測試的專案中,主要是插入各種sync point 和各種定點異常。
目前VDL的異常用例有30多例,還在不斷地新增中,主要分類有:
1.模擬磁碟IO異常:包括磁碟寫入異常、寫入延時;
2.模擬網路異常:包括丟包,Delay,使用TC進行模擬。我們並不處理拜占庭的情況;
3.程式異常:包括隨機Kill/Kill -9 VDL節點;
4.Raft流程異常:包括Delete Raft Log,落後節點加入叢集,不斷停止Leader節點等情況;
5.Log Store異常:包括資料損壞、索引檔案異常等情況;
6.客戶端異常測試:包括客戶端邊界請求、異常請求測試。
FIU的例子:
我們舉一個例子方便與更加直觀理解。假設我們有一個三節點組成的VDL叢集,配合FIU,部署圖如下:
(FIU Driver也可以跟agent機器部署在一起)
上圖中fiu_driver用於給agent傳送執行請求,異常測試用例指令碼會部署在driver所在伺服器,在執行用例過程中,指令碼會呼叫fiu_driver給agent傳送命令。fiu_driver不是常駐程式。
fiu_agent接收fiu_driver的請求,執行操作。主要有執行shell指令碼與往Share Mem Map 注入異常資訊。fiu_agent是常駐程式。
假設我們要完成如下的異常測試:
1.#####################################
2.#
3.# 流程:
4.#
5.# 測試與Raft流程相關的儲存介面異常時,VDL叢集情況
6.# 1) 啟動3節點叢集,啟動傳送服務
7.# 2) 選取一個節點,往儲存介面注入錯誤
8.# 3) 判斷節點情況
9.# 4) 恢復節點,清除錯誤
10.# 5) 迴圈2-4,向下一個介面注入錯誤
11.# 6) 共測試20次
12.# 7) 完成20次異常後,清除錯誤,關閉傳送服務,並檢查
13.#
14.# 預期:
15.# 1) 注入錯誤後,節點會crash
16.# 2) 叢集恢復正常後, 叢集有Leader, 且三節點raft log資料一致
17.#
18.# ###################################
那麼需要實現一個測試用例,並放在driver所在的機器上:
1.function TestCase_logstore_error() {
2.// 過程先略過
3.}
我們按用例的流程介紹:
-第一步: 啟動3節點叢集,啟動傳送服務
1.function TestCase_logstore_error() {
2.
3....
4.# 啟動vdl0
5.local start_vdl0=`${fiu_driver} ${vdl0_ip} ${fiu_port} 'remote.sync.pipe' 'sh '${vdl_root}'/tools/fiu/fiu_agent/script/start_vdl.sh' '10000'`
6.# 檢查vdl0是否正確
7.Expect_EQ $start_vdl0 "1"
8.
9.# 啟動vdl1
10.local start_vdl1=`${fiu_driver} ${vdl1_ip} ${fiu_port} 'remote.sync.pipe' 'sh '${vdl_root}'/tools/fiu/fiu_agent/script/start_vdl.sh' '10000'`
11.# 檢查vdl1是否正確
12.Expect_EQ $start_vdl1 "1"
13.
14.# 啟動vdl2
15....
16.
17.# 啟動傳送服務
18.# 啟動傳送服務會執行本地的一個shell指令碼,包括動態編譯producer並啟動,不再詳細展開。
19.echo '-------------produce message async(start)----------------'
20.${vdl_root}/tools/fiu/fiu_agent/script/pmsg.sh 6000 5 t
21.
22.}
指令碼中,start_vdl1命令中的fiu_driver是driver的路徑,vdl0_ip是要啟動的VDL的IP地址,fiu_port是agent的port,remote.sync.pipe是指要同步執行, xxxx/start_vdl.sh是指agent要執行的指令碼,10000是指超時時間。
啟動VDL,測試指令碼會呼叫driver,往agent傳送啟動命令。agent接受到請求後,執行本地指令碼並返回結果,流程圖如下:
-第二步: 選取一個節點,往儲存介面注入錯誤
1.function TestCase_logstore_error() {
2.
3.......
4.
5. #這裡定義要注入的錯誤的陣列
6.local store_interface_error_array=('fiu_logstore_entries_error' 'fiu_logstore_term_error' ...省略)
7.local error_array_count=${#store_interface_error_array[@]}
8.
9.#------節點注入錯誤--------------------------------
10.for((i=0;i<20;i++))
11.{
12.# 偽隨機選取要注入的異常
13.local inject_node=$((i%3))
14.local inject_error_index=$(( i % error_array_count ))
15.
16.echo '--------注入錯誤-----------'
17.PrepareOneCondition ${vdl_ip_array[inject_node]} ${fiu_port}'sync.point'${store_interface_error_array[inject_error_index]}
18.
19.#下面是檢查程式碼
20....
21.}
22.}
關鍵程式碼是:
1.PrepareOneCondition ${vdl_ip_array[inject_node]} ${fiu_port}'sync.point'${store_interface_error_array[inject_error_index]}
PrepareOneCondition是共用函式,實際是呼叫driver,往agent執行'sync.point'命令。流程如下:
往Share Mem Map插入Key後,VDL使用fiu_engine的介面,就能獲取到對應的錯誤訊號,程式碼如下:
1. // 下面是Go程式碼
2.func (s *LogStore) Term(i uint64) (uint64, error) {
3.
4.// mock error
5.if fiu.IsSyncPointExist(vdlfiu.FiuStoreTermError) {
6.return 0, errors.New("Mock FiuStoreTermError")
7.}
8.}
-後面幾步: 與前面的第一、二步類似,例如"判斷節點情況",則Driver傳送'remote.sync.pipe'請求到agent,agent執行"檢查VDL指令碼",返回結果。
到目前為止,我們介紹了VDL如何使用異常測試對各種情況進行模擬。下面我們來講講如何校驗節點間資料一致性。
節點資料一致性校驗
判斷VDL是否能正常服務,可以簡單透過監控頁面看到,但如何才能簡單地確認叢集的資料是一致的呢?VDL在壓測環境下,三個副本,目前共生產2400多億條資料,並且還在不斷增長中,灰度環境兩天就能產生15億條資料,如何才能簡單校驗副本間資料都是一致的呢?
由於資料量太多,不可能對每條資料進行對比,且每個節點的log檔案不相同,也不可以簡單使用md5直接對比檔案。對此我們自研了一個資料校驗工具,校驗節點間的資料一致性。使用的方案是連續checksum的方式對資料進行對比。
如圖所示,三個節點均從某個index開始,計算連續的checksum,只要相同的index有相同的checksum,則認為三節點資料均一致。
在實際使用中,我們將每個節點的checksum資料按一定規則輸出到日誌中,我們只要校驗最新的相同的index,若有相同的checksum,則在["計算的index", "校驗的index"] 這個區間的資料均一致。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900365/viewspace-2222265/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 基於MFS高可用的分散式儲存架構分散式架構
- 02 . 分散式儲存之FastDFS 高可用叢集部署分散式AST
- 分散式日誌儲存架構程式碼實踐分散式架構
- 高效能、分散式、實時日誌服務 - TLog分散式
- HDFS分散式儲存分散式
- Redis 分散式儲存Redis分散式
- SpringBoot接入輕量級分散式日誌框架(GrayLog)Spring Boot分散式框架
- python日誌怎麼儲存Python
- lumen cli日誌和普通日誌分開儲存
- 可靠的分散式KV儲存產品-ETCD-初見分散式
- 分散式儲存ceph 物件儲存配置zone同步分散式物件
- DAOS 分散式非同步物件儲存|儲存模型分散式非同步物件模型
- 如何編寫高質量的函式 -- 敲山震虎篇函式
- 分散式儲存架構知識,一篇講清楚!分散式架構
- 分散式儲存轉崗記分散式
- Gartner:浪潮儲存進入分散式儲存前三分散式
- 哪些企業需要分散式式儲存?分散式
- 分散式架構的高效能與可用性分散式架構
- 分散式塊儲存 ZBS 的自主研發之旅 | 架構篇分散式架構
- 儲存服務質量優化優化
- Laravel 使用 Elasticsearch 作為日誌儲存LaravelElasticsearch
- PG wal 日誌的物理儲存分析
- 「如何設計」高可用的分散式鎖分散式
- 日誌: 分散式系統的核心分散式
- 分散式日誌元件GrayLog入門分散式元件
- 分散式儲存glusterfs詳解【轉】分散式
- GlusterFS企業分散式儲存【轉】分散式
- 什麼是HDFS 分散式儲存分散式
- python如何分散式儲存檔案?Python分散式
- PolarDB-X 高可用儲存服務 基於 X-Paxos 一致性協議協議
- CEPH分散式儲存搭建(物件、塊、檔案三大儲存)分散式物件
- 如何編寫高質量的 JS 函式(1) -- 敲山震虎篇JS函式
- Laravel 5.6+ 使用 MongoDB 儲存框架日誌LaravelMongoDB框架
- 使用 Easysearch,日誌儲存少一半
- 我們NetCore下日誌儲存設計NetCore
- 唯品會的“成年煩心事”
- LNMP 分散式叢集(六):keepalived 高可用方案LNMP分散式
- 分散式服務高可用實現:複製分散式