<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          幾個內(nèi)核參數(shù)引起的 K8s 集群 Java 血案

          共 26664字,需瀏覽 54分鐘

           ·

          2022-11-02 02:28


          ?

          本文轉(zhuǎn)自博客園,原文:https://www.cnblogs.com/apink/p/15728381.html,版權(quán)歸原作者所有。歡迎投稿,投稿請?zhí)砑游⑿藕糜眩?strong style="color: rgb(50, 108, 229);">cloud-native-yang

          背景說明

          運行環(huán)境信息:Kubernetes + docker,應(yīng)用程序:Java

          問題描述

          1、首先從 Kubernetes 事件中心告警信息如下,該告警集群常規(guī)告警事件(其實從下面這些常規(guī)告警信息是無法判斷是什么故障問題)

          2、最初懷疑是 docker 服務(wù)有問題,切換至節(jié)點上查看 docker & kubelet 日志,如下:

          ?

          kubelet 無法初始化線程,需要增加所處運行用戶的進程限制,大致意思就是需要調(diào)整 ulimit -u(具體分析如下先描述問題)

          $ journalctl -u "kubelet" --no-pager --follow 
          -- Logs begin at Wed 2019-12-25 11:30:13 CST. --
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: encoding/js(*decodeState).unmarshal(0xc000204580, 0xcafe00, 0xc00048f440, 0xc0002045a8, 0x0)
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/encoding/json/decode.go:180 +0x1ea
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: encodijson.Unmarshal(0xc00025e000, 0x9d38, 0xfe00, 0xcafe00, 0xc00048f440, 0x0, 0x0)
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/encoding/json/decode.go:107 +0x112
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: github.com/go-openaspec.Swagger20Schema(0xc000439680, 0x0, 0x0)
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.com/openapi/spec/spec.go:82 +0xb8
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: github.com/go-openapi/spec.MustLoadSwagger20Schema(...)
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.com/openapi/spec/spec.go:66
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: github.com/go-openapi/spec.init.4()
          Dec 22 14:21:51 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.com/openapi/spec/spec.go:38 +0x57
          Dec 22 14:22:06 PROD-BE-KWN8 kubelet[3124]: runtime: failed to create new OS thread (have 15 already; errno=11)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime: may need to increase max user processes (ulimiu)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: fatal error: newosproc
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: goroutine 1 [running, locked to thread]:
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.throw(0xcbf07e, 0x9)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtipanic.go:1116 +0x72 fp=0xc00099fe20 sp=0xc00099fdf0 pc=0x4376d2
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.newosproc(0xc000600800)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtios_linux.go:161 +0x1c5 fp=0xc00099fe80 sp=0xc00099fe20 pc=0x433be5
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.newm1(0xc000600800)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiproc.go:1843 +0xdd fp=0xc00099fec0 sp=0xc00099fe80 pc=0x43dcbd
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.newm(0xcf1010, 0x0, 0xffffffffffffffff)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiproc.go:1822 +0x9b fp=0xc00099fef8 sp=0xc00099fec0 pc=0x43db3b
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.startTemplateThread()
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiproc.go:1863 +0xb2 fp=0xc00099ff28 sp=0xc00099fef8 pc=0x43ddb2
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.LockOSThread()
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiproc.go:3845 +0x6b fp=0xc00099ff48 sp=0xc00099ff28 pc=0x44300b
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: main.init.0()
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/plugins/cilium-ccilium-cni.go:66 +0x30 fp=0xc00099ff58 sp=0xc00099ff48 pc=0xb2fa50
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.doInit(0x11c73a0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiproc.go:5652 +0x8a fp=0xc00099ff88 sp=0xc00099ff58 pc=0x44720a
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.main()
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiproc.go:191 +0x1c5 fp=0xc00099ffe0 sp=0xc00099ff88 pc=0x439e85
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: runtime.goexit()
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/runtiasm_amd64.s:1374 +0x1 fp=0xc00099ffe8 sp=0xc00099ffe0 pc=0x46fc81
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: goroutine 11 [chan receive]:
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: k8s.io/klog/v2.(*loggingT).flushDaemon(0x121fc40)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/k8s.io/klog/klog.go:1131 +0x8b
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: created by k8s.io/klog/v2.init.0
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/k8s.io/klog/klog.go:416 +0xd8
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: goroutine 12 [select]:
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*pipe).Read(0xc000422780, 0xc00034b000, 0x1000, 0x1000, 0xba4480, 0x1, 0xc00034b000)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:57 +0xe7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*PipeReader).Read(0xc00000e380, 0xc00034b000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:134 +0x4c
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: bufio.(*Scanner).Scan(0xc00052ef38, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/bufio/scan.go:214 +0xa9
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: github.com/sirupsen/logr(*Entry).writerScanner(0xc00016e1c0, 0xc00000e380, 0xc000516300)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:59 +0xb4
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: created by github.com/sirupsen/logrus.(*Entry).WriterLevel
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:51 +0x1b7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: goroutine 13 [select]:
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*pipe).Read(0xc0004227e0, 0xc000180000, 0x1000, 0x1000, 0xba4480, 0x1, 0xc000180000)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:57 +0xe7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*PipeReader).Read(0xc00000e390, 0xc000180000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:134 +0x4c
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: bufio.(*Scanner).Scan(0xc00020af38, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/bufio/scan.go:214 +0xa9
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: github.com/sirupsen/logr(*Entry).writerScanner(0xc00016e1c0, 0xc00000e390, 0xc000516320)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:59 +0xb4
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: created by github.com/sirupsen/logrus.(*Entry).WriterLevel
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:51 +0x1b7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: goroutine 14 [select]:
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*pipe).Read(0xc000422840, 0xc0004c2000, 0x1000, 0x1000, 0xba4480, 0x1, 0xc0004c2000)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:57 +0xe7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*PipeReader).Read(0xc00000e3a0, 0xc0004c2000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:134 +0x4c
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: bufio.(*Scanner).Scan(0xc00052af38, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/bufio/scan.go:214 +0xa9
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: github.com/sirupsen/logr(*Entry).writerScanner(0xc00016e1c0, 0xc00000e3a0, 0xc000516340)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:59 +0xb4
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: created by github.com/sirupsen/logrus.(*Entry).WriterLevel
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:51 +0x1b7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: goroutine 15 [select]:
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*pipe).Read(0xc0004228a0, 0xc000532000, 0x1000, 0x1000, 0xba4480, 0x1, 0xc000532000)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:57 +0xe7
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: (*PipeReader).Read(0xc00000e3b0, 0xc000532000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/io/pipe.go:134 +0x4c
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: bufio.(*Scanner).Scan(0xc00052ff38, 0x0)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /usr/local/go/src/bufio/scan.go:214 +0xa9
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: github.com/sirupsen/logr(*Entry).writerScanner(0xc00016e1c0, 0xc00000e3b0, 0xc000516360)
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:59 +0xb4
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: created by github.com/sirupsen/logrus.(*Entry).WriterLevel
          Dec 22 14:22:06 PROD-BE-K8S-WN8 kubelet[3124]: /go/src/github.com/cilium/cilium/vendor/github.csirupsen/logrus/writer.go:51 +0x1b7

          3、于是查看系統(tǒng)日志,如下(本來想追蹤當前時間的系統(tǒng)日志,但當時系統(tǒng)反應(yīng)超級慢,但是當時的系統(tǒng) load 是很低并沒有很高,而且 CPU & MEM 利用率也不高,具體在此是系統(tǒng)為什么反應(yīng)慢,后面再分析 “問題一”):

          ?

          再執(zhí)行查看系統(tǒng)命令,提示無法創(chuàng)建進程

          $ dmesg -TL
          -bash: fork: retry: No child processes
          [Fri Sep 17 18:25:53 2021] Linux version 5.11.1-1.el7.elrepo.x86_64 (mockbuild@Build64R7) (gcc (GC9.3.1 20200408 (Red Hat 9.3.1-2), GNU ld version 2.32-16.el7) #1 SMP Mon Feb 22 17:30:33 EST 2021
          [Fri Sep 17 18:25:53 2021] Command line: BOOT_IMAGE=/boot/vmlinuz-5.11.1-1.el7.elrepo.x86_root=UUID=8770013a-4455-4a77-b023-04d04fa388c8 ro crashkernel=auto spectre_v2=retpoline net.ifnamesconsole=tty0 console=ttyS0,115200n8 noibrs
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x008: 'MPX bounds registers'
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x010: 'MPX CSR'
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x020: 'AVX-512 opmask'
          [Fri Sep 17 18:25:53 2021] x86/fpu: Supporting XSAVE feature 0x040: 'AVX-512 Hi256'

          4、嘗試在該節(jié)點新建 Container,如下:

          ?

          提示初始化線程失敗,資源不夠

          $ docker run -it --rm tomcat bash
          runtime/cgo: runtime/cgo: pthread_create failed: Resource temporarily unavailable
          pthread_create failed: Resource temporarily unavailable
          SIGABRT: abort
          PC=0x7f34d16023d7 m=3 sigcode=18446744073709551610

          goroutine 0 [idle]:
          runtime: unknown pc 0x7f34d16023d7
          stack: frame={sp:0x7f34cebb8988, fp:0x0} stack=[0x7f34ce3b92a8,0x7f34cebb8ea8)
          00007f34cebb8888:  000055f2b345a7bf <runtime.(*mheap).scavengeLocked+559>  00007f34cebb88c0
          00007f34cebb8898:  000055f2b3450e0e <runtime.(*mTreap).end+78>  0000000000000000

          故障分析

          根據(jù)以上的故障問題初步分析,第一反應(yīng)是 ulimi -u 值太小,已經(jīng)被 hit(觸及到,突破該參數(shù)的上限),于是查看各用戶的 ulimi  -u,官方描述就是 max user  processes(該參數(shù)的值上限應(yīng)該小于 user.max_pid_namespace 的值,該參數(shù)是內(nèi)核初始化分配的)。

          監(jiān)控信息

          查看用戶的 max processes 的上限,如下:

          ulimit -a
          core file size          (blocks, -c) 0
          data seg size           (kbytes, -d) unlimited
          scheduling priority             (-e) 0
          file size               (blocks, -f) unlimited
          pending signals                 (-i) 249047
          max locked memory       (kbytes, -l) 64
          max memory size         (kbytes, -m) unlimited
          open files                      (-n) 65535
          pipe size            (512 bytes, -p) 8
          POSIX message queues     (bytes, -q) 819200
          real-time priority              (-r) 0
          stack size              (kbytes, -s) 8192
          cpu time               (seconds, -t) unlimited
          max user processes              (-u) 249047
          virtual memory          (kbytes, -v) unlimited
          file locks                      (-x) unlimited

          因為 ulimit 是針對于每用戶而言的,具體還要驗證每個用戶的 limit 的配置,如下:

          ?

          根據(jù)以下配置判斷,并沒有超出設(shè)定的范圍。

          # 默認limits.conf的配置
          # End of file
          root soft nofile 65535
          root hard nofile 65535
          * soft nofile 65535
          * hard nofile 65535

          # limits.d/20.nproc.conf的配置,如下
          # Default limit for number of user's processes to prevent
          # accidental fork bombs.
          # See rhbz #432903 for reasoning.

          *          soft    nproc     65536
          root       soft    nproc     unlimited

          查看節(jié)點運行的進程:

          ?

          從監(jiān)控信息可以看到在故障最高使用 457 個進程。

          查看系統(tǒng)中的進程狀態(tài),如下:

          ?

          雖然說有個 Z 狀的進程,但是也不影響當前系統(tǒng)運行。

          查看系統(tǒng) create 的線程數(shù),如下:

          ?

          從下監(jiān)控圖表,當時最大線程數(shù)是 32616。

          分析過程

          1、從以上監(jiān)控信息分析,故障時間區(qū)間,系統(tǒng)運行的線程略高 31616,但是該值卻沒有超過當前用戶的 ulimit -u 的值,初步排除該線索。

          2、根據(jù)系統(tǒng)拋出的錯誤提示,Google 一把 fork: Resource temporarily unavailable,找到了一個貼子:https://github.com/awslabs/amazon-eks-ami/issues/239 [1],在整個帖子看到一條這樣的提示:

          One possible cause is running out of process IDs. Check you don't  have 40.000 defunct processes or similar on nodes with problems

          3、于是根據(jù)該線索,翻閱 linux 內(nèi)核文檔,搜索 PID 相關(guān)字段,其中找到如下相關(guān)的 PID 參數(shù):

          • kernel.core_uses_pid = 1

            ?

            引用官方文檔 https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#core-uses-pid

            參數(shù)大致意思是為系統(tǒng) coredump 文件命名,實際生成的名字為 “core.PID”,則排除該參數(shù)引起的問題。

          • kernel.ns_last_pid = 23068

            ?

            引用官方文檔 https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#ns-last-pid

            參數(shù)大致意思是,記錄當前系統(tǒng)最后分配的 PID identifiy,當 kernel fork 執(zhí)行下一個 task 時,kernel 將從此 pid 分配 identify。

          • kernel.pid_max = 32768

            ?

            引用官方文檔 https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#pid-max

            參數(shù)大致意思是,kernel 允許當前系統(tǒng)分配的最大 PID identify,如果 kernel  在 fork 時 hit 到這個值時,kernel 會 wrap back 到內(nèi)核定義的 minimum PID  identify,意思就是不能分配大于該參數(shù)設(shè)定的值+1,該參數(shù)邊界范圍是全局的,屬于系統(tǒng)全局邊界。

            通過該參數(shù)的闡述,大致問題定位到了,在 linux 中其實 thread & process 的創(chuàng)建都會被該參數(shù)束縛,因為無論是線程還是進程結(jié)構(gòu)體基本上一樣的,都需要 PID 來標識

          • user.max_pid_namespaces = 253093

            ?

            引用官方文檔 https://www.kernel.org/doc/html/latest/admin-guide/sysctl/user.html#max-pid-namespaces

            參數(shù)大致意思是,在當前所屬用戶 namespace 下允許該用戶創(chuàng)建的最大的 PID,意思應(yīng)該是最大進程吧,等同于參數(shù) ulimit  -u 的值,由內(nèi)核初始化而定義的,具體算法應(yīng)該是(init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2)。

          • kernel.cad_pid = 1

            ?

            引用官方文檔 https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#cad-pid

            參數(shù)大致意思是,向系統(tǒng)發(fā)送 reboot 信號,特別針對于 ctrl+alt+del,對于該參數(shù)不需要理解太多,用不到。

          4、查看系統(tǒng)內(nèi)核參數(shù) kernel.pid_max,如下:

          ?

          關(guān)于該參數(shù)的初始值是如何計算的,下面會分析的。

          $ sysctl -a | grep pid_max
          kernel.pid_max = 32768

          5、返回系統(tǒng)中,需要定位是哪個應(yīng)用系統(tǒng) create 如此之多的線程,如下(推薦安裝監(jiān)控系統(tǒng),用于記錄監(jiān)控數(shù)據(jù)信息):

          通常網(wǎng)上的教程都是盲目的調(diào)整對應(yīng)的內(nèi)核參數(shù)值,個人認為運維所有操作都是被動的,不具備根治問題,需要從源頭解決問題,最好是拋給研發(fā),在應(yīng)用系統(tǒng)初始化,create 適當?shù)木€程量。

          具體如何優(yōu)化內(nèi)核參數(shù),下面來分析。

          參數(shù)分析

          相關(guān)內(nèi)核參數(shù)詳細說明,及如何調(diào)整,及相互關(guān)系,及計算方式,參數(shù)邊界,如下說明:

          kernel.pid_max

          概念就不詳述了,參考上文(大致意思就是,系統(tǒng)最大可分配的 PID identify,理解有點抽象,嚴格意義是最大標識,每個進程的標識符,當然也代表最大進程吧)。

          話不多說,分析源代碼,如有誤,請指出。

          int pid_max = PID_MAX_DEFAULT;

          #define RESERVED_PIDS        300

          int pid_max_min = RESERVED_PIDS + 1;
          int pid_max_max = PID_MAX_LIMIT;

          代碼地址:https://github.com/torvalds/linux/blob/v5.11-rc1/kernel/pid.c

          上面代碼表示,pid_max 默認賦值等于 PID_MAX_DEFAULT 的值,但是初始創(chuàng)建的 PID identify 是 RESERVD_PIDS + 1,也就是等于 301,小于等于 300 是系統(tǒng)內(nèi)核保留值(可能是特殊使用吧)

          那么 PID_MAX_DEFAULT 的值是如何計算的及初始化時是如何定義的及默認值、最大值,及 LIMIT 的值的呢?具體 PID_MAX_DEFAULT 代碼如下:

          /*
           * This controls the default maximum pid allocated to a process
           * 大致意思就是,如果在編譯內(nèi)核時指定或者為CONFIG_BASE_SMALl賦值了,那么默認值就是4096,反而就是32768
           */

          #define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)

          /*
           * A maximum of 4 million PIDs should be enough for a while.
           * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]
           * 如果CONFIG_BASE_SMALL被賦值了,則最大值就是32768,如果條件不成立,則判斷l(xiāng)ong的類型通常應(yīng)該是操作系統(tǒng)版本,如果大于4字節(jié),取值范圍大約就是4 million,精確計算就是4,194,304,如果條件還不成立則只能取值最被設(shè)置的PID_MAX_DEFAULT的值
           */

           
          #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
              (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))

          代碼地址:linux/threads.h at v5.11-rc1 · torvalds/linux · GitHub[2]

          但是翻閱 man proc 的官方文檔,明確說明:如果 OS 為 64 位系統(tǒng) PID_MAX_LIMIT 的邊界值為 2 的 22 次方,精確計算就是 210241024*1024 等于 1,073,741,824,10 億多。而 32BIT 的操作系統(tǒng)默認就是 32768

          如何查看 CONFIG_BASE_SMALL 的值,如下:

          $ cat /boot/config-5.11.1-1.el7.elrepo.x86_64 | grep CONFIG_BASE_SMALL
          CONFIG_BASE_SMALL=0

          0 代表未被賦值。

          kernel.threads-max

          參考文檔:Documentation for /proc/sys/kernel/ — The Linux Kernel documentation[3]

          該參數(shù)大致意思是,系統(tǒng)內(nèi)核 fork() 允許創(chuàng)建的最大線程數(shù),在內(nèi)核初始化時已經(jīng)設(shè)定了此值,但是即使設(shè)定了該值,但是線程結(jié)構(gòu)只能占用可用 RAM page 的一部分,約 1/8(注意是可用內(nèi)存,即 Available memory  page), 如果超出此值 1/8 則 threads-max 的值會減少

          內(nèi)核初始化時,默認指定最小值為 MIN_THREADS = 20,MAX_THREADS 的最大邊界值是由 FUTEX_TID_MASK 值而約束,但是在內(nèi)核初始化時,kernel.threads-max 的值是根據(jù)系統(tǒng)實際的物理內(nèi)存計算出來的,如下代碼:

          /*
           * set_max_threads
           */

          static void set_max_threads(unsigned int max_threads_suggested)
          {
              u64 threads;
              unsigned long nr_pages = totalram_pages();

              /*
               * The number of threads shall be limited such that the thread
               * structures may only consume a small part of the available memory.
               */

              if (fls64(nr_pages) + fls64(PAGE_SIZE) > 64)
                  threads = MAX_THREADS;
              else
                  threads = div64_u64((u64) nr_pages * (u64) PAGE_SIZE,
                              (u64) THREAD_SIZE * 8UL);

              if (threads > max_threads_suggested)
                  threads = max_threads_suggested;

              max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS);
          }

          代碼地址:linux/fork.c at v5.16-rc1 · torvalds/linux · GitHub[4]

          kernel.threads-max 該參數(shù)一般不需要手動更改,因為在內(nèi)核根據(jù)現(xiàn)在有的內(nèi)存已經(jīng)算好了,不建議修改

          那么 kernel.threads-max 由 FUTEX_TID_MASK 常量所約束,那它的具體值是多少呢,代碼如下:

          #define FUTEX_TID_MASK        0x3fffffff

          代碼地址:linux/futex.h at v5.16-rc1 · torvalds/linux · GitHub[5]

          vm.max_map_count

          參考文檔:Documentation for /proc/sys/vm/ — The Linux Kernel documentation[6]

          這個參數(shù)大致意思是,允許系統(tǒng)進程最大分配的內(nèi)存 MAP 區(qū)域,一般應(yīng)用程序占用少于 1000 個 map,但是個別程序,特別針對于被 malloc 分配,可能會大量消耗,每個 allocation 會占用一到二個 map,默認值為 65530。

          通過設(shè)定此值可以限制進程使用 VMA(虛擬內(nèi)存區(qū)域) 的數(shù)量。虛擬內(nèi)存區(qū)域是一個連續(xù)的虛擬地址空間區(qū)域。在進程的生命周期中,每當程序嘗試在內(nèi)存中映射文件,鏈接到共享內(nèi)存段,或者分配堆空間的時候,這些區(qū)域?qū)⒈粍?chuàng)建。調(diào)優(yōu)這個值將限制進程可擁有 VMA 的數(shù)量。限制一個進程擁有 VMA 的總數(shù)可能導(dǎo)致應(yīng)用程序出錯,因為當進程達到了 VMA 上線但又只能釋放少量的內(nèi)存給其他的內(nèi)核進程使用時,操作系統(tǒng)會拋出內(nèi)存不足的錯誤。如果你的操作系統(tǒng)在 NORMAL 區(qū)域僅占用少量的內(nèi)存,那么調(diào)低這個值可以幫助釋放內(nèi)存給內(nèi)核用參數(shù)大致作用就是這樣的。

          可以總結(jié)一下什么情況下,適當?shù)脑黾樱?/p>

          • 壓力測試,壓測應(yīng)用程序最大 create 的線程數(shù)量;
          • 高并發(fā)的應(yīng)用系統(tǒng),單進程并發(fā)非常高。

          參考文檔:

          • http://www.kegel.com/c10k.html#limits.threads
          • https://listman.redhat.com/archives/phil-list/2003-August/msg00005.html
          • https://bugzilla.redhat.com/show_bug.cgi?id=1459891

          配置建議

          參數(shù)邊界

          參數(shù)名稱范圍邊界
          kernel.pid_max系統(tǒng)全局限制
          kernel.threads-max系統(tǒng)全局限制
          vm.max_map_count進程級別限制
          /etc/security/limits.conf用戶級別限制

          總結(jié)建議

          1. kernel.pid_max 約束整個系統(tǒng)最大 create 的線程與進程數(shù)量,無論是線程還是進程,都不能 hit 到此設(shè)定的值,錯誤有二種(create 接近拋出 Resource temporarily unavailable,create 大于拋出 No more processes...);可以根據(jù)實際應(yīng)用場景及應(yīng)用平臺修改此值,比如 Kubernetes 平臺,一個節(jié)點可能運行上百 Container instance,或者是高并發(fā),多線程的應(yīng)用。
          2. kernel.threads-max 只針對事個系統(tǒng)所有用戶的最大他 create 的線程數(shù)量,就大于系統(tǒng)所有用戶設(shè)定的 ulimit  -u 的值,最好 ulimit -u  精確的計算一下(不推薦手動修改該參數(shù),該參數(shù)是由在內(nèi)核初始化系統(tǒng)算出來的結(jié)果,如果將其放大可以會造成內(nèi)存溢出,一般系統(tǒng)默認值不會被 hit 到)。
          3. vm.max_map_count 是針對系統(tǒng)單個進程允許被分配的 VMA 區(qū)域,如果在壓測時,會有二種情況拋出(線程不夠 11=no more threads allowed,資源不夠 12 = out of  mem.)但是此值了不能設(shè)置的太大,會造成內(nèi)存開銷,回收慢;此值的調(diào)整,需要根據(jù)實際壓測結(jié)果而定(常指可以被 create 多少個線程達到飽和)。
          4. limits.conf 針對用戶級別的,在設(shè)置此值時,需要考慮到上面二個全局參數(shù)的值,用戶的 total 值(不管是 nproc  還是 nofile)不能大于與之對應(yīng)的 kernel.pid_max & kernel.threads-max &  fs.file-max。
          5. Linux 通常不會對單個 CPU 的 create 線程數(shù)做上限,過于復(fù)雜,個人認為內(nèi)存不好精確計算吧。

          引用鏈接

          [1]

          https://github.com/awslabs/amazon-eks-ami/issues/239 : https://github.com/awslabs/amazon-eks-ami/issues/239

          [2]

          linux/threads.h at v5.11-rc1 · torvalds/linux · GitHub: https://github.com/torvalds/linux/blob/v5.11-rc1/include/linux/threads.h

          [3]

          Documentation for /proc/sys/kernel/ — The Linux Kernel documentation: https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#threads-max

          [4]

          linux/fork.c at v5.16-rc1 · torvalds/linux · GitHub: https://github.com/torvalds/linux/blob/v5.16-rc1/kernel/fork.c

          [5]

          linux/futex.h at v5.16-rc1 · torvalds/linux · GitHub: https://github.com/torvalds/linux/blob/v5.16-rc1/include/uapi/linux/futex.h

          [6]

          Documentation for /proc/sys/vm/ — The Linux Kernel documentation: https://www.kernel.org/doc/html/latest/admin-guide/sysctl/vm.html#max-map-count




          你可能還喜歡

          點擊下方圖片即可閱讀

          輕量級云原生日志收集方案 Loki

          2022-10-27

          WASM 將引領(lǐng)下一代計算范式!

          2022-10-24

          汽車智能計算平臺公司「地平線」在 Ingress Controller 的探索和實踐

          2022-10-20

          國內(nèi)外云廠商容器服務(wù)備份恢復(fù)方案調(diào)研

          2022-10-19


          云原生是一種信仰 ??

          關(guān)注公眾號

          后臺回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!



          點擊 "閱讀原文" 獲取更好的閱讀體驗!


          發(fā)現(xiàn)朋友圈變“安靜”了嗎?

          瀏覽 123
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  第四色俺也去 | 国产淫色色色 | 操必毛片| 亚洲AV成人无码精品直播在线 | 亚洲成人导航在线 |