為什麼 Lettuce 會帶來更長的故障時間?
來源:阿里技術
這是2023年的第69篇文章
( 本文閱讀時間:15分鐘 )
本文詳述了阿里雲資料庫 Tair/Redis 將使用長連線客戶端在非預期故障當機切換場景下的恢復時間從最初的 900s 降到 120s 再到 30s的最佳化過程,涉及產品最佳化,開源產品問題修復等諸多方面。
01
背景
Lettuce1 是一款優秀的 Redis2 Java 客戶端,支援同步、非同步、流式等程式設計介面,深受使用者喜歡。2020 年開始,隨著其使用者量增大,很多使用者反饋其使用 Lettuce 客戶端時,在某些 Redis 故障當機情況下,Lettuce 會持續超時長達 15 分鐘,導致業務不可用。
阿里雲資料庫工程師也收到了客戶反饋,於是我們開始深入調查並持續跟蹤解決這個問題。終於,在最近 9 月份,這個問題得到了有效解決。下面我們以 Redis 的標準版架構來描述此問題(注意,即使在非雲環境,此問題仍舊存在)。
(圖 1. Redis 標準版雙副本切換流程)
Redis 標準版架構中,開源 SDK 透過域名解析獲取到 VIP 地址,建連到 Ali-LB,再到 Redis Master(圖中 1’ 和 1 連線對應)。
當 Master 由於非預期故障直接當機,有機率不會產生 RST 注。
HA 元件探測 Master 當機,呼叫 Ali-LB switch_rs 介面,將後端的連線從 Master 切換到 Replica。
切換完成後 Ali-LB 並不會主動釋放前端舊的客戶端連線,對於客戶端發到 Ali-LB 的包,由於後端不可用,預設丟棄,因此客戶端將持續超時。此時如果有新的連線建立(例如 4’,會建連到新的 Master)是不存在問題的,但 Lettuce 客戶端在超時情況下不會重新建立連線,因此舊連線存在問題。
直到到達 Ali-LB 的 est_timeout(預設 900s)之後,Ali-LB 會回覆 RST 斷開連線,之後客戶端恢復。
注:對於部分網路卡當機、網路分割槽故障等情況,機率性不會產生 RST。大多數的當機,作業系統會在退出前給客戶端傳送 RST,因此這個問題不是切換或者當機就必現;在正常切換情況下由於 Master 可服務,在第 3 步,HA 元件會主動傳送 client kill 命令給舊的 Master,從而讓客戶端發起一次重連恢復。
02
問題分析
首先這是一個 Lettuce 客戶端設計缺陷,原因見後文和其餘客戶端對比分析。
其次這是一個 Ali-LB 的不成熟的機制(切換之後保持靜默狀態,不關閉自己與 Client 的連線),因此所有使用 Ali-LB 的資料庫產品都會遇到,包括 RDS MySQL 等。
由於 900s 不可用對 Tair 來說影響太大,比如使用者 1 萬 QPS,那麼 900s 就涉及約千萬 QPS,因此我們率先來推動這個問題的解決。
2.1 為什麼 Jedis 和 Redisson 客戶端沒有問題?
Jedis 是連線池模式,底層超時之後,會銷燬當前連線,下一次重新建連,就會連線到新的切換節點上去並恢復。
Jedis連線池模式
try { jedis = jedisPool.getResource(); // 查詢前獲取一個連線 // jedis.xxx // 執行操作查詢} catch (Exception e) { e.printStackTrace(); // 超時,命令錯誤等情況} finally { if (jedis != null) { // 這裡的 close,如果連線正常,就返回連線池 // 如果連線異常,則會銷燬這條連線 jedis.close(); }}
Redisson 本身支援了間隔發 ping 給服務端判活,如果不通則發起重連。
Redisson 的 PingConnectionInterval 引數
// PingConnectionInterval: 間隔多少 ms 給服務端發 PING 包,在本連線上,如果不通則重連,預設 30000config.useSingleServer().setAddress(uri).setPingConnectionInterval(1000);RedissonClient connect = Redisson.create(config);2.2 能否透過配置 TCP 的 KeepAlive 來保活?
結論是不行,因為 TCP Retransmission Package 的優先順序高於 KeepAlive,即如果是一個活躍連線,當此問題出現時候,會先開始 TCP Retran,具體取決於 tcp_retries23 引數(預設 15 次,需要 924.6 s)。
(圖2. 活躍連線黑洞問題流程圖)
T1:Client 傳送 set key value 給 Ali-LB
T2:Ali-LB 回覆 ok
T3:Client 傳送 get key 給 Ali-LB,但是此時後端發生切換,之後 Ali-LB 沒有任何 Response,客戶端表現超時
T4:開始第一次 tcp retran
T5:開始第二次 tcp retran
T6:此時還在 tcp retran,但是因為到達 Ali-LB est_timeout 時間,因此 Ali-LB 回覆了 RST 回來,客戶端就會恢復了。那如果 Ali-LB 一直不回覆 RST,重傳結束之後,TCP 也是會主動斷開重連的,也可以恢復。
所以說,如果客戶端側想解決這個問題,依靠 TCP KeepAlive 是無法完成的,也可以參考知乎此問題《TCP中已有SO_KEEPALIVE選項,為什麼還要在應用層加入心跳包機制》4 ,而 Lettuce 在 6.1.05 版本開始支援了設定 KeepAlive 的選項,但如此前分析,這並不能解決活躍連線的問題。因此我們給 Lettuce 提了一個詳細的 issue6 ,來描述問題、復現方法、原因,可能的修復方法,作者也認同了問題。
03
問題解決
3.1 緊急止血
由於沒有別的有效方法,只能先將 est_timeout 調整到 120s (不能再小,否則會斷開正常靜默連線),這意味著使用者最多受損 135s(120s + 15s 探測,注意:不可用之後還要探測完才能發起切換)。
官網文件不推薦使用者使用 Lettuce。
3.2 客戶端側修復
嘗試一:為 Lettuce 新增 PingConnectionInterval
上述分析我們提到,如果客戶端側想解決這個問題,需要實現應用層的判活機制,簡而言之就是客戶端會在和服務端的連線上間接的插入判活資料包,注意,這裡使用的連線必須是客戶端和服務端已有連線,而不能是一個單獨的新連線,否則會誤判,因為問題是針對連線維度的黑洞,如果使用新連線判斷,那麼服務端會返回正常的結果。
提交了 commit7 之後,作者對這個方案並不是非常認同,他認為:
這個修復方法比較複雜。
由於 Lettuce 支援 Command Listener,他認為使用者可以在 Command 超時之後自己關閉連線。
Redis 本身存在一些 Block 的命令,例如 xread,brpop,此時連線是被 hang 住的,探活無法進行。
交流下來,我們拒絕因為修改複雜就讓使用者透過 Command Listener 的方法來自己關閉連線,這意味著每個使用者為了安全使用 Lettuce 都要改程式碼,成本將會非常高,但是 block 的命令透過此方案無法解決的問題也確實存在,因此暫時被擱置。
嘗試二:使用 TCP_USER_TIMEOUT
TCP USER TIMEOUT 是RFC 54288 規定的 TCP option,用來擴充套件 TCP RFC 7939 協議中本身的 "User Timeout" 引數(原協議不允許配置引數大小)。其用來控制已經傳送,但是尚未被 ACK的資料包的存活時間,超過這個時間則會強制關閉連線。用它可以解決上述 KeepAlive 無法解決的 Retran 優先順序高的問題,下面是 KeepAlive 和 Retran 以及 TCP USER TIMEOUT 一起工作的情況。
確認 TCP_USER_TIMEOUT 可以解決此問題後,和作者再次溝通,作者也同意了此修復訪問,我們提交了 PR10,並最終被合併,之後也驗證了修復的效果,符合預期。使用下述版本可以解決黑洞問題,但需要依賴netty-transport-native-epoll:4.1.65.Final:linux-x86_64,在 EPOLL 可用時,用下面程式碼開啟,tcpUserTimeout 可結合業務具體情況配置,建議 30s。
開啟 TCP_USER_TIMEOUT
bootstrap.option(EpollChannelOption.TCP_USER_TIMEOUT, tcpUserTimeout);
Lettuce 修復版本的SNAPSHOT版本<dependency> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> <version>6.3.0.BUILD-SNAPSHOT</version></dependency><dependency> <groupId>io.netty</groupId> <artifactId>netty-transport-native-epoll</artifactId> <version>4.1.65.Final</version> <classifier>linux-x86_64</classifier></dependency>3.3 Ali-LB 的修復方案
Ali-LB 側針對此問題,推出了 Connection Draining 功能,Connection Draing 意為連線排空,為了做優雅關閉使用。
優雅關閉意味著通常後端伺服器可用,如下圖一個 Ali-LB 後面掛有 4 個 Server,執行縮容操作移除 Server4,對於即將要發給這個 Server 的 Request 4 和 6(同連線上),在 draining 配置的時間內(0-900s),Server4 還是會對 Request 做出響應,等到 draining 時間到達之後才斷開連線,注意:draining 之後,新的連結就不會再排程給 Server4 了,因此後續的7,8,9等請求都不會再發給 Server4 了,這也是能排空的前提。
因此一旦開啟 draining,則在最遲到達 draining 時間之後,客戶端就會收到 Ali-LB 的 RST 了。
(圖 3. Connection Draining 示意圖)
對比 est_timeout 機制,Connection Draining 的優勢是減少了誤判,盡最大能力交付。
(表1. est_timeout 對比 connection draining)
Ali-LB 團隊上線 Connection Draining 之後,我們配合驗證,可以將故障時間從 120s 縮短至 30s 內,符合 Redis 產品的 SLA,目前已經全網釋出完成,這也解決其餘 Redis 收斂連線 SDK,和整個資料庫產品的連線黑洞問題。
04
總結
本文詳述了 Lettuce 客戶端黑洞問題的原理和解決方案:
從客戶端側:可以升級 Lettuce 最新的 6.3.0 版本,並開啟 TCP_USER_TIMEOUT 引數。在阿里雲上,無需修改程式碼,Ali-LB 的 Connection Draining 將會主動避免此問題,(無需使用者升級,阿里雲會主動逐步變更)。
一個應用廣泛的軟體包的惡性 Bug 傷害巨大。比如這次 Lettuce,本來屬於 Spring Boot 中最常用的 Redis SDK,由於作者的矯情也好,較真也好(見6)導致數年中諸多雲上使用者出現大量惡性故障,我們在推動中既看到如 Azure、AWS 和華為在諮詢和推動,也看到無數期待 Fix 的開發者。Redis 和 Tair 也要加大在社群 SDK 的投入,尤其是自研,自主自控的 SDK 尤為重要。
此問題從發現,到修復歷時約 2 年,終於被解決,道阻且長,行則將至!
參考閱讀
[02]
[03] tcp_retries2
https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
[04] 《TCP中已有SO_KEEPALIVE選項,為什麼還要在應用層加入心跳包機制?》
[05] /issues/1437
[06] /issues/2082
[07]
[08] TCP_USER_TIMEOUT
[09]
[10] /pull/2499
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2986573/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 六西格瑪為什麼會風行這麼長的時間?
- 次世代主機載入時間過短會帶來什麼樣的困擾?
- 為什麼現在開發一款軟體的時間越來越長?
- 為什麼“敏捷”會浪費這麼多時間? - Reddit敏捷
- gRPC為什麼使用截止時間而不是超時時間?RPC
- 越過5G的時代斷崖:搜狗分身技術會為IP產業帶來什麼?產業
- 如果你的生命所剩無幾,那麼剩下的時間,你會用來做什麼
- 孩子長大了能給父母帶來什麼?
- 為什麼 AI 時代更應該 Learn in PublicAI
- React Hooks 可以為我們帶來什麼,及為什麼我覺得React才是前端的未來ReactHook前端
- 無處不在的時序資料能帶來什麼?
- 中間表是什麼?和報表有什麼關係?會帶來怎樣的問題?又如何解決?
- AI與雲端計算的深度融合會帶來什麼?AI
- 為什麼感覺時間越過越快?
- 為什麼升級到 MySQL 8.x 後,帶有多個 IN 值的查詢會更昂貴?MySql
- 為什麼《夢幻西遊》能這麼長壽?大型複雜遊戲如何長時間經營?遊戲
- 為什麼 Vue 更符合這個時代的大勢所趨?Vue
- iOS12 beta4會帶來什麼新功能? iOS12 beta4什麼時候出iOS
- AI與區塊鏈的融合會給人類帶來什麼?AI區塊鏈
- IT 服務管理可以為你帶來什麼好處?
- 致同:同理心能為企業帶來什麼?
- 為什麼說“概率”帶來一場現代革命?
- KPI過時了?為什麼科技公司更偏愛OKR?KPIOKR
- 為什麼要用setTimout來做定時器?定時器
- 張馳課堂:為什麼疫情期間大家都來考六西格瑪綠帶黑帶證書?
- 什麼是基於模型的管理,它可以為組織帶來什麼好處?- modernanalyst模型NaN
- Istio控制平面故障後會發生什麼?
- 新媒體運營主要學什麼,多長時間?
- 為什麼不要輕易勸別人“做時間的朋友”?
- 為什麼專案開發永遠缺乏合理的時間?
- GitOps實踐指南:GitOps能為我們帶來什麼?Git
- 精益生產諮詢為公司帶來了什麼?
- SRM系統可以為企業帶來什麼價值?
- 低程式碼平臺能為企業帶來什麼?
- 為什麼電話機器人能為企業帶來更高的利潤?機器人
- 為什麼我們應該相信區塊鏈技術會給世界帶來變化區塊鏈
- 線上會計軟體是什麼,它能為企業發展帶來哪些好處?
- 帝國cms為什麼釋出時間比實際時間相差8個小時?