您好,登錄后才能下訂單哦!
這篇文章主要介紹“Redis變慢的原因是什么及如何排查”,在日常操作中,相信很多人在Redis變慢的原因是什么及如何排查問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Redis變慢的原因是什么及如何排查”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
排查思路
如果你的 Redis 實例設置了內存上限 maxmemory,那么也有可能導致 Redis 變慢。
當我們把 Redis 當做純緩存使用時,通常會給這個實例設置一個內存上限 maxmemory,然后設置一個數據淘汰策略。而當實例的內存達到了 maxmemory 后,你可能會發現,在此之后每次寫入新數據,操作延遲變大了。
導致變慢的原因
當 Redis 內存達到 maxmemory 后,每次寫入新的數據之前,Redis 必須先從實例中踢出一部分數據,讓整個實例的內存維持在 maxmemory 之下,然后才能把新數據寫進來。
這個踢出舊數據的邏輯也是需要消耗時間的,而具體耗時的長短,要取決于你配置的淘汰策略:
allkeys-lru:不管 key 是否設置了過期,淘汰最近最少訪問的 key
volatile-lru:只淘汰最近最少訪問、并設置了過期時間的 key
allkeys-random:不管 key 是否設置了過期,隨機淘汰 key
volatile-random:只隨機淘汰設置了過期時間的 key
allkeys-ttl:不管 key 是否設置了過期,淘汰即將過期的 key
noeviction:不淘汰任何 key,實例內存達到 maxmeory 后,再寫入新數據直接返回錯誤
allkeys-lfu:不管 key 是否設置了過期,淘汰訪問頻率最低的 key(4.0+版本支持)
volatile-lfu:只淘汰訪問頻率最低、并設置了過期時間 key(4.0+版本支持)
具體使用哪種策略,我們需要根據具體的業務場景來配置。一般最常使用的是 allkeys-lru / volatile-lru 淘汰策略,它們的處理邏輯是,每次從實例中隨機取出一批 key(這個數量可配置),然后淘汰一個最少訪問的 key,之后把剩下的 key 暫存到一個池子中,繼續隨機取一批 key,并與之前池子中的 key 比較,再淘汰一個最少訪問的 key。以此往復,直到實例內存降到 maxmemory 之下。
需要注意的是,Redis 的淘汰數據的邏輯與刪除過期 key 的一樣,也是在命令真正執行之前執行的,也就是說它也會增加我們操作 Redis 的延遲,而且,寫 OPS 越高,延遲也會越明顯。
另外,如果此時你的 Redis 實例中還存儲了 bigkey,那么在淘汰刪除 bigkey 釋放內存時,也會耗時比較久。
看到了么?bigkey 的危害到處都是,這也是前面我提醒你盡量不存儲 bigkey 的原因。
解決方案
避免存儲 bigkey,降低釋放內存的耗時
淘汰策略改為隨機淘汰,隨機淘汰比 LRU 要快很多(視業務情況調整)
拆分實例,把淘汰 key 的壓力分攤到多個實例上
如果使用的是 Redis 4.0 以上版本,開啟 layz-free 機制,把淘汰 key 釋放內存的操作放到后臺線程中執行(配置 lazyfree-lazy-eviction = yes)
排查思路
我們都知道,應用程序向操作系統申請內存時,是按內存頁進行申請的,而常規的內存頁大小是 4KB。
Linux 內核從 2.6.38 開始,支持了內存大頁機制,該機制允許應用程序以 2MB 大小為單位,向操作系統申請內存。
應用程序每次向操作系統申請的內存單位變大了,但這也意味著申請內存的耗時變長。
導致變慢的原因
當 Redis 在執行后臺 RDB 和 AOF rewrite 時,采用 fork 子進程的方式來處理。但主進程 fork 子進程后,此時的主進程依舊是可以接收寫請求的,而進來的寫請求,會采用 Copy On Write(寫時復制)的方式操作內存數據。
也就是說,主進程一旦有數據需要修改,Redis 并不會直接修改現有內存中的數據,而是先將這塊內存數據拷貝出來,再修改這塊新內存的數據,這就是所謂的「寫時復制」。
寫時復制你也可以理解成,誰需要發生寫操作,誰就需要先拷貝,再修改。
這樣做的好處是,父進程有任何寫操作,并不會影響子進程的數據持久化(子進程只持久化 fork 這一瞬間整個實例中的所有數據即可,不關心新的數據變更,因為子進程只需要一份內存快照,然后持久化到磁盤上)。
但是請注意,主進程在拷貝內存數據時,這個階段就涉及到新內存的申請,如果此時操作系統開啟了內存大頁,那么在此期間,客戶端即便只修改 10B 的數據,Redis 在申請內存時也會以 2MB 為單位向操作系統申請,申請內存的耗時變長,進而導致每個寫請求的延遲增加,影響到 Redis 性能。
同樣地,如果這個寫請求操作的是一個 bigkey,那主進程在拷貝這個 bigkey 內存塊時,一次申請的內存會更大,時間也會更久。可見,bigkey 在這里又一次影響到了性能。
解決方案
關閉內存大頁機制。
首先,你需要查看 Redis 機器是否開啟了內存大頁:
$ cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never
如果輸出選項是 always,就表示目前開啟了內存大頁機制,我們需要關掉它:
$ echo never > /sys/kernel/mm/transparent_hugepage/enabled
其實,操作系統提供的內存大頁機制,其優勢是,可以在一定程序上降低應用程序申請內存的次數。
但是對于 Redis 這種對性能和延遲極其敏感的數據庫來說,我們希望 Redis 在每次申請內存時,耗時盡量短,所以我不建議你在 Redis 機器上開啟這個機制。
排查思路
如果你發現 Redis 突然變得非常慢,每次的操作耗時都達到了幾百毫秒甚至秒級,那此時你就需要檢查 Redis 是否使用到了 Swap,在這種情況下 Redis 基本上已經無法提供高性能的服務了。
導致變慢的原因
什么是 Swap?為什么使用 Swap 會導致 Redis 的性能下降?
如果你對操作系統有些了解,就會知道操作系統為了緩解內存不足對應用程序的影響,允許把一部分內存中的數據換到磁盤上,以達到應用程序對內存使用的緩沖,這些內存數據被換到磁盤上的區域,就是 Swap。
問題就在于,當內存中的數據被換到磁盤上后,Redis 再訪問這些數據時,就需要從磁盤上讀取,訪問磁盤的速度要比訪問內存慢幾百倍!尤其是針對 Redis 這種對性能要求極高、性能極其敏感的數據庫來說,這個操作延時是無法接受的。
此時,你需要檢查 Redis 機器的內存使用情況,確認是否存在使用了 Swap。你可以通過以下方式來查看 Redis 進程是否使用到了 Swap:
# 先找到 Redis 的進程 ID $ ps -aux | grep redis-server # 查看 Redis Swap 使用情況 $ cat /proc/$pid/smaps | egrep '^(Swap|Size)'
輸出結果如下
Size: 1256 kB Swap: 0 kB Size: 4 kB Swap: 0 kB Size: 132 kB Swap: 0 kB Size: 63488 kB Swap: 0 kB Size: 132 kB Swap: 0 kB Size: 65404 kB Swap: 0 kB Size: 1921024 kB Swap: 0 kB ...
這個結果會列出 Redis 進程的內存使用情況。
每一行 Size 表示 Redis 所用的一塊內存大小,Size 下面的 Swap 就表示這塊 Size 大小的內存,有多少數據已經被換到磁盤上了,如果這兩個值相等,說明這塊內存的數據都已經完全被換到磁盤上了。
如果只是少量數據被換到磁盤上,例如每一塊 Swap 占對應 Size 的比例很小,那影響并不是很大。如果是幾百兆甚至上 GB 的內存被換到了磁盤上,那么你就需要警惕了,這種情況 Redis 的性能肯定會急劇下降。
解決方案
增加機器的內存,讓 Redis 有足夠的內存可以使用
整理內存空間,釋放出足夠的內存供 Redis 使用,然后釋放 Redis 的 Swap,讓 Redis 重新使用內存
釋放 Redis 的 Swap 過程通常要重啟實例,為了避免重啟實例對業務的影響,一般會先進行主從切換,然后釋放舊主節點的 Swap,重啟舊主節點實例,待從庫數據同步完成后,再進行主從切換即可。
可見,當 Redis 使用到 Swap 后,此時的 Redis 性能基本已達不到高性能的要求(你可以理解為武功被廢),所以你也需要提前預防這種情況。
預防的辦法就是,你需要對 Redis 機器的內存和 Swap 使用情況進行監控,在內存不足或使用到 Swap 時報警出來,及時處理。
排查思路
如果以上產生性能問題的場景,你都規避掉了,而且 Redis 也穩定運行了很長時間,但在某個時間點之后開始,操作 Redis 突然開始變慢了,而且一直持續下去,這種情況又是什么原因導致?
此時你需要排查一下 Redis 機器的網絡帶寬是否過載,是否存在某個實例把整個機器的網路帶寬占滿的情況。
導致變慢的原因
網絡帶寬過載的情況下,服務器在 TCP 層和網絡層就會出現數據包發送延遲、丟包等情況。
Redis 的高性能,除了操作內存之外,就在于網絡 IO 了,如果網絡 IO 存在瓶頸,那么也會嚴重影響 Redis 的性能。
解決方案
及時確認占滿網絡帶寬 Redis 實例,如果屬于正常的業務訪問,那就需要及時擴容或遷移實例了,避免因為這個實例流量過大,影響這個機器的其他實例。
運維層面,你需要對 Redis 機器的各項指標增加監控,包括網絡流量,在網絡流量達到一定閾值時提前報警,及時確認和擴容。
1) 頻繁短連接
你的業務應用,應該使用長連接操作 Redis,避免頻繁的短連接。
頻繁的短連接會導致 Redis 大量時間耗費在連接的建立和釋放上,TCP 的三次握手和四次揮手同樣也會增加訪問延遲。
2) 運維監控
前面我也提到了,要想提前預知 Redis 變慢的情況發生,必不可少的就是做好完善的監控。
監控其實就是對采集 Redis 的各項運行時指標,通常的做法是監控程序定時采集 Redis 的 INFO 信息,然后根據 INFO 信息中的狀態數據做數據展示和報警。
這里我需要提醒你的是,在寫一些監控腳本,或使用開源的監控組件時,也不能掉以輕心。
在寫監控腳本訪問 Redis 時,盡量采用長連接的方式采集狀態信息,避免頻繁短連接。同時,你還要注意控制訪問 Redis 的頻率,避免影響到業務請求。
在使用一些開源的監控組件時,最好了解一下這些組件的實現原理,以及正確配置這些組件,防止出現監控組件發生 Bug,導致短時大量操作 Redis,影響 Redis 性能的情況發生。
我們當時就發生過,DBA 在使用一些開源組件時,因為配置和使用問題,導致監控程序頻繁地與 Redis 建立和斷開連接,導致 Redis 響應變慢。
3)其它程序爭搶資源
最后需要提醒你的是,你的 Redis 機器最好專項專用,只用來部署 Redis 實例,不要部署其他應用程序,盡量給 Redis 提供一個相對「安靜」的環境,避免其它程序占用 CPU、內存、磁盤資源,導致分配給 Redis 的資源不足而受到影響。
到此,關于“Redis變慢的原因是什么及如何排查”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。