淺談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)'
輸出結果如下
解決方案 增加機器的內存,讓Redis 有足夠的記憶體可以使用Size: 1256 kB
如果只是少量資料被換到磁碟上,例如每一塊 Swap 佔對應 Size 的比例很小,那麼影響並不是很大。如果是幾百兆甚至上 GB 的記憶體被換到了磁碟上,那麼你就需要警惕了,這種情況 Redis 的效能肯定會急劇下降。
Swap: 4 kB
Swap: 0 kB
Size: 63488 kB
Swap: 0 kB
Size: 0 kB
Size: 65404 kB## 1921024 kB
Swap: 0 kB
...
這個結果會列出Redis 行程的記憶體使用量。
每一行Size 表示Redis 所用的一塊內存大小,Size 下面的Swap 就表示這塊Size 大小的內存,有多少資料已經被換到磁碟上了,如果這兩個值相等,說明這區塊記憶體的資料都已經完全被換到磁碟上了。
整理記憶體空間,釋放出足夠的記憶體供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影片教學
以上是淺談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 讀取隊列,需要獲取隊列名稱、使用 LPOP 命令讀取元素,並處理空隊列。具體步驟如下:獲取隊列名稱:以 "queue:" 前綴命名,如 "queue:my-queue"。使用 LPOP 命令:從隊列頭部彈出元素並返回其值,如 LPOP queue:my-queue。處理空隊列:如果隊列為空,LPOP 返回 nil,可先檢查隊列是否存在再讀取元素。

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

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

使用 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 參數設置。

Redis計數器是一種使用Redis鍵值對存儲來實現計數操作的機制,包含以下步驟:創建計數器鍵、增加計數、減少計數、重置計數和獲取計數。 Redis計數器的優勢包括速度快、高並發、持久性和簡單易用。它可用於用戶訪問計數、實時指標跟踪、遊戲分數和排名以及訂單處理計數等場景。

在Debian系統中,readdir系統調用用於讀取目錄內容。如果其性能表現不佳,可嘗試以下優化策略:精簡目錄文件數量:盡可能將大型目錄拆分成多個小型目錄,降低每次readdir調用處理的項目數量。啟用目錄內容緩存:構建緩存機制,定期或在目錄內容變更時更新緩存,減少對readdir的頻繁調用。內存緩存(如Memcached或Redis)或本地緩存(如文件或數據庫)均可考慮。採用高效數據結構:如果自行實現目錄遍歷,選擇更高效的數據結構(例如哈希表而非線性搜索)存儲和訪問目錄信
