一位同学的线上服务器出现一个诡异的问题?mt4骗局一位同砚的线上任职器崭露一个诡异的题目,实行任何敕令都是报错“fork:无法分拨内存”。这个题目近来崭露的,前几次重启后办理的,然而每隔 2-3 天就会崭露一次。
看到这个提示,群众的第一响应笃信是思疑内存真的不足了。咱们这位读者也是这么以为的。但查看内存占用却展现基础没有,内存还空闲了一大把!(众试几次才有机缘实行凯旋一次)
1.是不是numa架构下,过程启动的时辰绑定了node,导致唯有一个node里的内存正在起效用?
正在过程一段年光的排查从此,这位读者的题目成功办理。这里直接和群众请示结论,前面闭于 numa 内存不够的推测是谬误的。线 个,这台任职器上面的某几个java过程创修了太众的线程,导致了这个报错的出现,并不真的是内存不足。
这个题目中,Linux 报错提示存正在误导人的地方。导致群众并没有第偶尔间往过程数上念。因此才有了这么庞大波折的排错经过,乃至于磋议才得以办理。
于是我念长远到内核里看看,报错终究是怎样提示出来这么一个担心妥的谬误提示的。然后乘隙我们也来清晰清晰创修过程的经过。
读者的线上任职器的操作编制是 CentOS 7.8,我查了一下对应的内核版本是 3.10.0-1127。
正在 Linux 内核里,无论是创修过程如故线程,城市移用到最中心的 do_fork 上来。正在这个函数内部,通过拷贝的式样来创修新的过程(线程)所须要的内核数据对象。
扫数过程创修的中心都是位于 copy_process 中,咱们来看它的源码。
通过以上代码可能看出,Linux 内核创修扫数过程内查对象的创修经过都是通过离别移用分别的 copy_xxx 的式样来告终的,包含 mm 组织体、包含 namespaces等等。
咱们来核心 alloc_pid 联系的这一段。正在这一段中,主意是要申请一个 pid 对象出来。借使申请挫折就返回谬误了。群众谨慎这段代码的细节:无论 alloc_pid 返回的是何品种型的挫折,其谬误类型都写死的返回 -ENOMEM。。。为了轻易群众清楚,我孑立把这段逻辑再映现一遍。
咱们来查看一下 ENOMEM 的界说。它代外的是 Out of memory 的乐趣。(内核只是返回谬误码,操纵层再给出整个的谬误提示,因此现实提示的是中文的“无法分拨内存”)。
那咱们接着再来精细看看都有哪些处境下分拨 pid 会挫折呢?来看 alloc_pid 的源码
咱们通常说的 pid 正在内核中并不是一个单纯的整数类型,而是一个小组织体来吐露的(struct pid),如下。
因此须要先到内存中申请一块内存用来存储这个小对象。第一种谬误处境是借使内存申请挫折,alloc_pid 会返回挫折。这种处境下确实是内存题目,失足后内核返回 ENOMEM 无可厚非。
接着往下看第二种处境,alloc_pidmap 是要为如今的过程申请过程号,便是咱们通常所说的 PID 编号。借使申请挫折,也会返回谬误。
对付这种处境来说,只是分拨过程编号失足了,和内存不足用半毛钱的相干都没有。但正在这种处境下内核却会导致返回给上层的谬误类型是 ENOMEM(Out of memory)。这实正在是挺分歧理的。
通过这里咱们还卓殊研习到了其余一个学问!一个过程并不单是申请一个过程号就够了。而是通过一个 for 轮回去申请了众个。
若是说如今创修的过程是一个容器中的过程,那么它起码得申请两个 PID 号才行。一个 PID 是正在容器定名空间中的过程号,一个是根定名空间(宿主机)中的过程号。
这也吻合咱们通常的体味。正在容器中的每一个过程实在咱们正在宿主机中也都能看到。然而正在容器中看到的过程号普通是和正在宿主机上看到的是不相似的。譬喻一个过程正在容器中的 pid 是 5,正在宿主机定名空间下是 1256。那么该过程正在内核中的对象或者是如下这个形貌。
接下来,我最先念到的大概是由于我们用的内核版本太旧了。(谙习飞哥的读者都清爽,我用的内核版本是 3.10.1,这是为了和咱们公司线上任职器的版本维持相同。)
因此我又到非凡新的 Linux 5.16.11 翻了一翻,看看新版本是否有修复这个担心妥的提示。
保举一个东西:。正在这个网站上可能查看随便版本的 linux 内核源码。借使只是暂时看一下,用它非凡的适合。
貌似看起来有戏,retval 不再写死的是 ENOMEM 了,而是遵照 alloc_pid 现实的谬误实行了配置。咱们再来看 alloc_pid 是不是精确地配置谬误类型了呢?
当我掀开 alloc_pid 的源码里,看到这一大段解释的时辰,我的心凉了半截。。。
我把这段解释给群众大致翻译一下。它的乐趣是“ENOMEM不是最显明的选取,加倍是对付 pid 创修挫折的处境下。然而,ENOMEM 是咱们历久露出给用户空间的东西。以是,纵使有更适合的谬误代码,咱们也无法随便更改它”
看到这儿,我念起了有不少人也称 Linux 为屎山,大概这便是此中的一坨吧!最新的版本里也并没有很好地办理这个题目。
正在 Linux 里创修过程时,借使正在 pid 不够的时辰公然返回的谬误提示是“内存不够”。这个担心妥的谬误提示导致良众同砚都猜疑不已。
通过本日的作品,从此你再遭遇这种内存不够谬误的时辰,你就要众留个心眼儿了,别被内核被蒙骗了,先来看看我方的过程(线程)数是不是过众了。
至于说展现了这个题目该怎样办理嘛,可能通过修削内核参数加大可用 pid 数目(/proc/sys/kernel/pid_max)。
然而我感到最基础的本事如故要揪出来为啥编制中会崭露这么众的过程(线程),然后把它干掉。默认处境下的两三万个过程数对付绝大大都的任职器来说一经是一个过于重大的数字了,连这个数都进步了,必然是分歧理的。