【问题标题】:How do I ensure that a process running is the process I expect is running?如何确保正在运行的进程是我期望正在运行的进程?
【发布时间】:2012-09-01 08:34:37
【问题描述】:

上下文

我有一个 linux[1] 系统,它管理着一系列第三方守护进程,它们的交互仅限于 shell[2] 初始化脚本,即只有 {start|restart|stop|status} 可用。

问题

进程可以假定先前运行的进程的 PID,进程的状态通过使用它的 PID 检查是否存在正在运行的进程来检查。

示例

进程 A 使用 PID 123 运行,随后死亡,进程 B 使用 PID 123 进行初始化,并且状态命令以不真实(错误)的“OK”响应。换句话说,我们只从它的 PID 中检查一个进程是否存在,以验证该进程是否正在运行,我们假设如果存在具有该 PID 的进程,它就是有问题的进程。

建议的解决方案

  1. 使用 PID 询问进程,以确保命令/守护程序按照预期的 PID 运行。这个方案的问题是命令和PID都需要匹配;因此需要维护和保持多位信息同步,并增加错误/边缘条件的复杂性。
  2. 将 PID 文件的创建时间与进程的启动时间相关联,如果进程在 PID 文件创建时间的某个增量内,我们可以相当确定命令/守护程序运行是否符合预期。

除了存在使用该 PID 运行的进程之外,是否有一种标准方法来批准进程/PID 文件的真实性? IE。我(作为系统)想知道你(进程)是否正在运行,以及你是否是我认为的你(A 而不是 B)。

假设我们选择实施上面提出的第二种解决方案,PID 创建时间和进程启动时间之间的置信区间/增量是多少是合理的?在这里,合理的意思是类型 1/类型 2 错误之间可接受的折衷。

[1] CentOS/RHEL [2] 重击

【问题讨论】:

  • 不应该在ServerFault上吗?
  • 您可以对第三方守护进程本身进行任何更改吗?如果是这样,您可以使用flock 为守护进程创建一些文件系统锁。
  • 您确定进程 ID 会被立即重用吗?我知道在 Windows 上就是这种情况,但在 Linux 或 UNIX 上我没有观察到。见stackoverflow.com/questions/3446727/…
  • @cdarke 永远不会有相同 PID 的多个实例,问题是一旦进程死亡,它的 PID 可能会被重用。此时,由于异常情况杀死进程而成为孤立的PID文件的存在,用于确定进程是否仍在运行。在这里,一切看起来都很好(进程正在运行),但实际上并不是我们希望找到的进程。
  • @Gary:是的,但我的意思是 PID 不会立即重用(Windows 除外)。如果没有整理操作,则可能会从先前的运行中留下旧的 PID 文件。显然使用 PID 文件来确定进程是否仍在运行是有缺陷的设计。

标签: linux bash shell process pid


【解决方案1】:

文件内容:

/proc/{PID}/cmdline

是用于启动进程的命令行。这是你需要的吗?

【讨论】:

  • 在提议的解决方案 1 中考虑了这一点:它仍然需要我在批准进程时保留 pid & 命令的副本。保留这两种信息虽然合理,但会增加额外的复杂性。
  • 加里,你想要“相当确定”还是“确定”的结果?如果估计和近似结果足够好(只有您可以判断),然后尝试实施您的第二个解决方案,如果您的代码有问题,请将它们发布到 StackOverflow。这是一个编程问答网站,而不是系统管理最佳实践。同时,考虑切换到Daemontools,而不是使用初始化脚本启动。
  • 谢谢你的建议,ghoti。我对两种提议的解决方案都有功能性的演绎;我正在尝试确定是否存在解决此问题的推荐/标准方法。
【解决方案2】:

我的解决方案是捕获命令(通过/proc/PID/cmdline)以及相对开始时间。使用absolute start time(通过ps -p PID -o lstart=)可能会起作用,但您会得到confusing results if your system clock changes(例如,来自NTP 更新或夏令时)。

这是我的实现:

# Prints enough detail to confirm a PID still refers to the same process.
# In other words, even if a PID is recycled by a call to the same process the
# output of this command should still be different. This is not guaranteed
# across reboots.
proc_detail() {
  local pid=${1:?Must specify PID}
  # the process' commandline, if it's running
  # ensures a non-existant PID will never have the same output as a running
  # process, and helps debugging
  cat "/proc/$pid/cmdline" 2> /dev/null && echo
  # this is the number of seconds after boot that the process started
  # https://unix.stackexchange.com/a/274722/19157
  # in theory this could collide if the same process were restarted in the same
  # second and assigned the same PID, but PIDs are assigned in order so this
  # seems acceptably unlikely for now.
  echo "$(($(cut -d. -f1 < /proc/uptime) - \
           $(ps -p "$pid" -o etimes= 2> /dev/null || echo "0")))"
}

我还决定将此输出存储在/dev/shm 中,以便在关机时自动为我清除。还有其他可行的选项(例如 @reboot cronjob),但对于我的用例而言,写到 tmpfs 既简单又干净。

【讨论】:

    【解决方案3】:

    我一直在寻找问题的答案我如何确保一个进程仍然是同一个进程,我想到了问题中的两个解决方案,即一个进程是否可以由元组(pid,命令)或(pid,进程启动时间)唯一标识。但遗憾的是,这两种选择似乎都不够。

    1. (pid, command) 由于 pid 重用而不够用,例如,原始进程可能已被杀死,并且 pid 空闲可重用,具有相同命令行的另一个进程可能已使用该命令启动pid。

    2. (pid,进程启动时间)似乎有问题,启动时间有时会发生少量变化。

    现在,另一个选项来自能够更改进程标题,例如,我们可以将一个随机数放入您的进程标题,并将随机数与 pid 一起存储在一个 pidfile 中。那么当我们要检查进程是否还是同一个进程时,例如杀死它,我们可以检查pid文件的pid的进程标题是否仍然以pid文件中的随机数开头。

    为了说明,请考虑这个简短的 python sn-p,类似的功能应该可以通过其他语言的库获得:

    #!/usr/bin/env python3
    import os, setproctitle
    nonce = bytes.hex(os.urandom(8))                      # create hex nonce
    setproctitle.setproctitle(nonce + " " + setproctitle.getproctitle()) # set title
    with open("run.pid", "w"): f.write(pid + " " + nonce) # store pid and nonce in pidfile
    

    连同这个shell脚本一起杀掉进程,如果还是一样的话。

    #!/bin/sh
    PID=$(cat run.pid | cut -f1 -d" ")     # get pid from pidfile
    NONCE1=$(cat run.pid | cut -f2- -d" ") # get nonce from pidfile
    NONCE2="$(ps -p "$PID" -o command= 2> /dev/null | cut -f1 -d" ")" # get nonce from process title
    if [ "$NONCE1" = "$NONCE2" ]; then     # if nonces equal
      kill "$PID"                          # kill process
      echo "killed"
    else                                   # otherwise the process you wanted to kill
      echo "was already dead"              # has been dead anyway
    fi
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 2015-06-10
      • 1970-01-01
      • 2011-07-09
      • 2018-02-08
      相关资源
      最近更新 更多