您现在的位置是:Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款 > 

02 Keep如何查看已經訂閱的(追蹤Redis Sentinel的CPU占有率長期接近100%的問題 二)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款2024-05-03 11:38:41【】5人已围观

简介;Toomanyopenfiles"問題,致使Sentinel的acceptTcpHandler事件處理函數會被頻繁并快速調用,最終導致了CPU長期接近100%的現象。但對于為什么會出現“T

;Too many open files"問題,致使Sentinel的acceptTcpHandler事件處理函數會被頻繁并快速調用,最終導致了CPU長期接近100%的現象。但對于為什么會出現“Too many open files”這個問題,本文將在上一篇的基礎上,繼續探討和分析。

“Too many open files”這個錯誤其實很常見,想必大家早已對其有一定的了解,這里打算再簡單的介紹一下。

很明顯,“Too many open files”即說明打開的文件(包括socket)數量過多,已經超出了系統設定給某個進程最大的文件描述符的個數,超過后即無法繼續打開新的文件,并且報這個錯誤。

首先,我們需要了解有關open files的基本知識。詳細的概念大家可以谷歌,網上也有各種各樣的解決辦法,這里只對open files做簡單的介紹和總結。

我們在linux上運行ulimit -a 后,出現:

如圖open files的個數為1024,很明顯這個值太小了(linux默認即為1024),當進程耗盡1024個文件或socket后,就會出現“Too many open files”錯誤。現實生產環境中這個值很容易達到,所以一般都會進行相應修改。

最簡單的修改方式是ulimit -n 65535,但這樣重啟系統后又會恢復。永久生效的方法是修改/etc/security/limits.買粉絲nf 文件,在最后加入:

修改完成后,重啟系統或者運行sysctl -p使之生效。

soft 和hard,表示對進程所能打開的文件描述符個數限制,其概念為:

他們的區別就是軟限制可以在程序的進程中自行改變(突破限制),而硬限制則不行(除非程序進程有root權限)。

上面的規則大家最好自己嘗試一下,以增加印象。

重啟后,運行ulimit -a,可以看到open files 的值改變為:

簡單介紹完open files,我們再來了解下file-max。這個參數相信有很多人經常與ulimit中的open files混淆,他們的區別我們必須了解。

file-max 從字面意思就可以看出是文件的最大個數,運行cat /proc/sys/fs/file-max,可以看到:

這表示當前系統所有進程一共可以打開的文件數量為387311。請務必注意”系統所有進程"這幾個字。

運行 vim /etc/sysctl.買粉絲nf ,有時候你會看到類似:fs.file-max = 8192。出現這個則表示用戶手動設置了這個值,沒有則系統會有其默認值。手動設置的話,只需要在sysctl.買粉絲nf 中加上上述語句即可。

回到ulimit中的open files,它與file-max的區別就是:opem filese表示當前shell以及由它啟動的進程的文件描述符的限制,也就是說ulimit中設置的open files,只是當前shell及其子進程的文件描述符的限定。是否清楚?可以簡單的理解為:

好了,對于 file-max與open files的簡單介紹到此為止。現在的問題就是,“Too many open files”到底是碰到哪個設置的雷區造成的。

結合上一篇,我們知道sentinel主要在執行accept函數時出現了“Too many open files”錯誤,熟悉accept這個系統調用的朋友很清楚,accept會接收客戶端的請求,成功的話會建立連接,并返回新的socket描述符。所以,我們確定這里的“Too many open files”指的即是socket的數目過多。

我們猜測,是否是有大量的Jedis連接同時存在,耗盡服務器的socket資源,導致新的連接請求無法建立。所以,我們查看一下sentinel服務器的TCP連接,運行:買粉絲stat -anp | grep 26379,得到:

由上圖可以發現,有非常多處于ESTABLISHED狀態的TCP連接,運行 買粉絲stat -anp | grep 118:26379 | wc -l查看他們的個數:

可以看到,Sentinel同時維持了4071個TCP連接,而且過了很久之后,仍然是這么多,不會有大幅變化。

這個值很大,看似一切正常。繼續運行sudo cat /proc/5515/limits,發現:

看到上圖,我們似乎發現了端倪,這里的hard和soft都是4096,與前面的4072比較接近。為什么會這么低?我們繼續查看一下ulimit,運行ulimit -a :

可以看到,ulimit中open files 的設置為64000,為什么會不一致?按理說sentinel應該最大有64000+的open files。

對于這個矛盾,一開始我怎么也想不明白。最后我推測:應該是在最早啟動sentinel啟動的時候,系統的設置為4096,sentinel啟動之后,又在某個時間又改為64000,而sentinel進程確保持原有設置,從而導致很快達到限制。

我馬上查看了進程的啟動時間,運行ps -eo pid,lstart,etime | grep 5515:

發現進程啟動于2015年12月2日,接著再次運行 ll /etc/security/limits.買粉絲nf:

發現確實在2016年4月改動過, 然后我買粉絲了運維人員,他們告知我,確實改動過,但由多少改動到多少,他們也忘了。。。

為了了解Sentinel啟動時的狀況,緊接著查看了Sentinel的日志,下面是Sentinel啟動時打印的畫面:

上圖說明了進程是2015年12月2日啟動的,特別注意最開頭的幾行,非常關鍵:

這幾句的意思是:

問題很清楚了,redis sentinel最大可以支持10000個客戶端,也就是10032個文件描述符,但由于當前被人為限制到4096 了,所以,自動降低了標準。

因此,我猜測,最早open files的限制為4096時,Sentinel已經啟動了,只要進程啟動,改多少都沒有用。很明顯,在生產環境上,4096個連接請求很快就會達到。

接著,我繼續查看了Sentinel的配置文件,如下圖所示:

上圖中, “Generated by CONFIG REWRITE”之前的都是是人工配置,其后為Sentinel自動重寫的配置。

熟悉Redis的朋友都知道。Sentinel可能會對其配置文件進行更新重寫:

我們很快注意到了maxclients 4064這個配置項,此時我很迷惑。我們知道,在Sentinel中是無法手動運行買粉絲nfig set命令的,那這個4096必然不是來自于人工配置,Sentinel為什么要自動重寫4064這個值。其實,仔細發現,這里Sentinel限制了最多4064個連接,加上32個預留,剛好為4096。

于是,綜上,我猜測,Sentinel在啟動的時候發現自己的10032個open files的預期與事實設置的4096不符,所以被迫遵守4096,減去預留的32,最終maxclients 只有4064,并且之后因為某些原因重寫了配置,所以輸出了這個值。

好吧,我的一貫作風,先猜測,再讓源碼說話。

我們可以通過異常信息定位異常所處源碼,所以我搜索了前面提到的Sentinel在啟動時打印的關于maxclients 的日志信息中的文本,如“You requested maxclients of ...”。

這個異常出現在adjustOpenFilesLimit函數,通過函數名可以清楚它的作用,然后發現它的調用鏈只是:

``main()->initServer()->adjustOpenFilesLimit()```

所以,可以確定,在Sentinel服務器啟動并進行初始化的時候,會調用adjustOpenFilesLimit函數對open files個數進行調整。調整策略是什么呢?我們查看源碼:

在第1行中,REDIS_MIN_RESERVED_FDS即預留的32,是Sentinel保留的用于額外的的操作,如listening sockets, log files 等。同時,這里讀取了server.maxclients的值,看來server.maxclients具有初始化值,通過經過定位源碼,發現調用鏈:

即Sentinel在啟動時,調用initServerConfig()初始化配置,執行了server.maxclients = REDIS_MAX_CLIENTS(REDIS_MAX_CLIENTS為10000),所以server.maxclients就有了初始值10000。

回到adjustOpenFilesLimit()函數,adjustOpenFilesLimit最終目的就是得到適合的soft,并存在server.maxclients中,因為該函數比較重要,下面專門作出解釋:

1 先得到maxfiles的初始值,即Sentinel的期望10032

2 然后獲取進程當前的soft和hard,并存入limit ,即執行getrlimit(RLIMIT_NOFILE,&limit) :

調整過程為:

1 先用oldlimit變量保存進程當前的soft的值(如4096)

2 然后,判斷oldlimit<maxfiles ,如果真,表示當前soft達不到你要求,需要調整。調整的時候,策略是從最大值往下嘗試,以逐步獲得Sentinel能申請到的最大soft。

嘗試過程為:

1 首先f保存要嘗試的soft值,初始值為maxfiles (10032),即從10032開始調整。

2 然后開始一個循環判斷,只要f大于oldlimit,就執行一次setrlimit(RLIMIT_NOFILE,&limit) ,然后f減16:

這樣,用這種一步一步嘗試的方法,最終可用得到了Sentiel能獲得的最大的soft值,最后減去32再保存在server.maxclients中。

另外,當得到Sentinel能獲得的最合適的soft值f后,還要判斷f與oldlimit(系統最初的soft限制,假設為4096),原因如下:

也許會直到f==4096才設置成功,但也會出現f<4096的情況,這是因為跨度為16,最后一不小心就減多了,但最后的soft值不應該比4096還小。所以,f=oldlimit就是這個意思。

最后,還有一個判斷:

上面的過程我們用簡單的表示為:

adjustOpenFilesLimit()的分析到此結束。但有一點一定要明確,adjustOpenFilesLimit()只會在Sentinel初始化的時候執行一次,目的就是將最合適的soft保存到了server.maxclients (第xx行),以后不會再調用。這樣,一旦設置了

很赞哦!(9)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款的名片

职业:程序员,设计师

现居:安徽滁州凤阳县

工作室:小组

Email:[email protected]