每天5分钟,学转《容器实战高手课》容器中的僵尸进程

231 阅读3分钟

Linux 进程状态转化图

top命令查看stat列

  • R running
    • 运行态, 进程正在运行中(即获得了 CPU 资源),或者进程在run queue 队列里 随时可以运行
  • S sleep
    • 睡眠态,进程需要等待某个资源而进入了睡眠状态,要等待的资源可以是一个信号量(Semaphore),或者是磁盘 I/O,这个睡眠状态的进程会被放入到 wait queue 队列里
    • 包括两个子状态
      • 可以被打断的(TASK_INTERRUPTIBLE)显示为 S state
      • 不可被打断的(TASK_UNINTERRUPTIBLE)显示为 D stat
  • Z zombie 僵尸进程, 进程名后面加了 标识

限制容器中的进程数目

一台 Linux 机器上的进程总数目是有限制的。如果超过这个最大值,那么系统就无法创建出新的进程了,比如你想 SSH 登录到这台机器上就不行了。

/proc/sys/kernel/pid_max控制进程总数的最大值

  • Linux 内核在初始化系统的时候,会根据机器 CPU 的数目来设置 pid_max 的值
  • 如果机器中 CPU 数目小于等于 32,那么 pid_max 就会被设置为 32768(32K)
  • 如果机器中的 CPU 数目大于 32,那么 pid_max 就被设置为 N*1204 (N 就是 CPU 数目)

如果容器中的应用创建过多的进程或者出现 bug,就会产生类似 fork bomb 的行为, fork bomb是指在计算机中通过不断建立新进程来消耗系统中的进程资源,容器中的进程数就会把整个节点的可用进程总数给消耗完 所以需要限制每个容器中的最大进程数

什么是僵尸进程?

进程在调用 do_exit() 退出的时候,存在两个状态:

  • 一个是EXIT_DEAD(也就是进程在真正结束退出的那一瞬间的状态)
  • 一个是EXIT_ZOMBIE(这是进程在 EXIT_DEAD 前的一个状态),僵尸进程,也就是处于这个状态中。

它们是怎么产生的?

  • 父进程在创建完子进程之后就不管了,这就是造成子进程变成僵尸进程的原因。
  • 在 Linux 中的进程退出之后,如果进入僵尸状态,需要父进程调用 wait() syscall,去回收僵尸进程占用的系统资源,比如进程号资源

注意:

  • wait() 系统调用是一个阻塞的syscall, 如果父进程的子进程中没有僵尸进程, 父进程就会被阻塞住,
  • waitpid(-1, current_status, WNOHANG) 是非阻塞的syscall

僵尸进程太多会导致什么问题?

  • 进程号资源在宿主机上是有限的,僵尸进程在容器里仍然占据着进程号资源,很有可能会导致新的进程不能运转
  • 如果pids.current == pids.max,也就是已经达到了容器进程号数的上限 会出现“Resource temporarily unavailable”的错误消息