Redis是典型的單執行緒架構,所有的讀寫操作都是在一條主執行緒中完成的,當Redis用于高并發場景時,這條執行緒就變成了它的生命線,如果出現阻塞,哪怕是很短時間,對于我們的應用來說都是噩夢,導致阻塞問題的場景大致分為內在原因和外在原因:
·內在原因包括:不合理地使用API或資料結構、CPU飽和、持久化阻塞等,
·外在原因包括:CPU競爭、記憶體交換、網路問題等
- 發現阻塞:當Redis阻塞時,線上應用服務應該最先感知到,這時應用方會收到大量Redis超時例外,比如Jedis客戶端會拋出JedisConnectionException例外,完備的短信監控告警
- 內在原因:
- API或資料結構使用不合理:通常Redis執行命令速度非常快,但也存在例外,如對一個包含上萬個元素的hash結構執行hgetall操作,由于資料量比較大且命令演算法復雜度是O(n),這條命令執行速度必然很慢,這個問題就是典型的不合理使用API和資料結構,對于高并發的場景我們應該盡量避免在大物件上執行演算法復雜度超過O(n)的命令
- 發現慢查詢:執行slowlog get{n}命令可以獲取最近的n條慢查詢命令,默認對于執行超過10毫秒的命令都會記錄到一個定長佇列中,
- 如何發現大物件:redis-cli-h{ip}-p{port}bigkeys,內部原理采用分段進行scan操作,把歷史掃描過的最大物件統計出來便于分析優化
- CPU飽和
單執行緒的Redis處理命令時只能使用一個CPU,而CPU飽和是指Redis把單核CPU使用率跑到接近100%,使用top命令很容易識別出對應Redis行程的CPU使用率,CPU飽和是非常危險的,將導致Redis無法處理更多的命令,嚴重影響吞吐量和應用方的穩定性,
使用統計命令redis-cli-h{ip}-p{port}--stat獲取當前Redis使用情況,該命令每秒輸出一行統計資訊

以上輸出是一個接近飽和的Redis實體的統計資訊,它每秒平均處理6萬+的請求,對于這種情況,垂直層面的命令優化很難達到效果,這時就需要做集群化水平擴展來分攤OPS壓力,如果只有幾百或幾千OPS的Redis實體就接近CPU飽和是很不正常的,有可能使用了高演算法復雜度的命令,還有一種情況是過度的記憶體優化,這種情況有些隱蔽,需要我們根據info commandstats統計資訊分析出命令不合理開銷時間,例如下面的耗時統計:

查看這個統計可以發現一個問題,hset命令演算法復雜度只有O(1)但平均耗時卻達到135微秒,顯然不合理,正常情況耗時應該在10微秒以下,這是因為上面的Redis實體為了追求低記憶體使用量,過度放寬ziplist使用條件(修改了hash-max-ziplist-entries和hash-max-ziplist-value配置),行程內的hash物件平均存盤著上萬個元素,而針對ziplist的操作演算法復雜度在O(n)到O(n2)之間,雖然采用ziplist編碼后hash結構記憶體占用會變小,但是操作變得更慢且更消耗CPU,ziplist壓縮編碼是Redis用來平衡空間和效率的優化手段,不可過度使用,
- 持久化阻塞
- fork阻塞:fork操作發生在RDB和AOF重寫時,Redis主執行緒呼叫fork操作產生共享記憶體的子行程,由子行程完成持久化檔案重寫作業,如果fork操作本身耗時過長,必然會導致主執行緒的阻塞,可以執行info stats命令獲取到latest_fork_usec指標,表示Redis最近一次fork操作耗時,如果耗時很大,比如超過1秒,則需要做出優化調整,如避免使用過大的記憶體實體和規避fork緩慢的作業系統等,
- AOF刷盤阻塞:當我們開啟AOF持久化功能時,檔案刷盤的方式一般采用每秒一次,后臺執行緒每秒對AOF檔案做fsync操作,當硬碟壓力過大時,fsync操作需要等待,直到寫入完成,如果主執行緒發現距離上一次的fsync成功超過2秒,為了資料安全性它會阻塞直到后臺執行緒執行fsync操作完成, #運維提示:硬碟壓力可能是Redis行程引起的,也可能是其他行程引起的,可以使用iotop查看具體是哪個行程消耗過多的硬碟資源,
- HugePage寫操作阻塞:子行程在執行重寫期間利用Linux寫時復制技術降低記憶體開銷,因此只有寫操作時Redis才復制要修改的記憶體頁,對于開啟Transparent HugePages的作業系統,每次寫命令引起的復制記憶體頁單位由4K變為2MB,放大了512倍,會拖慢寫操作的執行時間,導致大量寫操作慢查詢,
- 外在原因
- CPU競爭:
-
行程競爭
:Redis是典型的CPU密集型應用,不建議和其他多核CPU密集型服務部署在一起,當其他行程過度消耗CPU時,將嚴重影響Redis吞吐量,可以通過top、sar等命令定位到CPU消耗的時間點和具體行程 -
系結CPU
:部署Redis時為了充分利用多核CPU,通常一臺機器部署多個實體,常見的一種優化是把Redis行程系結到CPU上,用于降低CPU頻繁背景關系切換的開銷
2.記憶體交換:
記憶體交換(swap)對于Redis來說是非常致命的,Redis保證高性能的一個重要前提是所有的資料在記憶體中,如果作業系統把Redis使用的部分記憶體換出到硬碟,由于記憶體與硬碟讀寫速度差幾個數量級,會導致發生交換后的Redis性能急劇下降,
1)查詢Redis行程號:
# redis-cli -p 6383 info server | grep process_id process_id:4476
2)根據行程號查詢記憶體交換資訊:
# cat /proc/4476/smaps | grep Swap Swap: 0 kB
Swap: 0 kB
Swap: 4 kB
如果交換量都是0KB或者個別的是4KB,則是正常現象,說明Redis行程記憶體沒有被交換,預防記憶體交換的方法有:
·保證機器充足的可用記憶體,
·確保所有Redis實體設定最大可用記憶體(maxmemory),防止極端情況下Redis記憶體不可控的增長,
·降低系統使用swap優先級,如echo10>/proc/sys/vm/swappiness
3.網路問題
- 連接拒絕:網路閃斷,一般發生在網路割接或者帶寬耗盡的情況,對于網路閃斷的識別比較困難,常見的做法可以通過sar-n DEV查看本機歷史流量是否正常
-
Redis連接拒絕
Redis通過maxclients引數控制客戶端最大連接數,默認10000,當Redis連接數大于maxclients時會拒絕新的連接進入,info stats的rejected_connections統計指標記錄所有被拒絕連接的數量 - 連接溢位:行程使用的資源做限制
- 連接溢位:backlog佇列溢位、系統對于特定埠的TCP連接使用backlog佇列保存,Redis默認的長度為511,通過tcp-backlog引數設定,如果Redis用于高并發場景為了防止緩慢連接占用,可適當增大這個設定,但必須大于作業系統允許值才能生效,
- 網路延遲:網路帶寬不穩定
總結:
1)客戶端最先感知阻塞等Redis超時行為,加入日志監控報警工具可快速定位阻塞問題,同時需要對Redis行程和機器做全面監控, 2)阻塞的內在原因:確認主執行緒是否存在阻塞,檢查慢查詢等資訊,發現不合理使用API或資料結構的情況,如keys、sort、hgetall等,關注CPU使用率防止單核跑滿,當硬碟IO資源緊張時,AOF追加也會阻塞主執行緒, 3)阻塞的外在原因:從CPU競爭、記憶體交換、網路問題等方面入手排查是否因為系統層面問題引起阻塞,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/500871.html
標籤:其它
上一篇:Redis常用操作
