記一次 Redis Cluster 當機引發的事故
導讀:
Redis官方號稱支援併發11萬讀操作,併發8萬寫操作。由於優異的效能和方便的操作,相信很多人都在專案中都使用了Redis,為了不讓應用過分的依賴 Redis服務,Redis的作用只作為提升應用併發和降低應用響應時間存在,即使Redis出現異常,應用程式也不應該出現提供服務失敗問題,對此拍拍信最近安排了一次全環境的Redis Cluster 當機演練。
許彬:拍拍信架構負責人。
朱榮鬆:拍拍信架構開發工程師。
一、演練過程
Redis 叢集環境:
1. 測試環境:
Redis Cluster 配置 :Redis 3主 3從 一共6個節點。
2. 預發環境:
Redis Cluster 配置 :Redis 3主 3從 一共6個節點。
下面是我們操作的時間線:
第一天
程式執行中關閉任意一臺從節點,測試一天均無異常。
第二天
程式執行中關閉任意一臺從節點,程式未發現異常,測試一天未發現異常。
第三天
預發環境有應用發版,出現異常程式無法啟動。
……
二、問題描述
首先說明幾個前提:
1. 測試與預發環境目前關閉的都是任意一臺Redis從節點。
2. 測試環境經過反覆測試無問題才開始關閉預發環境節點。
3. 預發環境重啟被關閉的Redis節點後異常消失。
4. 連線Redis客戶端使用的是Java語言中使用範圍較廣的Jedis。
那麼為什麼測試環境在經過反覆測試沒有問題,到預發環境會出現問題?
三、原理
分析問題前先簡單解釋下Redis Cluster實現原理。簡單來說Redis Cluster中內建了 16384 個雜湊槽,當需要在 Redis Cluster中存取一個 key或者value時,Redis 客戶端先對 key 使用 crc16 演算法算出一個結果,然後把結果對 16384 求餘數( 演算法為:crc16(key)mod 16384),這樣每個 key 都會對應一個編號在 0-16383 之間的雜湊槽,值得注意的是這個計算key是在哪個槽上的操作是Redis 客戶端做的操作,Java中常用的客戶端為Jedis 這個也是被Spring推薦的一種客戶端。
注: 如果有人好奇為什麼Redis Cluster為什麼會使用16384也就是2^14個槽。可以檢視 Githubhttps://github.com/antirez/redis/issues/2576作者對此進行了解釋。
四、分析
首先是檢視程式啟動異常資訊,下圖1為程式異常資訊。
圖1異常很明顯丟擲的是連線異常
檢視了Jedis的原始碼後發現初始化Redis Cluster的槽資訊時,呼叫initializeSlotsCache()方法時出現異常。圖2 為此方法的具體實現,分析程式碼發現此程式碼的目的應該是需要cache Redis Cluster槽資訊,由於程式碼中有break,所以是隻需要連線Redis獲取一次資訊即可。細一看此程式碼應該是有Bug,Try 的範圍沒有覆蓋到Jedis連線的操作,如果Jedis連線失敗直接丟擲連線失敗異常,此迴圈會直接退出,與程式碼實際預期不符合。
圖2
由此引發另一個思考,是不是我關閉的節點正好為迴圈的第一個節點導致此問題。嘗試關閉另外一臺從節點後程式正常啟動。那麼Jedis載入的節點順序是什麼,似乎Jedis對節點順序進行了排序操作。在檢視原始碼後發現Jedis重寫了Redis節點配置類的hashCode方法。
圖3
圖4
下面簡單測試下如果配置為:jedis-01.test.com、jedis-02.test.com、jedis-03.test.com、jedis-04.test.com、jedis-05.test.com、jedis-05.test.com輸出順序是什麼。
圖5
輸出結果:
[redis-06.test.com:6379,redis-04.test.com:6379, redis-01.test.com:6379, redis-03.test.com:6379, redis-02.test.com:6379,redis-05.test.com:6379]
也就是說如果關閉redis-06.test.com:6379這臺節點,程式就會出現啟動失敗問題。
五、解決
問題定位後首先去Github上的檢視相關問題是否有人遇到,在查詢後發現此問題有人在去年11月提了PR解決了此問題,連結如下:
https://github.com/xetorthio/jedis/pull/1633
官方目前釋放出了2.10.0-m1和3.0.0-m1中解決了此問題,但是由於不是Release版本使用還得注意。解決的辦法為圖6,和圖2對比可以發現圖6對Jedis的例項化也進行了try catch。
圖6
六、思考
Redis Cluster由於使用去中心化思想 ,圖7 顯示了Redis Cluster叢集的狀態,所以Redis Cluster 中如果有部分節點異常就會導致整個叢集異常。
圖7
那麼問題來了多少節點異常會導致程式讀寫操作出現異常,下面我們也做了個簡單的測試用於統計程式執行中,關閉Redis節點後程式的出錯情況,以下測試表1僅供參考。
場景 | 操作(多節點均同時操作) | Redis寫總量 | Redis讀總量 | 錯誤量 | 總耗時(s) | 錯誤率 |
程式執行中 | 關主(關任一主) | 100000 | 100000 | 3084 | 100 | 0.031 |
關主(關任一主) | 100000 | 100000 | 1482 | 102 | 0.015 | |
關主(關任一主) | 100000 | 100000 | 3053 | 97.6 | 0.031 | |
關從(關任一從) | 100000 | 100000 | 0 | 109.2 | 0 | |
關從(關任一從) | 100000 | 100000 | 0 | 90.1 | 0 | |
關從(關任一從) | 100000 | 100000 | 0 | 88.9 | 0 | |
主從一起關(關任一對) | 100000 | 100000 | 32613 | 210.1 | 0.326 | |
主從一起關(關任一對) | 100000 | 100000 | 29148 | 169.8 | 0.291 | |
主從一起關(關任一對) | 100000 | 100000 | 32410 | 173.7 | 0.324 | |
所有主全關 | 100000 | 100000 | 100000 | 353.4 | 1 | |
所有從全關 | 100000 | 100000 | 0 | 87.7 | 0 | |
只留一臺主 | 100000 | 100000 | 100000 | 357.1 | 1 |
表1
從測試結果看,叢集Master的選舉過程是由Master參與選舉的。
1. 如果半數以上 Master 處於關閉狀態那麼整個叢集處於不可用狀態。
2. 關閉任意一對主從節點會導致部分(大約為整個叢集的1/3)失敗。
3. 關閉任意一主,會導致部分寫操作失敗,是由於從節點不能執行寫操作,在Slave升級為Master期間會有少量的失敗。
4. 關閉從節點對於整個叢集沒有影響
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31562044/viewspace-2286388/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Redis Cluster 當機引發的事故Redis
- 記go中一次http超時引發的事故GoHTTP
- 記一次自定義starter引發的線上事故覆盤
- Redis分散式鎖引發的工作事故Redis分散式
- 一次依賴注入不慎引發的一連串事故依賴注入
- 記一次go中map併發引起的事故Go
- 記一次JVM FullGC引發嚴重線上事故的定位、分析、解決過程!JVMGC
- 一次mongo查詢不存在欄位引發的事故Go
- Redis-cluster命令 cluster info 引數資訊解釋Redis
- 記一次處理事故
- 記一次訂單號事故
- git stash 引發得事故Git
- 【Redis】redis-cluster到redis-cluster的快速複製Redis
- 【故障公告】redis 伺服器當機引發部落格站點故障Redis伺服器
- 執行緒池運用不當的一次線上事故執行緒
- Redis Manager 建立 Redis Cluster —— 機器安裝Redis
- 記錄一次錯誤的使用當前時間new Date()引發的錯誤
- 一個與運算引發的事故
- 與親生的Redis Cluster,來一次親密接觸Redis
- 線上問題排查:記一次 Redis Cluster Pipeline 導致的死鎖問題Redis
- 記一次 redis 事件註冊不當導致的記憶體洩露Redis事件記憶體洩露
- 記一次Content-Length引發的血案
- 記一次線上問題引發的對 Mysql 鎖機制分析MySql
- 記一次記憶體溢位導致的生產事故記憶體溢位
- 一次事故的回顧
- Redis Cluster原理Redis
- Redis Cluster 3.0Redis
- redis cluster 搭建Redis
- 記一次資料庫事故-ORA-15038資料庫
- Facebook當機事故,暴露了上雲不是唯一的答案
- redis 單機和cluster資料遷移Redis
- Redis基礎知識(學習筆記5--Redis Cluster)Redis筆記
- 記一次Lombok的Setter過載方法造成的事故及思考Lombok
- 一次app抓包引發的Android分析記錄APPAndroid
- Redis當機恢復Redis
- 一次線上Redis類轉換異常排查引發的思考Redis
- Redis服務之Redis ClusterRedis
- 「生產事故」MongoDB複合索引引發的災難MongoDB索引