Redis慢查詢的具體使用
什么是Redis慢查詢?
redis的"慢查詢"與redis定義慢查詢的時間閾值有關(guān),Redis提供了slowlog-log-slower-than和slowlog-max-len兩個配置,slowlog-log-slower-than指當redis命令的執(zhí)行時間超過該值時,redis會將其記錄在redis的慢查詢?nèi)罩局?,slowlog-max-len表示記錄的條數(shù)(超過時會只存儲最新的slowlog-max-len條),slowlog-log-slower-than的默認值為10000us,也就是一般來說,redis命令執(zhí)行時間超過10ms時,我們認為產(chǎn)生了慢查詢,redis慢查詢?nèi)罩居涗浀氖菆?zhí)行時間,沒有慢查詢,并不表示客戶端沒有超時問題,有可能網(wǎng)絡傳輸有延遲,也有可能排隊的命令比較多,導致redis查詢也很慢。
產(chǎn)生慢查詢有哪些原因?
在業(yè)務使用過程中,我們發(fā)現(xiàn)redis使用上出現(xiàn)慢查詢的原因有主要以下幾種:
- 使用復雜度過高的命令
- 大key問題
- 集中過期
如何解決慢查詢問題?
針對上述的原因,下面逐個給出導致慢查詢的原因細節(jié),并提出對應解決redis慢查詢的有效方法。
使用復雜度過高的命令
負責的命令一般指O(N)以上的命令,比如sort、sunion、zunionstore聚合類的命令,或是O(N)類的命令,但是N的值由于業(yè)務原因特別大。
對于O(N)以上的命令,redis在操作內(nèi)存數(shù)據(jù)時,耗時過高,會耗費更多的cpu資源,導致查詢變慢。對于O(N)類的命令,由于N的值特別大Redis 一次需要返回給客戶端的數(shù)據(jù)過多,更多時間花費在數(shù)據(jù)協(xié)議的組裝和網(wǎng)絡傳輸過程中。
除此之外,我們都知道,Redis 是單線程處理客戶端請求的,如果你經(jīng)常使用以上命令,那么當 Redis 處理客戶端請求時,一旦前面某個命令發(fā)生耗時,就會導致后面的請求發(fā)生排隊,對于客戶端來說,響應延遲也會長。
針對此類原因,我們一般有以下兩個原則:
- 盡量不使用O(N)以上復雜度的命令,某些數(shù)據(jù)排序或聚合操作,可以放在客戶端處理。
- 執(zhí)行O(N)命令時,保證 N 盡量的?。ㄍ扑] N <= 300 經(jīng)驗值),每次獲取盡量少的數(shù)據(jù),讓 Redis 可以及時處理返回。
大key問題
所謂大key問題其實并不是值key過大,實則值key對應的value的值過大,此類問題在SET / DEL這類命令中也常出現(xiàn)慢查詢。
首先我們要了解下redis寫入與刪除數(shù)據(jù)做了什么:
- 寫入數(shù)據(jù):為該數(shù)據(jù)分配內(nèi)存。
- 刪除數(shù)據(jù):釋放該數(shù)據(jù)對應的內(nèi)存空間。
很明顯,當數(shù)據(jù)值比較大時,redis分配數(shù)據(jù)內(nèi)存或釋放空間內(nèi)存都會比較耗時,針對大key問題,有以下建議:
- 盡量避免寫入大key(不要寫入無關(guān)的數(shù)據(jù),數(shù)據(jù)實在過大可以進行拆分,通過多key存儲)
- 如果你使用的 Redis 是 4.0 以上版本,用 UNLINK 命令替代 DEL,此命令可以把釋放 key 內(nèi)存的操作,放到后臺線程中去執(zhí)行,從而降低對 Redis 的影響
- 如果你使用的 Redis 是 6.0 以上版本,可以開啟 lazy-free 機制(lazyfree-lazy-user-del = yes),在執(zhí)行 DEL 命令時,釋放內(nèi)存也會放到后臺線程中執(zhí)行。
順邊提下檢測大key的一個命令:
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01
輸出結(jié)果會展示每種數(shù)據(jù)類型所占用的最大內(nèi)存 / 擁有最多元素的 key 是哪一個,以及每種數(shù)據(jù)類型在整個實例中的占比和平均大小 / 元素數(shù)量。
其實,使用這個命令的原理,就是 Redis 在內(nèi)部執(zhí)行了 SCAN 命令,遍歷整個實例中所有的 key,然后針對 key 的類型,分別執(zhí)行 STRLEN、LLEN、HLEN、SCARD、ZCARD 命令,來獲取 String 類型的長度、容器類型(List、Hash、Set、ZSet)的元素個數(shù)。
這里我需要提醒你的是,當執(zhí)行這個命令時,要注意 2 個問題:
- 對線上實例進行 bigkey 掃描時,Redis 的 OPS 會突增,為了降低掃描過程中對 Redis 的影響,最好控制一下掃描的頻率,指定 -i 參數(shù)即可,它表示掃描過程中每次掃描后休息的時間間隔,單位是秒
- 掃描結(jié)果中,對于容器類型(List、Hash、Set、ZSet)的 key,只能掃描出元素最多的 key。但一個 key 的元素多,不一定表示占用內(nèi)存也多,你還需要根據(jù)業(yè)務情況,進一步評估內(nèi)存占用情況
集中過期
集中過期產(chǎn)生的慢查詢很容易被忽略,可能我們在業(yè)務上線時,并沒有發(fā)生慢查詢,而是業(yè)務運行時在某個時間點總是突然發(fā)生慢查詢。為什么集中過期會導致慢查詢呢?我們首先了解下redis的兩種過期策略:
- 被動過期:只有當訪問某個key時,才會檢測該key是否已經(jīng)過期,如果已經(jīng)過期則從實例刪除該key。
- 主動過期:redis內(nèi)部存在一個定時任務,默認每間隔100毫秒就會從全局的過期哈希表里面隨機取出20個key,然后刪除其中過期的 key,如果過期 key 的比例超過了 25%,則繼續(xù)重復此過程,直到過期 key 的比例下降到 25% 以下,或者這次任務的執(zhí)行耗時超過了 25 毫秒,才會退出循環(huán)。
值得注意的是,主動過期key的定時任務是在redis主線程種執(zhí)行的,也就是說如果在執(zhí)行主動過期的過程中,出現(xiàn)了集中過期,那就需要大量刪除過期 key ,那么此時應用程序在訪問 Redis 時,必須要等待這個過期任務執(zhí)行結(jié)束,Redis 才可以服務這個客戶端請求,此時應用訪問 Redis 就可能產(chǎn)生查詢。
如果此時需要過期刪除的是一個 bigkey,那么這個耗時會更久。而且,這個操作延遲的命令并不會記錄在慢日志中。
因為慢日志中只記錄一個命令真正操作內(nèi)存數(shù)據(jù)的耗時,而 Redis 主動刪除過期 key 的邏輯,是在命令真正執(zhí)行之前執(zhí)行的。
對于集中過期問題,有以下建議
- 避免集中過期,比如將過期時間隨機化,添加一個隨機的值,分散集中過期的key的過期時間,降低 Redis 清理過期 key 的壓力
- 對于Redis 是 4.0 以上版本,可以開啟 lazy-free 機制,當刪除過期 key 時,把釋放內(nèi)存的操作放到后臺線程中執(zhí)行,避免阻塞主線程
總結(jié)
到此這篇關(guān)于Redis慢查詢的具體使用的文章就介紹到這了,更多相關(guān)Redis慢查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis+aop實現(xiàn)接口防刷(冪等)的解決方案
在高并發(fā)場景下,可能會因為網(wǎng)絡或者服務器原因,造成延遲,同時就是有可能會有人用腳本大量訪問你的接口,造成資源崩潰,所以本文給大家介紹了Redis+aop實現(xiàn)接口防刷(冪等)的解決方案,需要的朋友可以參考下2024-03-03