《如何排查Redis的延遲問題》要點:
本文介紹了如何排查Redis的延遲問題,希望對您有用。如果有疑問,可以聯系我們。
在你使用Redis的過程中,有時可能會遇到延遲的問題,本文將會詳述導致延遲的各項原因.
在本文中,延遲就是客戶端哀求執行一個命令和客戶端收到命令執行結果之間的最大時延.通常,Redis的處理時間幾乎可以忽略不計,基本在亞微秒的范圍之內.但是,某些情況可能會導致較高的延遲時間.
以下內容非常重要,能夠使得Redis以一種低延遲的方式運行.然而,你的工作可能非常繁忙,也許你想要從一個快速的檢查清單開始辦理問題.如果以下的檢查步驟不能辦理你的延遲問題,那么你還可以回來閱讀全文.
(1)確保Redis沒有執行速度較慢的命令,這些命令有可能會阻塞服務器.你可以使用Redis的慢查詢日志功能排查這個問題,請參考《Redis的慢查詢日志詳解》.
(2)對于亞馬遜EC2的用戶來說,確保你使用的HVM是基于現在的EC2實例的,例如:m3.medium.不然,fork()系統調用的速度會非常慢.
(3)你的系統內核必需禁用透明巨頁(THP).你可以使用echo never > /sys/kernel/mm/transparent_hugepage/enabled命令禁用透明巨頁,然后重啟你的Redis進程.
(4)如果你正在使用一臺虛擬機,那么可能會存在固有延遲,這種延遲與Redis毫無關系.你可以使用./redis-cli --intrinsic-latency 100命令,在你的運行時環境中檢查你能夠預期的最小延遲時間.注意:你必要在Redis服務端中運行這個命令,而不是在客戶端中運行.
(5)你可以使用Redis的延遲監控子系統,這樣便能得到易讀的延遲時間和延遲原因的相關信息.請參考《Redis延遲監控框架詳解》.
通常,你可以通過下面的列表,在持久性和延遲/性能之間作出權衡,這個列表按照更好的數據平安性至更好的延遲性進行排序.
AOF + 總是調用fsync
這種方案的速度非常慢,應當只有在你知道本身要做什么的時候才能使用這個方案.
AOF + 每秒調用一次fsync
這是一個很好的妥協方案.
AOF + 每秒調用一次fsync + 將no-appendfsync-on-rewrite 選項設為yes
這個方案和上面的一樣好,并且還能在重寫AOF文件期間避免調用fsync操作,這樣能夠降低磁盤的I/O壓力.
AOF + 從不調用fsync
在這個方案中,fsync操作完全是由系統內核負責調用的.這個方案的磁盤壓力較小,延遲飆升的風險也較小,但是數據平安性較差.
RDB
這個方案取決于你配置的保留觸發器,你可以在一個巨大的范圍中作出權衡.
通過上述的檢查清單,一般你只必要花費15分鐘就可以排查出問題了.下文將會詳述造成延遲的各種原因.
如果你正在遭受延遲問題的困擾,你有可能想要知道如安在你的應用程序的背景下測量延遲時間,或者你遇到的延遲問題有可能在宏觀上看也是非常明顯的.然而,你可以使用redis-cli客戶端來測量Redis服務器的延遲時間(單位為毫秒),只需要運行以下命令:
redis-cli --latency -h <host> -p <port>
從Redis 2.8.13版本以來,Redis實現了延遲監控子系統,這個子系統能夠對分歧的執行路徑進行采樣,這樣便能推測服務器在何處發生阻塞.這項功能大大簡化了調試本文描述的延遲問題的復雜度,因此,強烈建議盡快啟用延遲監控子系統.請參考《Redis延遲監控框架詳解》.
雖然你可以利用延遲監控子系統的采樣和上報功能更簡單地推測Redis系統產生延遲問題的原因,但是仍然建議你仔細閱讀本文,這樣能力更好地理解Redis延遲飆升的相關技術細節.
有一種類型的延遲是Redis的運行環境與生俱來的.通常,操作系統內核會發生這種延遲,如果你的Redis在虛擬化環境中運行,那么虛擬機管理器(hypervisor)也會發生這種延遲.
雖然這種延遲并不能被消除,但是對其展開研究卻是非常重要的,因為它是Redis延遲的基線.換句話說,由于操作系統內核或虛擬機管理器的實現或配置的原因,你無論怎么對Redis延遲進行優化,都不可能低于上述的延遲基線,究竟Redis運行環境中的每個進程都會遭受這種延遲.
這種類型的延遲被稱為固有延遲,從Redis 2.8.7版本以來的redis-cli客戶端能夠測量這種延遲.以下示例在CentOS 6.6操作系統中運行,服務器是一臺入門級的虛擬機.
注意:參數100表現測試執行的時間,單位為秒.測試運行的時間越長,就越有可能發現延遲飆升.100秒通常是合適的,然而你可能想要執行幾次不同時間的測試.注意,這項測試是CPU密集型的,很有可能會導致單核心系統性能飽和.
Redis的固有延遲示例
注意:在這個特例中,應當在Redis的服務端主機中運行redis-cli程序,而不是在客戶端主機中運行.在這個特殊模式中,redis-cli程序完全不會連接至任何Redis服務器,它只會嘗試測量內核沒有花費CPU時間來運行redis-cli進程自己的最大時間.
在上述示例中,Redis系統的固有延遲只有0.094毫秒(或94微秒),這是一個很好的成果!然而,請記住,固有延遲會隨著時間而改變,取決于系統負載的情況.
虛擬化環境的延遲性能并不是很好,特別是在系統負載較高時,或者鄰近的虛擬機搶占資源時.以下示例在一臺VMware虛擬機實例中運行,它同時運行Redis服務和Apache服務:
Redis在高負載下的固有延遲
上述示例的固有延遲大約為7.6毫秒,這就意味著這個Redis系統的性能差強人意.然而,在虛擬化環境中運行更多次測試時,如果使用分歧的測試時間、更高的系統負載、鄰近的爭搶資源的虛擬機,那么固有延遲的性能數據會更差.根據多次的測量結果,只要系統的固有延遲不大于40毫秒,Redis就能夠正常提供服務.
客戶端會通過兩種方式連接至Redis服務器:TCP/IP連接或Unix域連接.通常,1 Gbit/s帶寬的網絡的延遲時間大約為200μs,而Unix域套接字的延遲時間可以低至30μs.延遲時間實際上取決于你的網絡和系統硬件.在網絡通信之上,系統也會增加一些延遲時間(線程調度、CPU緩存、NUMA結構等,都會增加延遲).在虛擬化環境中,系統導致的延遲時間明顯高于在物理機中運行的系統.
這種延遲造成的結果就是,即使Redis處理大多數命令所耗費的時間在亞微秒的范圍之內,當某個客戶端正在和Redis服務器進行許多次來回通信時,這個客戶端仍然會為這些網絡和系統相關的延遲付出很多額外的性能開銷.
因此,高效的客戶端會盡量限制來回通信的次數,可以利用管道機制,將若干條命令一次性發送給Redis服務器.Redis服務器和大多數客戶端完全支持上述的管道機制.類似于MSET/MGET的聚合命令也可以到達相似的效果.從Redis 2.4版本以來,很多命令還支持可變參數,適用于所有數據類型.
下面是一些指導方針:
如果你可以接受較高的本錢,那么盡量使用物理機來部署Redis服務器,而不是虛擬機.
不要有計劃地連接/斷開Redis服務器(對于WEB應用程序尤其要注意).盡可能長時間地堅持連接不要斷開.
如果你的客戶端和Redis服務器在相同的宿主機上,那么請使用Unix域套接字.
如果可以的話,請盡量使用聚合命令(MSET/MGET),或者使用支持可變參數的命令,而不是使用管道機制.
如果可以的話,請盡量使用管道機制,而不是必要來回通信的命令序列.
Redis服務器支持Lua腳本編程,在不支持原生管道機制的應用場景中,你可以使用Lua腳本(例如,當某條命令的執行成果是后續命令的一個輸入參數時).
在Linux系統中,有些人會優化進程布局(任務集)、cgroup、實時優先級(chrt)、NUMA配置(numactl),或者使用低延遲的系統內核,這些措施有可能獲得更好的延遲性能.請注意,Redis實際上不適合綁定至單個CPU核心.Redis會調用fork操作來創建后臺任務,類似于bgsave或AOF重寫的操作會極大地消耗CPU性能.這些任務絕對不能和主事件循環(也便是Redis主進程)在相同的CPU核心上運行.
在大多數情況下,不必要進行這些類型的系統級優化.只有當你必要的時候才能進行優化,同時你也得非常熟悉這些優化方案.
通常,Redis是以單線程模式工作的.這就意味著,Redis只會使用一個進程處理所有客戶端的哀求,這種技術被稱為多路復用.這就意味著,在每個給定的時刻,Redis只需要處理一個客戶端哀求.因此,所有的哀求都是按照順序依次處理的.這種設計非常類似于Node.js的工作原理.然而,這兩種產品都具有非常快的運行速度.有一部分原因在于處理單個哀求的時間非常短,但主要原因還在于這兩種產品被設計為不會阻塞系統調用(例如,從socket讀取數據或向socket寫入數據).
正如先前所述,Redis只是在大多數情況下以單線程模式工作.實際上,從Redis 2.4版本以來,Redis會使用多線程來執行某些較慢的后臺I/O操作(主要是磁盤I/O操作),但是這并不能否定Redis使用單線程來處理所有客戶端哀求的事實.
單線程模式有一個缺點,當某個哀求處理較慢時,其他所有的客戶端都必須等待這個哀求處理完成.當執行普通命令(例如,GET、SET或LPUSH命令)時,這個缺點一點都不成問題,因為這些命令的執行時間都是常數,并且耗時非常短.然而,某些命令(例如,SORT、LREM或SUNION命令)會操作很多元素.例如,如果Redis要獲得兩個大集合的交集,那么耗費的時間會非常可觀.
Redis的官方文檔列出了所有命令的算法復雜度.如果你要使用某些不熟悉的命令,那么在使用之前,最好了解一下這些命令的技術細節.
如果你對延遲時間心存疑慮,那么你不該當使用速度較慢的命令來操作由很多元素構成的對象,你也不該當在運行較慢的查詢操作時通過Redis復制功能進行數據備份.
通過Redis的慢查詢日志功能,你可以監控運行速度較慢的命令.請參考《
Redis的慢查詢日志詳解》.
另外,你可以使用你喜歡的監控程序(top、htop、prstat等等)來快速檢查Redis主進程的CPU消耗水平.如果CPU消耗較高,而網絡流量卻較低,那么通常Redis很有可能正在執行速度較慢的命令.
重要提示:在生產環境中,執行KEYS命令是造成延遲的一個常見原因,這個命令的運行速度很慢.正如Redis官方文檔所述,KEYS命令只應當在調試法式時使用.從Redis 2.8版本以來,Redis引入了一種新的命令類型,這些命令能夠增量迭代鍵空間和其他的大型集合.請參考SCAN、SSCAN、HSCAN和ZSCAN命令的用法.
為了在后臺生成RDB文件,或者重寫AOF文件(如果啟用AOF持久化功能的話),Redis必須調用fork()操作來創建后臺進程.fork()操作(在主線程中運行)自己就會產生延遲.
在類Unix系統中,fork()操作的性能開銷比擬大,因為它需要拷貝很多鏈接至進程的對象.對于虛擬內存機制相關的頁表來說,這種性能開銷顯得尤為明顯.
例如,在Linux/AMD64系統中,內存會被劃分為4 kB大小的頁.為了將虛擬地址轉換為物理地址,每個進程都會存儲一個頁表(實際的表現形式為一棵樹),這個頁表至少會包括進程地址空間的每個內存頁的一個指針.因此,如果某個Redis實例需要使用24 GB的內存,那么它需要24 GB / 4 kB * 8 = 48 MB的內存空間來存儲相應的頁表.
當某個Redis實例執行后臺保留操作(BGSAVE)時,這個實例將會調用fork()操作,這項操作需要分配和拷貝48 MB的內存.fork()操作會耗費時間和CPU性能,尤其對于虛擬機來說,一個大內存塊的分配和初始化會帶來相當可觀的開銷.
現代硬件拷貝頁表的速度非常快,但是Xen卻不行.Xen的問題并不是虛擬化特有的問題,而只是Xen特有的問題.例如,使用VMware或Virtual Box虛擬機時,調用fork()操作的速度也是非常快的.對于多個使用不同內存大小的Redis實例,以下列表會比擬它們執行fork()操作所耗費的時間.在每個Redis實例中執行BGSAVE命令就能夠獲得各自耗費的時間,這個時間表現為INFO命令輸出信息中的latest_fork_usec字段.
然而好消息是,如果你的實例是基于新型的EC2 HVM的,那么fork()操作耗費的時間會短得多,幾乎和物理機相同.因此,如果你使用m3.medium(或更好的)實例,那么就不消擔心fork()操作的性能.
Linux操作系統 + VMware虛擬機 + 6.0 GB的RSS內存:fork()操作耗費77毫秒(每GB耗費12.8毫秒).
Linux操作系統 + 物理機(未知硬件) + 6.1 GB的RSS內存:fork()操作耗費80毫秒(每GB耗費13.1毫秒).
Linux操作系統 + 物理機(Xeon@2.27GHz) + 6.9 GB的RSS內存:fork()操作耗費62毫秒(每GB耗費9毫秒).
Linux操作系統 + 6sync虛擬機(KVM)+ 360 MB的RSS內存:fork()操作耗費8.2毫秒(每GB耗費23.3毫秒).
Linux操作系統 + EC2虛擬機 + 舊實例類型(Xen)+ 6.1 GB的RSS內存:fork()操作耗費1460毫秒(每GB耗費239.3毫秒).
Linux操作系統 + EC2虛擬機 + 新實例類型(Xen)+ 1 GB的RSS內存:fork()操作耗費10毫秒(每GB耗費10毫秒).
Linux操作系統 + Linode實例(Xen)+ 0.9 GB的RSS內存:fork()操作耗費382毫秒(每GB耗費424毫秒).
正如你看到的,通過Xen運行的某些虛擬機的性能有著1到2個數量級的差距.對于EC2用戶來說,優化建議非常簡單:使用基于新型HVM的實例就可以了.
不幸的是,如果Linux內核啟用透明巨頁,那么當Redis調用fork()操作,以便于將數據持久化至磁盤時,Redis便會遇到很年夜的延遲問題.巨頁是導致下列問題的原因:
(1)Redis調用
fork()操作時,會創立兩個共享巨頁的進程.
(2)Redis的工作負載較重時,運行幾次事件循環就會導致命令必要處理幾千個內存頁,這樣便會造成Redis幾乎要對整個進程內存空間執行寫時拷貝(Copy On Write)操作.
(3)這將會導致較年夜的延遲時間和較高的內存使用率.
使用以下命令,確保操作系統禁用透明巨頁:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
為了能夠更高效地使用系統內存,當Linux系統(以及很多其他的當代操作系統)將數據從內存交換至磁盤時,它能夠重新分配內存頁,反之亦然.
如果內核將Redis的某個內存頁從內存交換至swap文件,那么當Redis需要使用存放在這個內存頁中的數據時(例如,拜訪某個存放在這個內存頁中的Key),為了將這個內存頁移回內存之中,內核將會停止Redis進程的運行.上述操作的速度很慢(相比起拜訪已在內存之中的內存頁來說),它牽涉到隨機的I/O操作,這樣會導致Redis客戶端遭受異常的延遲時間.
內核會重新分配寄存在磁盤上的Redis內存頁,主要歸結為以下三個原因:
如果正在運行的進程哀求更多的物理內存,而可用的內存總量卻不能滿足需求,那么系統便會遭受很大的內存壓力.這個問題的最簡單的例子就是Redis實際需要使用的內存總量多于服務器的可用內存總量.
如果Redis實例的數據集,或者數據集的一部分,在大多數時候是完全空閑的(客戶端從未拜訪),那么內核會將空閑的內存頁交換至磁盤.這種問題非常少見,因為即使某個Redis具有中等水平的運行速度,它也會經常拜訪所有的內存頁,這就會強迫Redis將所有的內存頁保留在內存之中.
在系統中,某些進程會發生大量的讀取或寫入的I/O操作.由于系統通常會緩存文件,這就很有可能迫使內核增加文件系統的緩存,因此就會發生內存交換活動.注意,Redis的RDB和/或AOF后臺線程也存在上述行為,這兩種持久化機制都會發生大型文件.
幸運的是,Linux操作系統有一個很好的工具能夠排查這個問題.因此,當Redis發生延遲問題時,最簡單的辦法就是檢查系統是否正在進行內存交換.
首先,必要查看交換至磁盤的Redis內存總量.為了這樣做,你必要獲得Redis實例的PID,如下圖所示:
Redis的進程ID
現在,進入這個進程對應的/proc文件系統的目錄,運行以下命令:
cd /proc/1522
此處,你會發現一個名為smaps的文件,它會描述Redis進程的內存布局(假設你正在使用Linux 2.6.16或更新的版本).這個文件包括系統進程的內存映射有關的非常詳細的信息,其中有一個名為Swap的字段,它正是我們需要觀察的字段.然而,smaps文件并不是只有Swap字段,因為這個文件會包括Redis進程的各種內存映射關系(相比起簡單的內存頁線性數組,進程的內存布局要復雜得多).
因為我們對進程交換的所有內存都感興趣,所以我們首先必要從smap文件抓取所有的Swap字段,如下圖所示:
smaps文件的swap字段
如果每一行都是0 KB,或者如果只有零星的4k條目,那么表現系統運行一切正常.實際上,在我們示例的Redis實例中(這臺服務器同時運行一個網站和一個Redis實例,每秒鐘為上百個用戶提供服務),只有少數幾個條目表現發生內存頁交換.為了排查這臺服務器是否有嚴重的問題,我們修改了先前的命令,同時輸出內存映射的大小,如下圖所示:
smaps文件的swap和size字段
正如你可以從輸出信息中看到的,最大的內存映射為1689600 kB,其中只有2000 kB被交換;第二大的內存映射為96844 kB,沒有任何內存被交換:基本上只有很少量的內存被交換,因此根本不會發生任何問題.
如果有大量的進程內存被交換至磁盤,那么你遇到的延遲問題很有可能和內存交換相關.如果這是你的Redis實例產生延遲問題的原因,那么你還可以使用vmstat命令進一步驗證延遲問題,如下圖所示:
vmstat命令的輸出信息
在vmstat命令的輸出信息中,我們只對si和so列感興趣,這兩列分別表現從swap文件換出和從swap文件換入的內存總量.如果你在這兩列看到非零值,那么就表現你的系統發生過內存交換活動.
最后,可以使用iostat命令檢查系統的全局I/O活動,如下圖所示:
iostat命令的輸出信息
如果你的延遲問題是由于Redis內存的交換操作而導致的,那么你必要降低系統的內存壓力:若Redis必要使用的內存總量多于可用的內存總量,則應當添加更多內存,或者避免在同一個系統中運行其他消耗內存較多的進程.
Redis的AOF持久化功能是導致延遲問題的另一個原因.基本上,AOF持久化會使用兩個系統調用來實現它的功能.此中一個是write(2)系統調用,它會將數據寫入AOF文件;另一個是fdatasync(2)
系統調用,它會將內核文件緩沖的數據刷入磁盤,這樣便能確保用戶指定的持久性等級.
write(2)和fdatasync(2)系統調用都可能導致延遲問題.例如,當正在執行涉及整個系統的數據同步(sync)時,或者當輸出緩沖已滿,內核必要將緩沖數據刷入磁盤,以便于接收新寫入的數據時,write(2)系統內調用便會阻塞系統.
相比之下,fdatasync(2)系統調用更有可能導致延遲問題.當執行這個系統調用時,很多種內核和文件系統的組合方式都會花費幾毫秒至幾秒才能完成,當某些其他進程正在執行I/O操作時尤其如此.為了辦理這個問題,從Redis 2.4版本以來,Redis會盡可能在一個不同的進程中執行fdatasync(2)系統調用.
經過多次修改AOF的相關配置,我們發現了AOF持久化是如何導致Redis發生延遲問題的.
通過appendfsync配置選項,你可以將AOF持久化配置為以三種分歧的方式調用fsync操作,將數據同步至磁盤上(你可以在運行時修改這項配置,使用CONFIG SET命令):
當appendfsync被設置為no時,Redis就不會執行fsync操作.在這種配置中,導致延遲問題的原因只有write(2)操作.當這種情況經常發生時,因為磁盤不能應對Redis接收數據時的速率問題,所以并沒有什么解決辦法.然而,如果磁盤沒有被其他執行I/O操作的進程拖慢速率,那么這種情況并不會經常發生.
當appendfsync被設置為everysec時,Redis會每秒鐘執行一次fsync操作.Redis會使用一個分歧的線程,如果正在執行fsync操作,那么Redis會使用緩沖來延遲write(2)操作的調用,最多延遲2秒鐘(在Linux操作系統中,如果正在執行的fsync操作和write操作會處理相同的文件,那么write操作很有可能會發生阻塞).然而,如果fsync操作消耗的時間過長,那么Redis最終還是會執行write(2)調用(即使fsync操作仍然未執行完成),這很有可能是導致延遲問題的原因.
當appendfsync被設置為always時,Redis會在每次寫入操作完成之后和向客戶端回復OK結果代碼之前,執行一次fsync操作(實際上,Redis會嘗試將很多命令聚集在同一時刻執行,這樣便只必要為這些命令執行一次fsync操作就可以了).在這種模式中,Redis的性能通常會很慢,強烈建議使用高速磁盤(例如:SSD)和高速文件系統,它們可以在短時間內執行完成fsync操作.
大多數的Redis用戶會將appendfsync配置項設為no或everysec.為了將延遲降低至最低,建議避免在同一個系統中運行其他必要執行I/O操作的進程.使用SSD磁盤也可以降低延遲.但是,即便使用普通的機械磁盤,Redis的AOF持久化也可以獲得較好的性能,只要確保Redis向AOF文件寫入數據時,磁盤正處于空閑狀態,那么就不用執行任何額外的尋道操作.
如果你想要排查AOF持久化相關的延遲問題,那么可以在Shell中運行strace命令:
strace -p $(pidof redis-server) -T -e trace=fdatasync
上述命令將會顯示在主線程中運行的Redis執行的所有fdatasync(2)系統調用.當appendfsync配置項被設置為everysec時,你不克不及通過上述命令查看后臺線程執行的fdatasync系統調用.為了查看fdatasync系統調用,你只要為strace命令添加-f選項就可以了.
如果你想要同時查看fdatasync和write系統調用,那么可以使用以下命令:
strace -p $(pidof redis-server) -T -e trace=fdatasync,write
然而,Redis還會使用write(2)系統調向客戶端的socket寫入數據,上述命令很有可能顯示太多和磁盤I/O無關的信息.顯然,沒有任何辦法可以告訴strace命令只顯示速度較慢的系統調用,因此我會使用以下命令:
strace -f -p $(pidof redis-server) -T -e trace=fdatasync,write 2>&1 | grep -v '0.0' | grep -v unfinished
Redis會通過以下兩種方式回收已過期的鍵:
被動方式:當某個命令哀求一個已過期的鍵時,會發現這個鍵已經過期了,然后便會執行回收操作.
主動方式:每隔100毫秒執行一次回收操作.
Redis的主動過期方式是自適應的.Redis會每隔100毫秒執行一次過期循環(每秒10次),每次循環都會執行以下操作:
采樣ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP個鍵,回收所有已經過期的鍵.
如果發現跨越25%的鍵已經過期了,那么重復上述操作.
注意,ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP的值是在Redis源碼的server.h文件中定義的.ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP的默認值為20,Redis每秒鐘執行10次過期循環,通常每秒鐘只有200個鍵會主動過期.即使很長時間都沒有拜訪已經過期的鍵,主動方式仍然能夠快速地清理Redis數據庫,因此被動方式的算法并沒有任何作用.同時,每秒鐘僅僅回收200個已經過期的鍵并不會導致Redis實例發生延遲問題.
然而,主動方式的算法是自適應的,如果它發現鍵的采樣集合之內有跨越25%的鍵已經過期了,那么便會重復執行.但是,假設這個算法每秒鐘運行10次,這就意味著隨機的采樣集合之內有跨越25%的鍵幾乎在同一時刻過期,這并不是一個好現象.
換句話說,如果Redis有很多很多的鍵幾乎在同一時刻過期,而且這些鍵在使用SETEX命令設置的所有鍵之中的比率至少達到25%,那么為了使得上述比率降低至小于25%,Redis便有可能發生阻塞.
為了避免已經過期的鍵占用太多的內存空間,Redis有需要使用上述的主動方式.通常,這種方式不會產生任何問題,雖然大量的鍵在同一時刻過期是一個很奇怪的現象,但是用戶在使用EXPIREAT
命令時不大可能大范圍地使用相同的Unix時間戳.
簡而言之:請注意,如果有很多鍵在同一時刻過期,那么Redis就有可能產生延遲問題.
Redis 2.6版本引入一個名為Redis軟件看門狗的調試工具,它可以用來跟蹤上述的各種延遲問題,你不必再使用其他工具來闡發問題了.
軟件看門狗是一個實驗性的功能.雖然可以在生產環境中使用軟件看門狗,但是在使用這項功能之前,你應當注意備份Redis數據庫,因為這項功能和Redis服務器的正常操作之間可能會發生無法預料的相互作用.
只有當你通過其他所有辦法都不能夠跟蹤延遲問題時,才能將軟件看門狗作為排查問題的最后手段.
這項功能的工作流程如下所示:
用戶通過CONFIG SET命令啟用軟件看門狗功能.
Redis賡續地監控自身.
如果Redis發現服務器由于某個操作未能快速返回而導致阻塞,這個操作很有可能就是延遲問題的原因,軟件看門狗便會在日志文件中生成關于服務器阻塞原因的底層申報.
在Redis的谷歌討論組中,用戶可以向Redis的開發者發送求助信息,包括看門狗生成的延遲報告.
注意,你無法通過redis.conf文件啟用這項功能,因為它原來就被設計為只有正在運行的Redis實例才能夠啟用,并且只能用作調試用途.
若要啟用這項功能,則在shell中運行以下命令:
redis-cli config set watchdog-period 500
周期時間的單位為毫秒.在上述示例中,看門狗只會在監測到Redis服務器產生500毫秒(或更長)的延遲時,才會將這個延遲問題記錄至日志文件.能夠配置的最小周期時間為200毫秒.
當你用完軟件看門狗之后,你可以將watchdog-period參數設置為0,這樣便能關閉這項功能.重要提示:用完軟件看門狗之后切記要關閉這項功能,通常長時間啟用不是一個好主意.
當軟件看門狗監測到Redis服務器的延遲時間超過指定的閾值時,便會在日志文件中發生相應的信息,如下圖所示:
看門狗的堆棧跟蹤信息
注意:在示例中,為了阻塞服務器,我們會使用DEBUG SLEEP命令.如果服務器在分歧的環境中發生阻塞,那么日志中的堆棧跟蹤也就分歧.
如果你收集到多個看門狗的堆棧跟蹤,那么你最好將所有這些信息都發送至Redis的谷歌討論組:Redis的開發者得到越多的跟蹤信息,排查你的Redis實例遇到的延遲問題也就越簡單.
歡迎參與《如何排查Redis的延遲問題》討論,分享您的想法,維易PHP學院為您提供專業教程。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/9257.html