ZooKeeper-3.4.6叢集選舉Bug踩坑與恢復記錄
來源:轉轉技術
1 問題背景
2 探索
2.1 各節點埠的連通性統計
2.2 未重啟節點狀態檢查
2.3 透過日誌檔案尋找線索失敗
2.4 線上ZK節點新增埠探測監控
2.5 柳暗花明
3 叢集恢復方案制定
3.1 測試環境還原線上叢集
3.2 測試Codis叢集和demo服務連線到測試ZK叢集
3.3 關鍵要素測試
3.4 方案選擇
4 方案落地
4.1 日誌滾動調整配置檔案
4.2 準備3節點小叢集
4.3 老節點工作路徑配置調整與滾動操作
5 總結
1 問題背景
我司快取Codis依賴的ZooKeeper服務,在探索異地機房資料庫高可用方案時,期望透過新增observer的方式實現異地容災,但在方案實施階段出現了新增observer節點失敗,並發現選舉埠不通的日誌記錄,復現狀態如下:
我
:???,先telnet一下leader的3888埠試試
我
:3888 真的不通了?!!新節點不能加入叢集!!!但是老叢集讀寫狀態是正常的,這情況太離譜了......
我
:重啟老節點,叢集應該會重新發現節點,順便恢復選舉埠
......
我
:完了...老節點埠通了但是也回不到叢集了??!
捋清操作時間線,同步ZK叢集現狀,向各位同事大佬求助,嘗試將叢集恢復到正常狀態。
為了填平賭上職業生涯重啟ZK節點的坑,開啟了本篇的探索之旅。
2 探索
2.1 各節點埠的連通性統計
2.2 未重啟節點狀態檢查
close_wait的來源都是安全掃描的IP地址但是根本沒有成功建立連線
2.3 透過日誌檔案尋找線索失敗
因為使用的預設配置啟動服務,ZK日誌沒有有效的切割和生命週期管理,僅使用 ">" 清空處理過,當前最大的日誌已經堆積了20G之多,遺憾的是最後透過排查也沒有找到有效資訊。
2.4 線上ZK節點新增埠探測監控
監控新增後大約1個小時左右,重啟的新節點3888選舉埠又不通了!!
2.5 柳暗花明
透過ITCP架構群發出issue,得到了去哪兒網小夥伴的積極回應,對比兩方的jstack,發現我們的ZK缺少了QuorumCnxManager$Listener執行緒!!!
這個執行緒是負責監聽3888選舉埠,並accept選舉請求的。我們未重啟節點裡這個執行緒都沒了!!!
由此一切都解釋通了,多數節點的選舉功能失效,當有節點想加入叢集時,當然不可能透過。
具體的排查驗證過程可查閱往期精品文章 ↓↓↓
如果你也在用ZK,那這個導致叢集掛掉的坑一定得注意!
至於這個issue問題的修復也在 ZooKeeper-3.4.7版本完成,使用高版本的讀者朋友們可以放心了~
3 叢集恢復方案制定
3.1 測試環境還原線上叢集
測試環境使用線上snapshot恢復搭建 ZooKeeper-3.4.6 版本5節點叢集,myid 和 角色完全與線上一致,然後透過telnet -1 將所有節點3888選舉埠打掛掉,重啟測試叢集6號/8號兩節點形成以下狀態。
3.2 測試Codis叢集和demo服務連線到測試ZK叢集
確認Codis-Proxy在測試ZK叢集內註冊了臨時節點;
確認服務在使用不同版本客戶端時,可以從測試ZK叢集獲取到Codis-Proxy地址資訊建立連線且讀寫操作正常。
3.3 關鍵要素測試
3.3.1 ZooKeeper 版本升級
ZooKeeper-3.4.6以後版本,使用版本號3.4.13,是否完美向下相容,映象恢復是否可行,操作流程順序是什麼?
3.3.2 Codis-Proxy 臨時節點註冊功能
在ZK叢集和ZK節點服務均正常情況下,Codis-Proxy連線到ZK叢集會向 /jodis/{CodisProductName}/ 寫入 proxy-{proxyToken} 臨時節點資訊,ZK叢集恢復的判斷條件之一必須是Codis-Proxy臨時節點註冊沒有異常。
3.3.3 多個版本的Codis客戶端表現
服務啟動後客戶端會快取ZK節點域名解析地址(形如codiszk.domain.com:2181)無法變更,只能原地操作叢集恢復;
客戶端連線到ZK叢集后,能否獲取到Codis-Proxy臨時節點,並完成Codis叢集資料的讀寫功能。
3.3.4 日誌切割
指定儲存路徑,按日切割,如何建立完整的日誌滾動生命週期管理規則。
3.4 方案選擇
關鍵要素經過多輪測試,彙總,總結以下兩套備選方案
3.4.1 原地滾動升級
準備新的ZooKeeper-3.4.13工作目錄,老叢集寫入Codis-Proxy永久節點資料,將6號和8號老節點停服,在新目錄使用老叢集最新映象啟動新服務,然後老叢集記憶體活的3節點順序關閉的同時啟動新版本ZK節點,形成3.4.13版本新叢集。
此方案優點:
操作簡單,理解容易,連續性強; 建立新工作目錄後,複製老叢集leader資料目錄,日誌目錄,配置檔案過來,更新 myid 即可。
缺點:
一定會引起ZK服務中斷(老叢集3節點任意關閉一個則整體不可用並觸發重新選舉)。
3.4.2 異常老節點下線拉起新叢集然後恢復到5節點叢集
由於6號/8號兩節點已經不提供服務,老叢集資料短時間內也不會有變動,索性重新搭建一套3節點叢集,資料與線上一致,然後重新擴容恢復到5節點叢集!
準備新的ZooKeeper-3.4.13工作目錄,老叢集寫入Codis-Proxy永久節點資料,將6號和8號老節點停服並引入一個新節點,在新節點工作目錄使用老叢集最新映象啟動服務,然後兩個離線節點機器與臨時新節點組成3節點小叢集,此時小叢集的資料與線上一致且刷入了Codis-Porxy永久節點資料,已經可以提供服務,後面只需要儘快把老叢集節點關閉轉為高版本新節點重新加入新叢集就好了。
此方案優點:
規避了ZK服務中斷的情況,老叢集節點全部離線後,客戶端可以向小叢集重新建連。
缺點:
主動分裂形成了兩套叢集,有導致資料不一致的風險,必須儘快完成叢集的恢復。
4 方案落地
人生真是寂寞如雪呀...
2024年的1月都比平時更冷了一些...
某天后半夜工位周圍聚集了一圈大佬,反覆確認了以下恢復流程。
4.1 日誌滾動調整配置檔案
log4j被爆出過安全性漏洞,ZooKeeper-3.4.13使用了log4j 1.2.17,在沒有明確引用SocketServer建立監聽服務時,安全性較高,如果想完全解決需要升級log4j 2.x版本或者升級到ZooKeeper更高版本。
4.1.1 環境配置檔案bin/zkEnv.sh
修改預設日誌檔案路徑到 logs下,增加日誌配置 按日滾動規則;
4.1.2 節點配置檔案conf/log4j.properties
增加滾動升級配置方案支援和統一啟動檔案日誌名稱; 修改滾動升級方案到按日切割;
老ZK叢集節點6號/7號/8號/9號/10號都必須在例項本機ZooKeeper-3.4.13版本新工作路徑操作節點替換,業務客戶端快取的ZK節點DNS解析IP地址不能變。
從配置檔案conf/zoo.cfg確認dataDir(映象儲存路徑)和 dataLogDir(事務日誌儲存路徑);
{dataDir}路徑更改myid: 老叢集6號節點替換為2號,老叢集8號節點替換為3號,1號為臨時引入例項,最後清理掉;
配置檔案conf/zoo.cfg註釋線上7號/9號/10號/新增1號,關閉6號/8號例項,刪除{dataDir}/version-2 和 {dataLogDir}/version-2 目錄;
確保線上ZK叢集已經刷了全量Codis-Proxy永久節點資料到/jodis下,從10號(leader)複製dataDir和 dataLogDir完整目錄到 1號 ZK工作路徑下,啟動1號,再啟動2號/3號節點(2號/3號仍在接收線上請求,後啟動直接恢復全量資料即可接收連線提供服務)。
4.3 老節點工作路徑配置調整與滾動操作
同樣在例項本機ZooKeeper-3.4.13版本工作路徑操作,各節點先提前備好server資訊:
7號例項: 調整myid為4號,conf/zoo.cfg 調整例項資訊為server 1234,4條;
9號例項: 調整myid為5號,conf/zoo.cfg 調整例項資訊為server 12345, 5條;
10號例項: 調整myid為6號,conf/zoo.cfg 調整例項資訊為server 123456, 6條;
關閉 7號/9號/10號 全部老例項,切換到ZooKeeper-3.4.13工作目錄操作(關閉任意例項後,Codis-proxy即斷連並向新叢集註冊);
啟動4號新例項,加入新叢集,調整123配置檔案,新增4號server資訊,然後順序重啟例項231(1號為leader,最後重啟),此時4號為leader;
啟動5號新例項,加入新叢集,調整1234配置檔案,新增5號server資訊,然後順序重啟例項1234,此時5號為leader;
啟動6號新例項,加入新叢集,調整12345配置檔案,新增6號server資訊,然後順序重啟例項12345,此時6號為leader;
關閉1號例項,調整23456配置檔案,註釋1號server資訊,然後順序重啟例項23456,叢集恢復,此時5號為leader。
操作期間反覆的確認各ZK節點的連線情況,服務狀態,叢集狀態,日誌資訊
最終...
[root()@XShellTerminal bin]#echo mntr |nc localhost 2181
zk_server_state leader
zk_synced_followers 4.0
......
ZK叢集恢復完成,升級完成,日誌切割完成
5 總結
ZooKeeper的埠探測功能需要健全,比如服務埠/選舉埠/同步埠,本次踩坑經歷本可以儘早發現並及時處理; 不要糾結於當前的Bug問題,小版本升級讓你無後顧之憂; 方案的落地需要經過前期嚴格周密的關鍵目標測試,儘量做到一切符合“預期”; 做好兜底策略,只有一萬,沒有萬一。
關於作者
王嗣鑫,DBA,轉轉快取/運維平臺開發負責人,平平無奇的一個踩坑奇才。
來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70027826/viewspace-3006604/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mybatis學習與踩坑記錄MyBatis
- laravel踩坑記錄Laravel
- sealos踩坑記錄
- DietPi踩坑記錄
- Solr 部署與使用踩坑全記錄Solr
- Elasticsearch叢集的備份與恢復Elasticsearch
- strtotime 踩坑記錄
- ABP框架踩坑記錄框架
- Electron工程踩坑記錄
- gorm踩坑記錄(一)GoORM
- MySQL_踩坑記錄MySql
- spring boot學習與踩坑記錄Spring Boot
- Oracle 19c叢集安裝踩坑記錄-多私網Oracle
- 記一次Kafka叢集的故障恢復Kafka
- Laravel7 踩坑記錄Laravel
- vuePC專案踩坑記錄Vue
- React專案踩坑記錄React
- node link 踩坑記錄
- ES6踩坑記錄
- Go json 踩坑記錄GoJSON
- Taro 小程式 踩坑記錄
- Mac下Charles踩坑記錄Mac
- 微信小程式踩坑記錄微信小程式
- React同構踩坑記錄React
- iOS11踩坑記錄iOS
- [Hadoop踩坑]叢集分散式環境配置Hadoop分散式
- Python使用ClickHouse的實踐與踩坑記錄Python
- flutter前端入門踩坑記錄Flutter前端
- Electron Built-in AutoUpdater 踩坑記錄UI
- ijkplayer編譯踩坑記錄編譯
- uniapp開發踩坑記錄APP
- Next.js踩坑記錄JS
- 微信小程式BLE踩坑記錄微信小程式
- 我的學習(踩坑)記錄
- laravel-echo-server 踩坑記錄LaravelServer
- 新手學習laravel踩坑記錄Laravel
- Laragon 編譯 Vue 踩坑記錄Go編譯Vue
- JavaScript兩數相加(踩坑)記錄JavaScript