背景:在某年某月某日發(fā)現(xiàn)es運(yùn)行不正常,查看日志發(fā)現(xiàn)如下錯誤
java.io.IOException: Too many open files
以下為操作步驟:
1.查看es節(jié)點信息結(jié)果:
{
"cluster_name" : "elasticsearch",
"nodes" : {
"eE4eHSOWTK-j6IO7JJzcXG" : {
"name" : "Hardcore",
"transport_address" : "inet[silence/192.168.1.111:9300]",
"host" : "silence",
"ip" : "192.168.1.111",
"version" : "1.6.0",
"build" : "cdd3ac4",
"http_address" : "inet[/192.168.1.111:9200]",
"process" : {
"refresh_interval_in_millis" : 1000,
"id" : 10598,
"max_file_descriptors" : 32768,
"mlockall" : false
}
}
}
}
疑問:明明在/etc/init.d/elasticsearch啟動腳本中設(shè)置了MAX_OPEN_FILES=65535, 且執(zhí)行ulimits -n $MAX_OPEN_FILES成功, 但是es節(jié)點信息中max_file_descriptors始終為32768
2.查看/etc/init.d/elasticsearch啟動腳本內(nèi)容,在啟動進(jìn)程時使用/etc/init.d/functions下的daemon函數(shù)啟動,最終追溯到daemon使用runuser -s /bin/bash $user -c "$corelimit >/dev/null 2>&1 ; $*"方式啟動進(jìn)程,自然想要在-c中添加ulimit -n 65535, 結(jié)果以失敗告終,啟動腳本報錯ulimit: open files: cannot modify limit: Operation not permitted,自己在命令行下發(fā)現(xiàn)普通用戶在修改時報錯, 而root用戶就ok
3.修改/etc/security/limits.conf文件添加如下內(nèi)容(es運(yùn)行用戶為elasticsearch)
elasticsearch hard nofile 65535
elasticsearch soft nofile 65535
修改內(nèi)容后重啟es, 啟動后查詢es節(jié)點信息max_file_descriptors還是為32768 ... 此時已瘋
4.查看谷歌,說/etc/pam.d/login文件中需要有session required pam_limits.so limits.conf文件才會起效,于是乎,我加上了,結(jié)果...尼瑪咋還是32768呢
5.再次查看/etc/pam.d/login發(fā)現(xiàn)有這么一句話session include system-auth, 一看就是導(dǎo)入了文件system-auth, 于是在system-auth中發(fā)現(xiàn)已經(jīng)存在session required pam_limits.so,然后尼瑪刪除步驟3添加的內(nèi)容
6.此時想到反編譯pam_limits.so文件看看到底干了什么事, 當(dāng)然先得查詢文件在哪 find / -name pam_limits.so
然后使用strings pam_limits.so 結(jié)果尼瑪發(fā)現(xiàn)其中有這么兩行:
/etc/security/limits.conf
.
.
.
/etc/security/limits.d/*.conf
自然想查看/etc/security/limits.d/下的*.conf結(jié)果,發(fā)現(xiàn)了def.conf,內(nèi)容為:
* hard nofile 32768
* soft nofile 32768
說明: *表示對所有用戶生效
結(jié)果自然要試試修改def.conf文件,結(jié)果這次ok了
分析原因:
1.why在/etc/init.d/elasticsearch中已經(jīng)設(shè)置ulimit -n為啥沒有生效
runuser命令格式:runuser -s [shell] [uid/gid] -c "command", 說明:使用一個替代的用戶或組ID運(yùn)行一個Shell, 只有會話的PAM hooks運(yùn)行, 并且沒有密碼提示, 這個命令僅在root用戶時有用
根據(jù)測試也知道ulimit -n只是修改當(dāng)前會話中的打開文件描述符數(shù)量, 當(dāng)打開新回話時或切換新用戶則失效。并根據(jù)描述得知runuser在打開會話之后PAM hooks認(rèn)證模塊會執(zhí)行,因此在此前的設(shè)置參數(shù)都無效
2.why在runuser時在-c中添加ulimit -n 65535報錯
查找資料發(fā)現(xiàn), 普通用戶在設(shè)置ulimit -n時其大小不能超過預(yù)設(shè)置的值, 那預(yù)設(shè)置的值是誰呢, 自然就想到limits.conf,可以自己測試在limits.conf中添加自己的用戶信息(silence is me),可以發(fā)現(xiàn)再次修改則正常
silence hard nofile 65535
silence soft nofile 65535
3.limits.conf和limits.d/*.conf的關(guān)系
此時自然想到的是文件加載順序和配置內(nèi)容有關(guān),配置相同的內(nèi)容但是值不通時,后加載的配置文件的值會生效呢, 我們做一下測試:在limits.d/def.conf配置文件中添加一下信息,因為第2步已經(jīng)在limit.conf中設(shè)置其值為65535并測試成功,那么此時若我們再測試ulimit -n 50000正常而ulimit -n 65535 不正常自然可以驗證我們的猜測
silence hard nofile 50000
結(jié)果自然與猜測一致
根據(jù)反編譯的結(jié)果pam_limits.so會先加載limits.conf然后再加載limits.d/.conf此時有一定順序, 但是limits.d/.conf中加載順序如何呢? 猜測與系統(tǒng)排序有關(guān),但未測試,在通常情況下好的系統(tǒng)管理員對不同用戶應(yīng)該根據(jù)userid在limits.d下建立不同的文件單獨配置,方便管理
為什么在limits.d/def.conf中值設(shè)置hard值呢?可以查看配置文件的規(guī)則,hard設(shè)置為允許修改的最大值而soft設(shè)置的是新回話生成時默認(rèn)設(shè)置
4.此時你應(yīng)該會問這個值到底可以設(shè)置多大?
查看文件/proc/sys/fs/file-max和/proc/sys/fs/file-nr內(nèi)容
輸入: cat /proc/sys/fs/file-max
輸出: 191832
輸入: cat/proc/sys/fs/file-nr
輸出: 1792 0 191832
查閱GOOGLE, file-nr文件中的三個數(shù)分別表示: 系統(tǒng)已經(jīng)分配的文件句柄數(shù), 沒有用到的句柄數(shù)和所有可分配的最大句柄數(shù),file-max中的值為最大所能分配的句柄數(shù), 因此在ulimit -n是設(shè)置的值不能超過file-max記錄的值
file-nr文件內(nèi)容通常由在系統(tǒng)啟動時根據(jù)系統(tǒng)內(nèi)存計算得出,系統(tǒng)內(nèi)存增大則file-max增大
5.如何查看其他進(jìn)程當(dāng)前設(shè)置的max_file_descriptors
對于linux內(nèi)核為2.6.24及以后版本
輸入: cat /proc/34690/limits | grep "Max open files"
輸出: Max open files 32768 32768 files
6.如何查看某進(jìn)程當(dāng)前打開的文件句柄數(shù):
輸入: lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|grep pid
輸出: cnt pid