一起聊聊Redis變慢的原因及檢驗方法
這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了關於Redis變慢的原因及排查方法的相關問題,下面一起來看一下,希望對大家有幫助。
推薦學習:Redis影片教學
#原因1:實例記憶體達到上限
排查想法
如果你的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)
原因2:開啟記憶體大頁
#排查想法
- 我們都知道,應用程式向作業系統申請記憶體時,是按記憶體頁申請的,而常規的記憶體頁大小是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 機器上開啟這個機制。
原因3:使用Swap
檢查思路
#如果你發現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 時警出來,及時處理。
原因4:網路頻寬過載
#檢查想法
如果以上產生效能問題的場景,你都規避掉了,而且Redis 也穩定運行了很長一段時間,但在某個時間點之後開始,操作Redis 突然開始變慢了,而且一直持續下去,這種情況又是什麼原因導致?
此時你需要排查 Redis 機器的網路頻寬是否過載,是否有某個執行個體把整台機器的網路頻寬佔滿的狀況。
導致變慢的原因
網路頻寬過載的情況下,伺服器在 TCP 層和網路層就會出現封包發送延遲、遺失封包等情況。
Redis 的高效能,除了操作記憶體之外,就在於網路 IO 了,如果網路 IO 有瓶頸,也會嚴重影響 Redis 的效能。
解決方案
- 及時確認佔滿網路頻寬Redis 實例,如果屬於正常的業務訪問,那就需要及時擴容或遷移實例了,避免因為這個實例流量太大,影響這個機器的其他實例。
- 維運層面,你需要對 Redis 機器的各項指標增加監控,包括網路流量,在網路流量達到一定閾值時提前報警,及時確認和擴容。
原因5:其他原因
##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變慢的原因及檢驗方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Redis集群模式通過分片將Redis實例部署到多個服務器,提高可擴展性和可用性。搭建步驟如下:創建奇數個Redis實例,端口不同;創建3個sentinel實例,監控Redis實例並進行故障轉移;配置sentinel配置文件,添加監控Redis實例信息和故障轉移設置;配置Redis實例配置文件,啟用集群模式並指定集群信息文件路徑;創建nodes.conf文件,包含各Redis實例的信息;啟動集群,執行create命令創建集群並指定副本數量;登錄集群執行CLUSTER INFO命令驗證集群狀態;使

如何清空 Redis 數據:使用 FLUSHALL 命令清除所有鍵值。使用 FLUSHDB 命令清除當前選定數據庫的鍵值。使用 SELECT 切換數據庫,再使用 FLUSHDB 清除多個數據庫。使用 DEL 命令刪除特定鍵。使用 redis-cli 工具清空數據。

要從 Redis 讀取隊列,需要獲取隊列名稱、使用 LPOP 命令讀取元素,並處理空隊列。具體步驟如下:獲取隊列名稱:以 "queue:" 前綴命名,如 "queue:my-queue"。使用 LPOP 命令:從隊列頭部彈出元素並返回其值,如 LPOP queue:my-queue。處理空隊列:如果隊列為空,LPOP 返回 nil,可先檢查隊列是否存在再讀取元素。

使用 Redis 指令需要以下步驟:打開 Redis 客戶端。輸入指令(動詞 鍵 值)。提供所需參數(因指令而異)。按 Enter 執行指令。 Redis 返迴響應,指示操作結果(通常為 OK 或 -ERR)。

在CentOS系統上,您可以通過修改Redis配置文件或使用Redis命令來限制Lua腳本的執行時間,從而防止惡意腳本佔用過多資源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位於/etc/redis/redis.conf。編輯配置文件:使用文本編輯器(例如vi或nano)打開配置文件:sudovi/etc/redis/redis.conf設置Lua腳本執行時間限制:在配置文件中添加或修改以下行,設置Lua腳本的最大執行時間(單位:毫秒)

使用Redis進行鎖操作需要通過SETNX命令獲取鎖,然後使用EXPIRE命令設置過期時間。具體步驟為:(1) 使用SETNX命令嘗試設置一個鍵值對;(2) 使用EXPIRE命令為鎖設置過期時間;(3) 當不再需要鎖時,使用DEL命令刪除該鎖。

使用 Redis 命令行工具 (redis-cli) 可通過以下步驟管理和操作 Redis:連接到服務器,指定地址和端口。使用命令名稱和參數向服務器發送命令。使用 HELP 命令查看特定命令的幫助信息。使用 QUIT 命令退出命令行工具。

Redis數據過期策略有兩種:定期刪除:定期掃描刪除過期鍵,可通過 expired-time-cap-remove-count、expired-time-cap-remove-delay 參數設置。惰性刪除:僅在讀取或寫入鍵時檢查刪除過期鍵,可通過 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-user-del 參數設置。
