Redis阻塞整理筆記

Redis是典型的單線程架構,全部的讀寫操做都是在一條主線程中完成的。當Redis用於高併發場景時,這條線程就變成了它的生命線。若是出現阻塞,哪怕是很短期,對於應用來講都是噩夢。redis

致使阻塞問題的緣由:算法

  • 內在緣由:不合理地使用API或數據結構、CPU飽和、持久化阻塞等
  • 外在緣由:CPU競爭、內存交換、網絡問題等

 

 

 

 

1、發現阻塞sql

  • 應用方加入異常監控,如日誌系統,好比Java語言中的logback或log4j
  • Redis監控系統,如CacheCloud

 

2、內在緣由安全

2.1 API或數據結構使用不合理服務器

一般Redis執行命令速度很是快,可是,若是對一個包含上萬個元素的hash結構執行hgetall操做,因爲數據量比較大且命令算法複雜度是O(n),這條命令執行速度必然很慢。網絡

對於高併發的場景應該儘可能避免在大對象上執行算法複雜度超過O(n)的命令。數據結構

(1)如何發現慢查詢架構

Redis原生提供慢查詢統計功能,執行slowlog get{n}命令能夠獲取最近的n條慢查詢命令,默認對於執行超過10毫秒的命令都會記錄到一個定長隊列中,線上實例建議設置爲1毫秒便於及時發現毫秒級以上的命令。併發

(2)發現慢查詢後如何調整分佈式

  • 修改成低算法複雜度的命令
  • 調整大對象:縮減大對象數據或把大對象拆分爲多個小對象,防止一次命令操做過多的數據。大對象拆分過程須要視具體的業務決定,如用戶好友集合存儲在Redis中,有些熱點用戶會關注大量好友,這時能夠按時間或其餘維度拆分到多個集合中。

 

(3)如何發現大對象

Redis自己提供發現大對象的工具。具體命令:

redis-cli -h {ip}  -p {port} --bigkeys

 

內部原理採用分段進行scan操做,把歷史掃描過的最大對象統計出來便於分析優化。

2.2 CPU飽和

單線程的Redis處理命令時只能使用一個CPU。而CPU飽和是指Redis把單核CPU使用率跑到接近100%。使用top命令很容易識別出對應Redis進程的CPU使用率。CPU飽和是很是危險的,將致使Redis沒法處理更多的命令,嚴重影響吞吐量和應用方的穩定性。對於這種狀況,首先判斷當前Redis的併發量是否達到極限,建議使用統計命令redis-cli -h {ip} -p {port} --stat獲取當前Redis使用狀況

2.3 持久化阻塞

對於開啓了持久化功能的Redis節點,須要排查是不是持久化致使的阻塞。

  • fork阻塞:fork操做發生在RDB和AOF重寫時,Redis主線程調用fork操做產生共享內存的子進程,由子進程完成持久化文件重寫工做。若是fork操做自己耗時過長,必然會致使主線程的阻塞。
  • AOF刷盤阻塞:當咱們開啓AOF持久化功能時,文件刷盤的方式通常採用每秒一次,後臺線程每秒對AOF文件作fsync操做。當硬盤壓力過大時,fsync操做須要等待,直到寫入完成。若是主線程發現距離上一次的fsync成功超過2秒,爲了數據安全性它會阻塞直到後臺線程執行fsync操做完成。這種阻塞行爲主要是硬盤壓力引發。
  • HugePage寫操做阻塞:子進程在執行重寫期間利用Linux寫時複製技術下降內存開銷,所以只有寫操做時Redis才複製要修改的內存頁。對於開啓Transparent HugePages的操做系統,每次寫命令引發的複製內存頁單位由4K變爲2MB,放大了512倍,會拖慢寫操做的執行時間,致使大量寫操做慢查詢。

3、外在緣由

3.1 CPU競爭

  • 進程競爭:Redis是典型的CPU密集型應用,不建議和其餘多核CPU密集型服務部署在一塊兒。當其餘進程過分消耗CPU時,將嚴重影響Redis吞吐量。能夠經過top、sar等命令定位到CPU消耗的時間點和具體進程,這個問題比較容易發現,須要調整服務之間部署結構。
  • 綁定CPU:部署Redis時爲了充分利用多核CPU,一般一臺機器部署多個實例。常見的一種優化是把Redis進程綁定到CPU上,用於下降CPU頻繁上下文切換的開銷。這個優化技巧正常狀況下沒有問題,可是存在例外狀況,當Redis父進程建立子進程進行RDB/AOF重寫時,若是作了CPU綁定,會與父進程共享使用一個CPU。子進程重寫時對單核CPU使用率一般在90%以上,父進程與子進程將產生激烈CPU競爭,極大影響Redis穩定性。所以對於開啓了持久化或參與複製的主節點不建議綁定CPU。

 

3.2 內存交換

內存交換(swap)對於Redis來講是很是致命的,Redis保證高性能的一個重要前提是全部的數據在內存中。若是操做系統把Redis使用的部份內存換出到硬盤,因爲內存與硬盤讀寫速度差幾個數量級,會致使發生交換後的Redis性能急劇降低。

預防內存交換:

  • 保證機器充足的可用內存。
  • 確保全部Redis實例設置最大可用內存(maxmemory),防止極端狀況下Redis內存不可控的增加。
  • 下降系統使用swap優先級。

3.3 網絡問題

(1)鏈接拒絕

  • 網絡閃斷(網絡割接或者帶寬耗盡)
  • Redis鏈接拒絕(超過客戶端最大鏈接數)
  • 鏈接溢出(進程限制或backlog隊列溢出)

(2)網絡延遲

網絡延遲取決於客戶端到Redis服務器之間的網絡環境。主要包括它們之間的物理拓撲和帶寬佔用狀況。常見的物理拓撲按網絡延遲由快到慢可分爲:同物理機>同機架>跨機架>同機房>同城機房>異地機房。但它們容災性正好相反,同物理機容災性最低而異地機房容災性最高。

網絡延遲問題常常出如今跨機房的部署結構上,對於機房之間延遲比較嚴重的場景須要調整拓撲結構,如把客戶端和Redis部署在同機房或同城機房等。

帶寬瓶頸一般出如今如下幾個方面:

  • 機器網卡帶寬。
  • 機架交換機帶寬。
  • 機房之間專線帶寬。

(3)網卡軟中斷

網卡軟中斷是指因爲單個網卡隊列只能使用一個CPU,高併發下網卡數據交互都集中在同一個CPU,致使沒法充分利用多核CPU的狀況。網卡軟中斷瓶頸通常出如今網絡高流量吞吐的場景。

歡迎工做一到五年的Java工程師朋友們加入Java架構開發: 855835163 羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!

相關文章
相關標籤/搜索