天天看點

Redis大key問題全方位解析:從發現大key到優化方案一網打盡

作者:一個即将退役的碼農

前言

前幾天女神節,小黑奢侈一次,準時下班回到家,陪媳婦吃着面條,看着愛情轉移,好生惬意!

忽然,手機叮咣叮咣響個,釘釘報警不斷,小黑無奈的打開手機,看了下是某個服務調用Redis異常了。

放下飯碗,小黑打開電腦連上vpn,一頓操作排查,最終定位到是Redis有大key問題。

心裡想着老闆的微薄工資,尋思一時半會兒也解決不了,明天到公司再搞,先繼續看電視吧 哈哈哈。

在redis中什麼是大key呢?多大才算大呢?

對于初學者來說,肯定在想redis的key能有多大呀?

這裡就有個誤區了,所謂的大key問題是某個key的value比較大,是以本質上是大value問題。

這樣就對上了,key往往是程式可以自行設定的,value往往不受程式控制,是以可能導緻value很大。

設想一種場景:

在抖音直播中,某個頭部主播目前有很多正在觀看的使用者,假如有這樣的資料結構:

  • 直播間和觀看使用者之間的映射關系采用redis存儲
  • redis的key是直播間ID,長度可控且很小
  • redis的value是個list,list包含了直播間裡面所有使用者
  • 使用者可能很多,就導緻list長度不可控

這下明白啥是大key問題了吧!

Redis大key問題全方位解析:從發現大key到優化方案一網打盡

通常以Key的大小和Key中成員的數量來綜合判定,例如:

  • Key本身的資料量過大:一個String類型的Key,它的值為5 MB。
  • Key中的成員數過多:一個ZSET類型的Key,它的成員數量為10,000個。
  • Key中成員的資料量過大:一個Hash類型的Key,它的成員數量雖然隻有1,000個但這些成員的Value(值)總大小為100 MB。
key類型 field數量 耗時
Hash 100萬 1000ms
List 100萬 1000ms
Set 100萬 1000ms
ZSet 100萬 1000ms

大key會引發什麼問題呢?

我們都知道,redis的一個典型特征就是:核心工作線程是單線程。

單線程中請求任務的處理是串行的,前面完不成,後面處理不了,同時也導緻分布式架構中記憶體資料和CPU的不平衡。

  • 用戶端執行指令的時長變慢。
  • Redis記憶體達到maxmemory參數定義的上限引發操作阻塞或重要的Key被逐出,甚至引發記憶體溢出(Out Of Memory)。
  • 叢集架構下,某個資料分片的記憶體使用率遠超其他資料分片,無法使資料分片的記憶體資源達到均衡。
  • 對大Key執行讀請求,會使Redis執行個體的帶寬使用率被占滿,導緻自身服務變慢,同時易波及相關的服務。
  • 對大Key執行删除操作,易造成主庫較長時間的阻塞,進而可能引發同步中斷或主從切換。

這樣看來大key的影響還是很明顯的,最典型的就是阻塞線程,并發量下降,導緻用戶端逾時,服務端業務成功率下降。

大Key産生的原因

未正确使用Redis、業務規劃不足、無效資料的堆積、通路量突增等都會産生大Key,如:

  • 在不适用的場景下使用Redis,易造成Key的value過大,如使用String類型的Key存放大體積二進制檔案型資料;
  • 業務上線前規劃設計不足,沒有對Key中的成員進行合理的拆分,造成個别Key中的成員數量過多;
  • 使用LIST類型Key的業務消費側發生代碼故障,造成對應Key的成員隻增不減。
  • 存儲大量資料:Redis 具有非常高效的存儲和讀取性能,是以在某些情況下,開發人員可能會将大量資料存儲在單個 key 中,例如将整個資料庫或大型資料結構存儲在 Redis 中。
  • 誤用資料結構:開發人員可能會錯誤地選擇了不适合存儲大量資料的資料結構。例如,使用 Redis 清單來存儲大量元素,而不是使用 Redis 集合或有序集合,這可能導緻單個 key 變得非常大。
  • 資料積累:在實際使用 Redis 中,某些 key 可能會随着時間的推移逐漸增長,并變得越來越大,這可能會導緻單個 key 變得非常大。

如何快速找出大Key呢?

在 Redis 中,可以通過以下幾種方式來找到大 key:

1.使用 Redis 自帶的指令:Redis 提供了一些指令來幫助查找大 key,例如使用 redis-cli 指令行工具執行 redis-cli --bigkeys 指令,該指令可以列出 Redis 中大小最大的 key。這個指令隻在 Redis 4.0 或更高版本中可用。、

Redis大key問題全方位解析:從發現大key到優化方案一網打盡

2.通過Redis内置指令對目标Key進行分析,對不同資料類型的目标Key,分别通過如下風險較低的指令進行分析,來判斷目标Key是 否符合大Key判定标準。

  • STRING類型:執行STRLEN指令,傳回對應Key的value的位元組數。
  • LIST類型:執行LLEN指令,傳回對應Key的清單長度。
  • HASH類型:執行HLEN指令,傳回對應Key的成員數量。
  • SET類型:執行SCARD指令,傳回對應Key的成員數量。
  • ZSET類型:執行ZCARD指令,傳回對應Key的成員數量。
  • STREAM類型:執行XLEN指令,傳回對應Key的成員數量。

3.使用第三方工具:有許多第三方工具可以幫助查找 Redis 中的大 key,例如使用 RedisDesktopManager 工具中的“大 key”功能,或使用 KeyDBA 工具等。這些工具可以掃描整個 Redis 資料庫,并顯示大小最大的 key,進而幫助您确定哪些 key 是大 key。

4.手動周遊 key:可以通過編寫腳本或使用 Redis 的用戶端庫來周遊 Redis 資料庫中的所有 key,并檢查它們的大小。例如,在 Python 中使用 Redis 用戶端庫 redis-py,可以使用 scan_iter() 方法周遊 Redis 資料庫中的所有 key,并使用 memory_usage() 方法計算每個 key 的大小,進而确定哪些 key 是大 key。

如果你是用的aliyun的雲産品的話,你還可以用下面的方式進行檢視:

5.實時Top Key統計:可實時展示執行個體中的大Key和熱Key資訊,同時支援檢視4天内大Key和熱Key的曆史資訊。該功能可幫助您掌握Key在記憶體中的占用、Key的通路頻次等資訊,溯源分析問題,為您的優化操作提供資料支援。

Redis大key問題全方位解析:從發現大key到優化方案一網打盡

6.實時Top Key統計:對Redis的RDB備份檔案進行定制化的分析,幫助您發現執行個體中的大Key,掌握Key在記憶體中的占用和分布、Key過期時間等資訊,為您的優化操作提供資料支援,幫助您避免因Key傾斜引發的記憶體不足、性能下降等問題。

Redis大key問題全方位解析:從發現大key到優化方案一網打盡
Redis大key問題全方位解析:從發現大key到優化方案一網打盡

如何優化大Key呢?

在 Redis 中,大 key 可以對性能和可用性産生負面影響。是以,需要針對大 key 問題采取一些措施來優化 Redis 的性能和可用性,以下是幾種常見的解決方法:

  1. 分割大 key:将大 key 拆分成多個小 key 來存儲資料。例如,如果一個大型哈希表存儲了大量的資料,可以将它拆分成多個小的哈希表,每個哈希表存儲一部分資料。這樣可以降低每個 key 的大小,并使 Redis 更加穩定和高效。
  2. 使用适當的資料結構:選擇适當的 Redis 資料結構,以減少單個 key 的大小。例如,如果要存儲大量元素,應該使用 Redis 集合或有序集合,而不是使用清單。
  3. 定期清理資料:定期清理 Redis 中的過期資料和不必要的資料,以避免大 key 的大小增長。可以使用 Redis 内置的過期機制或手動清理不必要的資料。
  4. 壓縮資料:使用 Redis 的資料壓縮功能,将大 key 中的資料進行壓縮,可以減少每個 key 的大小,進而提高 Redis 的性能和可用性。
  5. 按需加載資料:不要在一次性将整個大 key 加載到記憶體中,而是按需加載資料,可以降低 Redis 的記憶體使用率,進而提高性能。

綜上所述,解決大 key 問題的方法包括分割大 key、使用适當的資料結構、定期清理資料、壓縮資料以及按需加載資料等。在實際應用中,需要根據實際情況選擇合适的方法來優化 Redis 的性能和可用性。

小結

Redis的大key問題,無論在面試還是工作中都很常見,好好了解一波,非常值得。

祝各位老鐵,深夜無報警,線上無bug!

繼續閱讀