最近在線上發現一個問題,程序在服務器上跑了3周後,會出現新日志文件創建不出來的問題,另外,該程序需要使用curl訪問後端的HTTP服務調用總是失敗。日志文件創建不出來由於不是關鍵業務,一開始沒有做太多關注。但是訪問後端HTTP服務失敗的問題卻是很要命。監控報警一響,我們首先嘗試解決問題,就重啟了所有程序,問題解決。之後,就立馬排查這個問題發生的原因。
在沒有重啟程序前,首先懷疑的自然是後端HTTP服務有問題(雖然該服務的報警沒有響起),一個同事在服務器上命令行嘗試curl調用,沒有問題(這也排除了DNS問題、防火牆問題,無需再ping和telnet了)。
查詢出現問題時服務器使用的CPU、內存量和磁盤剩余空間,都是正常的。
我突然將新日志文件創建不出來的問題和curl調用後端HTTP服務失敗的問題聯系起來,這兩者都需要創建文件句柄(curl需要創建socket句柄),會不會是文件句柄耗盡的問題呢?
測試環境大壓力壓程序,命令行使用“lsof -c 程序名 | wc -l”,確實發現打開的文件句柄越來越多。問題找到了。接下來就發現是一個函數內socket句柄創建後沒有關閉。添加close(fd)後,再次在測試環境測試,打開的文件句柄數量沒有出現增長,問題解決。
由於程序中加了設置可以打開文件句柄最大數量為65535,所以,這個問題事前根本沒有想到,而且在系統頻繁發布(一周兩次發布)的情況,根本不會出現。但是當發布頻率放緩後,問題就出現了。
因此,Linux程序開發,除了需要關注CPU使用率、內存使用率和硬盤空間外,也需要特別關注一下程序打開的文件句柄釋放的問題。
PS:更新打開文件句柄的最大數量程序如下:
[cpp]
#include <sys/time.h>
#include <sys/resource.h>
void max_fd()
{
struct rlimit rlim, rlim_new;
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
printf("RLIMIT_NOFILE Old Soft(%d), Hard(%d)\n", rlim.rlim_cur, rlim.rlim_max);
if(rlim.rlim_max < 65535 && rlim.rlim_max != RLIM_INFINITY)
{
rlim_new.rlim_max = 65535;
}
if(rlim.rlim_cur < 65535 && rlim.rlim_max != RLIM_INFINITY)
{
rlim_new.rlim_cur = 65535;
}
if (setrlimit(RLIMIT_NOFILE, &rlim_new) != 0) {
rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
(void) setrlimit(RLIMIT_NOFILE, &rlim_new);
printf("RLIMIT_NOFILE New Soft(%d), Hard(%d)\n", rlim_new.rlim_cur, rlim_new.rlim_max);
}
else www.2cto.com
{
printf("RLIMIT_NOFILE New Soft(%d), Hard(%d)\n", rlim_new.rlim_cur, rlim_new.rlim_max);
}
}
}