LWP進程資源耗盡,Resource temporarily unavailable

  • 2019 年 10 月 6 日
  • 筆記

服務器環境使用root賬戶運行應用程序是非常危險的,容易讓人拿到shell變成肉雞。所以有點意識的團隊,都會建立一個低權限的普通用戶用來運行java程序。

權限低,有點不像親兒子,在資源緊張的困難時刻尤其能看出來。

現象

問題是在一台公用的測試環境機器發生的,正式環境並沒有復現。這台服務器部署了幾十個服務,且部署賬戶最近從root切換到了xjjbot

運行一段時間後,服務器頻繁發生問題了。首先,有大量連接處於CLOSE_WAIT狀態,一度以為是被動關閉的問題。但並不是。

netstat -antp | grep CLOSE | awk '{print $7}'  | sort | uniq -c

奇怪的是,使用root賬戶或者其他賬戶登錄系統,操作一切正常。然而當切換到xjjbot賬戶,則會報以下錯誤:

# sudo su - xjjbot  bash: fork: retry: no child processes  bash: fork: retry: no child processes  bash: fork: retry: no child processes  bash: fork: retry: no child processes  bash: fork: Resource temporarily unavailable

以上是系統級別的報錯信息。這種情況下,jvm也會有相應報錯,但恐怕你也沒有機會去看了(可以使用其他系統用戶查看哦)。

- Cannot create GC thread. Out of system resources  - java.lang.OutOfMemoryError: unable to create new native thread

原因

引起的原因就是資源不夠用了,具體來說是進程資源。

Linux的線程其實是一個進程,所以java的也是,具體來說,叫做「light weight process(LWP)」—輕量級進程。

LWP與其它進程共享所有(或大部分)邏輯地址空間和系統資源,一個進程可以創建多個LWP,這樣它們共享大部分資源;LWP有它自己的進程標識符,並和其他進程有着父子關係;。LWP由內核管理並像普通進程一樣被調度

使用以下命令可以看到某個用戶使用了多少進程資源

ps -eLf | grep xjjbot(uid)  | wc -l

使用下面命令可以查看具體每個進程開啟了多少線程

ps -o nlwp,pid,lwp,args -u xjjbot(uid)  | sort -n

解決

根據linux一切都是文件的規則,首先想到的,是修改ulimit的參數,然而也不是,因為它已經足夠大了。交叉回想一下elasticsearch,在安裝的時候,需要配置一個叫做nproc的東西,問題大概就出在這,是進程資源不夠用啦。

相關的配置文件: /etc/security/limits.conf

在不同的內核版本上,也有一些小差異。比如 /etc/security/limits.d/* 下的文件,會在某些時候覆蓋limits.conf的配置。所以配置不生效的情況下,記得檢查一下。

鑒於以上原因,可以將limits.d中的配置全部注釋掉,統一在limits.conf中配置。

以下是原始配置

*          soft    nproc     4096  root       soft    nproc     unlimited

將4096改為大點的數字,或者直接改成unlimited就可以了。

ElasticSearch系統參數配置

既然提到了es,那麼我們看一下es安裝都需要改哪些系統配置。這些經驗都是公用的,可以舉一反三。

https://www.elastic.co/guide/en/elasticsearch/reference/master/setting-system-settings.html

禁用swap

swap是性能殺手,所以ES也忍受不住了,直接關掉。

sudo swapoff -a

在配置文件里也可以加入這個參數,jvm鎖住內存,不讓它們和交換分區交換。

bootstrap.memory_lock: true

虛擬內存

ES使用mmapfs來映射一些數據,但默認的系統參數對它來說太小了,也需要修改。

sysctl -w vm.max_map_count=262144

永久生效需要修改 /etc/sysctl.conf

文件句柄

ulimit

linux打開的文件描述符數量是有限的。如果你的應用需要同時和很多小文件打交道,則需要配置此參數。

sudo su  ulimit -n 65536  su elasticsearch

/etc/security/limits.conf

ok,這就是我們剛才改動的文件。要想上面的配置永久生效,則需要改動此文件。

elasticsearch  -  nofile  65536

線程數量

就是我們上面說的啦,能夠快速想到它,也是因為安裝過es -.- 所以,不要隨便開一大堆線程,除了增加調度時間,還容易頂到系統的天花板。

馮諾依曼架構下,這些軟件,不都一個套路么? 有着一樣的命運,掙扎着卻無法逃脫。