Redis 通常是我們業務系統中一個重要的組件,比如:緩存、賬號登錄信息、排行榜等。
一旦 Redis 請求延遲增加,可能就會導致業務系統“雪崩”。
我在單身紅娘婚戀類型互聯網公司工作,在雙十一推出下單就送女朋友的活動。
誰曾想,凌晨 12 點之後,用户量暴增,出現了一個技術故障,用户無法下單,當時老大火冒三丈!
經過查找發現Redis。
獲取不到連接資源,並且集羣中的單台 Redis 連接量很高。
大量的流量沒了 Redis 的緩存響應,直接打到了 MySQL,最後數據庫也宕機了……
於是各種更改最大連接數、連接等待數,雖然報錯信息頻率有所緩解,但還是持續報錯。
後來經過線下測試,發現存放Redis字符數據很大,平均 1s 返回數據。
可以發現,一旦 Redis 延遲過高,會引發各種問題。
Redis 性能出問題了麼?
最大延遲是客户端發出命令到客户端收到命令的響應的時間,正常情況下 Redis 處理的時間極短,在微秒級別。
當 Redis 出現性能波動的時候,比如達到幾秒到十幾秒,這個很明顯我們可以認定 Redis 性能變慢了。
有的硬件配置比較高,當延遲 0.6ms,我們可能就認定變慢了。硬件比較差的可能 3 ms 我們才認為出現問題。
那我們該如何定義 Redis 真的變慢了呢?
所以,我們需要對當前環境的 Redis 基線性能做測量,也就是在一個系統在低壓力、無干擾情況下的基本性能。
當你發現 Redis 運行時時的延遲是基線性能的 2 倍以上,就可以判定 Redis 性能變慢了。
延遲基線測量
redis-cli 命令提供了–intrinsic-latency 選項,用來監測和統計測試期間內的最大延遲(以毫秒為單位),這個延遲可以作為 Redis 的基線性能。
redis-cli --latency -h `host` -p `port`
比如執行如下指令:
redis-cli --intrinsic-latency 100
Max latency so far: 4 microseconds.
Max latency so far: 18 microseconds.
Max latency so far: 41 microseconds.
Max latency so far: 57 microseconds.
Max latency so far: 78 microseconds.
Max latency so far: 170 microseconds.
Max latency so far: 342 microseconds.
Max latency so far: 3079 microseconds.
45026981 total runs (avg latency: 2.2209 microseconds / 2220.89 nanoseconds per run).
Worst run took 1386x longer than the average latency.
注意:參數
100是測試將執行的秒數。我們運行測試的時間越長,我們就越有可能發現延遲峯值。通常運行 100 秒通常是合適的,足以發現延遲問題了,當然我們可以選擇不同時間運行幾次,避免誤差。
運行的最大延遲是 3079 微秒,所以基線性能是 3079 (3 毫秒)微秒。
需要注意的是,我們要在 Redis 的服務端運行,而不是客户端。這樣,可以避免網絡對基線性能的影響。
可以通過 -h host -p port 來連接服務端,如果想監測網絡對 Redis 的性能影響,可以使用 Iperf 測量客户端到服務端的網絡延遲。
如果網絡延遲幾百毫秒,説明網絡可能有其他大流量的程序在運行導致網絡擁塞,需要找運維協調網絡的流量分配。
慢指令監控
如何判斷是否是慢指令呢?
看操作複雜度是否是O(N)。官方文檔對每個命令的複雜度都有介紹,儘可能使用O(1) 和 O(log N)命令。
涉及到集合操作的複雜度一般為O(N),比如集合全量查詢HGETALL、SMEMBERS,以及集合的聚合操作:SORT、LREM、 SUNION等。
有監控數據可以觀測呢?代碼不是我寫的,不知道有沒有人用了慢指令。
有兩種方式可以排查到:
- 使用 Redis 慢日誌功能查出慢命令;
- latency-monitor(延遲監控)工具。
此外,可以使用自己(top、htop、prstat 等)快速檢查 Redis 主進程的 CPU 消耗。如果 CPU 使用率很高而流量不高,通常表明使用了慢速命令。
慢日誌功能
Redis 中的 slowlog 命令可以讓我們快速定位到那些超出指定執行時間的慢命令,默認情況下命令若是執行時間超過 10ms 就會被記錄到日誌。
slowlog 只會記錄其命令執行的時間,不包含 io 往返操作,也不記錄單由網絡延遲引起的響應慢。
我們可以根據基線性能來自定義慢命令的標準(配置成基線性能最大延遲的 2 倍),調整觸發記錄慢命令的閾值。
可以在 redis-cli 中輸入以下命令配置記錄 6 毫秒以上的指令:
redis-cli CONFIG SET slowlog-log-slower-than 6000
也可以在 Redis.config 配置文件中設置,以微秒為單位。
想要查看所有執行時間比較慢的命令,可以通過使用 Redis-cli 工具,輸入 slowlog get 命令查看,返回結果的第三個字段以微秒位單位顯示命令的執行時間。
假如只需要查看最後 2 個慢命令,輸入 slowlog get 2 即可。
示例:獲取最近2個慢查詢命令
127.0.0.1:6381> SLOWLOG get 2
1) 1) (integer) 6
2) (integer) 1458734263
3) (integer) 74372
4) 1) "hgetall"
2) "max.dsp.blacklist"
2) 1) (integer) 5
2) (integer) 1458734258
3) (integer) 5411075
4) 1) "keys"
2) "max.dsp.blacklist"
以第一個 HGET 命令為例分析,每個 slowlog 實體共 4 個字段:
- 字段 1:1 個整數,表示這個 slowlog 出現的序號,server 啓動後遞增,當前為 6。
- 字段 2:表示查詢執行時的 Unix 時間戳。
- 字段 3:表示查詢執行微秒數,當前是 74372 微秒,約 74ms。
- 字段 4: 表示查詢的命令和參數,如果參數很多或很大,只會顯示部分參數個數。當前命令是
hgetall max.dsp.blacklist。
Latency Monitoring
Redis 在 2.8.13 版本引入了 Latency Monitoring 功能,用於以秒為粒度監控各種事件的發生頻率。
啓用延遲監視器的第一步是設置延遲閾值(單位毫秒)。只有超過該閾值的時間才會被記錄,比如我們根據基線性能(3ms)的 3 倍設置閾值為 9 ms。
可以用 redis-cli 設置也可以在 Redis.config 中設置;
CONFIG SET latency-monitor-threshold 9
工具記錄的相關事件的詳情可查看官方文檔:https://redis.io/topics/latency-monitor
如獲取最近的 latency
127.0.0.1:6379> debug sleep 2
OK
(2.00s)
127.0.0.1:6379> latency latest
1) 1) "command"
2) (integer) 1645330616
3) (integer) 2003
4) (integer) 2003
- 事件的名稱;
- 事件發生的最新延遲的 Unix 時間戳;
- 毫秒為單位的時間延遲;
- 該事件的最大延遲。