Bigkey問題的解決思路與方式探索

来源:https://www.cnblogs.com/vivotech/archive/2022/11/22/16902138.html
-Advertisement-
Play Games

在Redis運維過程中,由於bigkey的存在,會影響業務程式的響應速度,嚴重的還會造成可用性損失,DBA也一直和業務開發方強調bigkey的規避方法以及危害 ...


作者:vivo 互聯網資料庫團隊- Du Ting

在Redis運維過程中,由於Bigkey 的存在,會影響業務程式的響應速度,嚴重的還會造成可用性損失,DBA也一直和業務開發方強調 Bigkey 的規避方法以及危害。

一、背景

在Redis運維過程中,由於Bigkey的存在,會影響業務程式的響應速度,嚴重的還會造成可用性損失,DBA也一直和業務開發方強調 Bigkey 的規避方法以及危害,但是Bigkey一直沒有完全避免。全網Redis集群有2200個以上,實例數量達到4.5萬以上,在當前階段進行一次全網 Bigkey檢查,估計需要以年為時間單位,非常耗時。我們需要新的思路去解決Bigkey問題。

二、Bigkey 介紹

2.1、什麼是 Bigkey

在Redis中,一個字元串類型最大可以到512MB,一個二級數據結構(比如hash、list、set、zset等)可以存儲大約40億個(2^32-1)個元素,但實際上不會達到這麼大的值,一般情況下如果達到下麵的情況,就可以認為它是Bigkey了。

  • 【字元串類型】: 單個string類型的value值超過1MB,就可以認為是Bigkey。
  • 【非字元串類型】:哈希、列表、集合、有序集合等, 它們的元素個數超過2000個,就可以認為是Bigkey。

2.2 Bigkey是怎麼產生的

我們遇到的Bigkey一般都是由於程式設計不當或者對於數據規模預料不清楚造成的,比如以下的情況。

  • 【統計】:遇到一個統計類的key,是記錄某網站的訪問用戶的IP,隨著時間的推移,網站訪問的用戶越來越多,這個key的元素數量也會越來越大,形成Bigkey。
  • 【緩存】: 緩存類key一般是這樣的邏輯,將數據從資料庫查詢出來序列化放到Redis里,如果業務程式從Redis沒有訪問到,就會查詢資料庫並將查詢到的數據追加到Redis緩存中,短時間內會緩存大量的數據到Redis的key中,形成Bigkey。
  • 【隊列】:把Redis當做隊列使用,處理任務,如果消費出現不及時情況,將導致隊列越來越大,形成Bigkey。

這三種情況,都是我們實際運維中遇到的,需要謹慎使用,合理優化。

2.3 Bigkey 的危害

我們在運維中,遇到Bigkey的情況下,會導致一些問題,會觸發監控報警,嚴重的還會影響Redis實例可用性,進而影響業務可用性,在需要水平擴容時候,可能導致水平擴容失敗。

2.3.1記憶體空間不均勻

記憶體空間不均勻會不利於集群對記憶體的統一管理,有數據丟失風險。下圖中的三個節點是同屬於一個集群,它們的key的數量比較接近,但記憶體容量相差比較多,存在Bigkey的實例占用的記憶體多了4G以上了。

圖片

可以使用使用Daas平臺“工具集-操作項管理”,選擇對應的slave實例執行分析,找出具體的Bigkey。

2.3.2 超時阻塞

Redis是單線程工作的,通俗點講就是同一時間只能處理一個Redis的訪問命令,操作Bigkey的命令通常比較耗時,這段時間Redis不能處理其他命令,其他命令只能阻塞等待,這樣會造成客戶端阻塞,導致客戶端訪問超時,更嚴重的會造成master-slave的故障切換。造成阻塞的操作不僅僅是業務程式的訪問,還有key的自動過期的刪除、del刪除命令,對於Bigkey,這些操作也需要謹慎使用。

超時阻塞案例

我們遇到一個這樣超時阻塞的案例,業務方反映程式訪問Redis集群出現超時現象,hkeys訪問Redis的平均響應時間在200毫秒左右,最大響應時間達到了500毫秒以上,如下圖。

圖片

hkeys是獲取所有哈希表中的欄位的命令,分析應該是集群中某些實例存在hash類型的Bigkey,導致hkeys命令執行時間過長,發生了阻塞現象。

1.使用Daas平臺“服務監控-資料庫實例監控”,選擇master節點,選擇Redis響應時間監控指標“redis.instance.latency.max”,如下圖所示,從監控圖中我們可以看到

(1)正常情況下,該實例的響應時間在0.1毫秒左右。

(2)監控指標上面有很多突刺,該實例的響應時間到了70毫秒左右,最大到了100毫秒左右,這種情況就是該實例會有100毫秒都在處理Bigkey的訪問命令,不能處理其他命令。

通過查看監控指標,驗證了我們分析是正確的,是這些監控指標的突刺造成了hkeys命令的響應時間比較大,我們找到了具體的master實例,然後使用master實例的slave去分析下Bigkey情況。

圖片

圖片

2.使用Daas平臺“工具集-操作項管理”,選擇slave實例執行分析,分析結果如下圖,有一個hash類型key有12102218個fields。

圖片

3. 和業務溝通,這個Bigkey是連續存放了30天的業務數據了,建議根據二次hash方式拆分成多個key,也可把30天的數據根據分鐘級別拆分成多個key,把每個key的元素數量控制在5000以內,目前業務正在排期優化中。優化後,監控指標的響應時間的突刺就會消失了。

2.3.3 網路阻塞

Bigkey的value比較大,也意味著每次獲取要產生的網路流量較大,假設一個Bigkey為10MB,客戶端每秒訪問量為100,那麼每秒產生1000MB的流量,對於普通的千兆網卡(按照位元組算是128MB/s)的伺服器來說簡直是滅頂之災。而且我們現在的Redis伺服器是採用單機多實例的方式來部署Redis實例的,也就是說一個Bigkey可能會對同一個伺服器上的其他Redis集群實例造成影響,影響到其他的業務。

2.3.4 遷移困難

我們在運維中經常做的變更操作是水平擴容,就是增加Redis集群的節點數量來達到擴容的目的,這個水平擴容操作就會涉及到key的遷移,把原實例上的key遷移到新擴容的實例上。當要對key進行遷移時,是通過migrate命令來完成的,migrate實際上是通過dump + restore + del三個命令組合成原子命令完成,它在執行的時候會阻塞進行遷移的兩個實例,直到以下任意結果發生才會釋放:遷移成功,遷移失敗,等待超時。如果key的遷移過程中遇到Bigkey,會長時間阻塞進行遷移的兩個實例,可能造成客戶端阻塞,導致客戶端訪問超時;也可能遷移時間太長,造成遷移超時導致遷移失敗,水平擴容失敗。

遷移失敗案例

我們也遇到過一些因為Bigkey擴容遷移失敗的案例,如下圖所示,是一個Redis集群水平擴容的工單,需要進行key的遷移,當工單執行到60%的時候,遷移失敗了。

1. 進入工單找到失敗的實例,使用失敗實例的slave節點,在Daas平臺的“工具集-操作項管理”進行Bigkey分析。

圖片

2. 經過分析找出了hash類型的Bigkey有8421874個fields,正是這個Bigkey導致遷移時間太長,超過了遷移時間限制,導致工單失敗了。

圖片

3.和業務溝通,這些key是記錄用戶訪問系統的某個功能模塊的ip地址的,訪問該功能模塊的所有ip都會記錄到給key裡面,隨著時間的積累,這個key變的越來越大。同樣是採用拆分的方式進行優化,可以考慮按照時間日期維度來拆分,就是一段時間段的訪問ip記錄到一個key中。

4.Bigkey優化後,擴容的工單可以重試,完成集群擴容操作。

三、Bigkey的發現

Bigkey首先需要重源頭治理,防止Bigkey的產生;其次是需要能夠及時的發現,發現後及時處理。分析Bigkey的方法不少,這裡介紹兩種比較常用的方法,也是Daas平臺分析Bigkey使用的兩種方式,分別是Bigkeys命令分析法、RDB文件分析法。

3.1 scan命令分析

Redis4.0及以上版本提供了--Bigkeys命令,可以分析出實例中每種數據結構的top 1的Bigkey,同時給出了每種數據類型的鍵值個數以及平均大小。執行--Bigkeys命令時候需要註意以下幾點:

  • 建議在slave節點執行,因為--Bigkeys也是通過scan完成的,可能會對節點造成阻塞。
  • 建議在節點本機執行,這樣可以減少網路開銷。
  • 如果沒有從節點,可以使用--i參數,例如(--i 0.1 代表100毫秒執行一次)。
  • --Bigkeys只能計算每種數據結構的top1,如果有些數據結構有比較多的Bigkey,是查找不出來的。

Daas平臺集成了基於原生--Bigkeys代碼實現的查詢Bigkey的方式,這個方式的缺點是只能計算每種數據結構的top1,如果有些數據結構有比較多的Bigkey,是查找不出來的。該方式相對比較安全,已經開放出來給業務開發同學使用。

3.2 RDB文件分析

藉助開源的工具,比如rdb-tools,分析Redis實例的RDB文件,找出其中的Bigkey,這種方式需要生成RDB文件,需要註意以下幾點:

  • 建議在slave節點執行,因為生成RDB文件會影響節點性能。
  • 需要生成RDB文件,會影響節點性能,雖然在slave節點執行,但是也是有可能造成主從中斷,進而影響到master節點。

Daas平臺集成了基於RDB文件分析代碼實現的查詢Bigkey的方式,可以根據實際需求自定義填寫N,分析的top N個Bigkey。該方式相對有一定風險,只有DBA有許可權執行分析。

3.3 Bigkey 巡檢

通過巡檢,可以暴露出隱患,提前解決,避免故障的發生,進行全網Bigkey的巡檢,是避免Bigkey故障的比較好的方法。由於全網Redis實例數量非常大,分析的速度比較慢,使用當前的分析方法很難完成。為瞭解決這個問題,存儲研發組分散式資料庫同學計劃開發一個高效的RDB解析工具,然後通過大規模解析RDB文件來分析Bigkey,可以提高分析速度,實現Bigkey的巡檢。

四、 Bigkey處理優化

4.1 Bigkey拆分

優化Bigkey的原則就是string減少字元串長度,list、hash、set、zset等減少元素數量。當我們知道哪些key是Bigkey時,可以把單個key拆分成多個key,比如以下拆分方式可以參考。

  • big list:list1、list2、...listN
  • big hash:可以做二次的hash,例如hash%100
  • 按照日期拆分多個:key20220310、key20220311、key202203212

4.2 Bigkey分析工具優化

我們全網Redis集群有2200以上,實例數量達到4.5萬以上,有的比較大的集群的實例數量達到了1000以上,前面提到的兩種Bigkey分析工具還都是實例維度分析,對於實例數量比較大的集群,進行全集群分析也是比較耗時的,為了提高分析效率,從以下幾個方面進行優化:

  • 可以從集群維度選擇全部slave進行分析。
  • 同一個集群的相同伺服器slave實例串列分析,不同伺服器的slave實例並行分析,最大併發度預設10,同時可以分析10個實例,並且可以自定義輸入執行分析的併發度。
  • 分析出符合Bigkey規定標準的所有key信息:大於1MB的string類型的所有key,如果不存在就列出最大的50個key;hash、list、set、zset等類型元素個數大於2000的所有key,如不存在就給出每種類型最大的50個key。
  • 增加暫停、重新開始、結束功能,暫停分析後可以重新開始。

4.3 水平擴容遷移優化

目前情況,我們有一些Bigkey的發現是被動的,一些是在水平擴容時候發現的,由於Bigkey的存在導致擴容失敗了,嚴重的還觸發了master-slave的故障切換,這個時候可能已經造成業務程式訪問超時,導致了可用性下降。

我們分析了Daas平臺的水平擴容時遷移key的過程及影響參數,內容如下:

(1)【cluster-node-timeout】:控制集群的節點切換參數,master堵塞超過cluster-node-timeout/2這個時間,就會主觀判定該節點下線pfail狀態,如果遷移Bigkey阻塞時間超過cluster-node-timeout/2,就可能會導致master-slave發生切換。

(2)【migrate timeout】:控制遷移io的超時時間,超過這個時間遷移沒有完成,遷移就會中斷。

(3)【遷移重試周期】:遷移的重試周期是由水平擴容的節點數決定的,比如一個集群擴容10個節點,遷移失敗後的重試周期就是10次。

(4)【一個遷移重試周期內的重試次數】:在一個起遷移重試周期內,會有3次重試遷移,每一次的migrate timeout的時間分別是10秒、20秒、30秒,每次重試之間無間隔。

比如一個集群擴容10個節點,遷移時候遇到一個Bigkey,第一次遷移的migrate timeout是10秒,10秒後沒有完成遷移,就會設置migrate timeout為20秒重試,如果再次失敗,會設置migrate timeout為30秒重試,如果還是失敗,程式會遷移其他新9個的節點,但是每次在遷移其他新的節點之前還會分別設置migrate timeout為10秒、20秒、30秒重試遷移那個遷移失敗的Bigkey。這個重試過程,每個重試周期阻塞(10+20+30)秒,會重試10個周期,共阻塞600秒。其實後面的9個重試周期都是無用的,每次重試之間沒有間隔,會連續阻塞了Redis實例。

(5)【遷移失敗日誌】:遷移失敗後,記錄的日誌沒有包括遷移節點、solt、key信息,不能根據日誌立即定位到問題key。

我們對這個遷移過程做了優化,具體如下:

(1)【cluster-node-timeout】:預設是60秒,在遷移之前設置為15分鐘,防止由於遷移Bigkey阻塞導致master-slave故障切換。

(2)【migrate timeout】:為了最大限度減少實例阻塞時間,每次重試的超時時間都是10秒,3次重試之間間隔30秒,這樣最多只會連續阻塞Redis實例10秒。

(3)【重試次數】:遷移失敗後,只重試3次(重試是為了避免網路抖動等原因造成的遷移失敗),每次重試間隔30秒,重試3次後都失敗了,會暫停遷移,日誌記錄下Bigkey,去掉了其他節點遷移的重試。

(4)【優化日誌記錄】:遷移失敗日誌記錄遷移節點、solt、key信息,可以立即定位到問題節點及key。

五、總結

本文通過對Bigkey的分析,重點介紹了在運維中對bigkey問題的處理思路、解決方式。首先是需要從源頭治理,防止Bigkey形成,DBA應該加強對業務開發同學bigkey相關問題的宣導;其次是需要具備及時發現的能力,這個也是我們現在的不足之處。我們後面會從Bigkey巡檢、Bigkey分析工具的這兩個方面,提高Bigkey發現能力。

參考資料:

  1. Redis命令參考
  2. Github:rdb-tools
  3. redis之bigkey(看這一篇就夠)
分享 vivo 互聯網技術乾貨與沙龍活動,推薦最新行業動態與熱門會議。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 需要將系統語言切換為英文,即可完成註冊,後面使用可以用中文 註冊碼: 4C21U-2KK9Q-M8130-4V2QH-CF810 ...
  • 本文主要翻譯自 Arm Cortex-M7 Processor Technical Reference Manual r1p2 其中章節 Memory System / L1 caches / Store Buffer 。 Store Buffer Cache中的數據,在寫入memory或 AXIM ...
  • 有時項目外設比較多,很容易造成串口不夠用的情況。 最近就遇到了,新增加一個GPS模塊串口的,串口現在外部只有原來的調試串口可以用,所以 嘗試將調試口更改為普通串口。 經過網上看大神們的文章和自己摸索,總結如下: V3S 修改調試串口步驟: 第一步修改設備樹: 路徑~/corelinux/v3ssdk ...
  • 1. 前文回顧 在上篇文章 《深入理解 Linux 虛擬記憶體管理》 中,筆者分別從進程用戶態和內核態的角度詳細深入地為大家介紹了 Linux 內核如何對進程虛擬記憶體空間進行佈局以及管理的相關實現。在我們深入理解了虛擬記憶體之後,那麼何不順帶著也探秘一下物理記憶體的管理呢? 所以本文的目的是在深入理解虛擬 ...
  • 分庫分表,是企業裡面比較常見的針對高併發、數據量大的場景下的一種技術優化方案,也是一個非常高頻的面試題。但是,因為很多人其實並沒有非常豐富的分庫分表的經驗,所以能把這個問題回答得比較好的人其實還挺少的。 那麼,本文就來試圖把關於分庫分表的事情,一次性講個清楚。 ...
  • 一、MySQL簡介 ​ MySQL是一種關係型資料庫管理系統,關係資料庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度並提高了靈活性。 二、安裝與下載 1、下載流程 1、訪問官方(www.mysql.com) 2、點擊‘DOWNLOADS’,進入下載界面 3、下拉,找到‘ ...
  • 在今年的第七屆中國開源年會上,StoneDB 團隊在大數據分論壇發表了《HTAP 的下一步?SoTP 初探》主題演講,在本次演講中,我們首次正式對外闡釋了“SoTP 資料庫”的技術理念,本系列是演講實錄+小編補充版,權當拋磚引玉,供大家批評指正。由於內容比較多,本文為第一章節,主要講講我們提 SoT ...
  • 1 構建一個centos7.6.1810的docker鏡像,用於下載MySQL+xtrabackup所需安裝包 7.6.1810的docker鏡像,低版本最小安裝,會儘可能把所需的包拉齊。 Dockerfile文件如下 FROM centos:7.6.1810 CMD yum install -y ...
一周排行
    -Advertisement-
    Play Games
  • 最近做項目過程中,使用到了海康相機,官方只提供了C/C++的SDK,沒有搜尋到一個合適的封裝了的C#庫,故自己動手,簡單的封裝了一下,方便大家也方便自己使用和二次開發 ...
  • 前言 MediatR 是 .NET 下的一個實現消息傳遞的庫,輕量級、簡潔高效,用於實現進程內的消息傳遞機制。它基於中介者設計模式,支持請求/響應、命令、查詢、通知和事件等多種消息傳遞模式。通過泛型支持,MediatR 可以智能地調度不同類型的消息,非常適合用於領域事件處理。 在本文中,將通過一個簡 ...
  • 前言 今天給大家推薦一個超實用的開源項目《.NET 7 + Vue 許可權管理系統 小白快速上手》,DncZeus的願景就是做一個.NET 領域小白也能上手的簡易、通用的後臺許可權管理模板系統基礎框架。 不管你是技術小白還是技術大佬或者是不懂前端Vue 的新手,這個項目可以快速上手讓我們從0到1,搭建自 ...
  • 第1章:WPF概述 本章目標 瞭解Windows圖形演化 瞭解WPF高級API 瞭解解析度無關性概念 瞭解WPF體繫結構 瞭解WPF 4.5 WPF概述 ​ 歡迎使用 Windows Presentation Foundation (WPF) 桌面指南,這是一個與解析度無關的 UI 框架,使用基於矢 ...
  • 在日常開發中,並不是所有的功能都是用戶可見的,還在一些背後默默支持的程式,這些程式通常以服務的形式出現,統稱為輔助角色服務。今天以一個簡單的小例子,簡述基於.NET開發輔助角色服務的相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 第3章:佈局 本章目標 理解佈局的原則 理解佈局的過程 理解佈局的容器 掌握各類佈局容器的運用 理解 WPF 中的佈局 WPF 佈局原則 ​ WPF 視窗只能包含單個元素。為在WPF 視窗中放置多個元素並創建更貼近實用的用戶男面,需要在視窗上放置一個容器,然後在這個容器中添加其他元素。造成這一限制的 ...
  • 前言 在平時項目開發中,定時任務調度是一項重要的功能,廣泛應用於後臺作業、計劃任務和自動化腳本等模塊。 FreeScheduler 是一款輕量級且功能強大的定時任務調度庫,它支持臨時的延時任務和重覆迴圈任務(可持久化),能夠按秒、每天/每周/每月固定時間或自定義間隔執行(CRON 表達式)。 此外 ...
  • 目錄Blazor 組件基礎路由導航參數組件參數路由參數生命周期事件狀態更改組件事件 Blazor 組件 基礎 新建一個項目命名為 MyComponents ,項目模板的交互類型選 Auto ,其它保持預設選項: 客戶端組件 (Auto/WebAssembly): 最終解決方案裡面會有兩個項目:伺服器 ...
  • 先看一下效果吧: isChecked = false 的時候的效果 isChecked = true 的時候的效果 然後我們來實現一下這個效果吧 第一步:創建一個空的wpf項目; 第二步:在項目裡面添加一個checkbox <Grid> <CheckBox HorizontalAlignment=" ...
  • 在編寫上位機軟體時,需要經常處理命令拼接與其他設備進行通信,通常對不同的命令封裝成不同的方法,擴展稍許麻煩。 本次擬以特性方式實現,以兼顧維護性與擴展性。 思想: 一種命令對應一個類,其類中的各個屬性對應各個命令段,通過特性的方式,實現其在這包數據命令中的位置、大端或小端及其轉換為對應的目標類型; ...