微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

linux – 当’正确’时,PID文件是否仍有缺陷?

重新启动服务通常通过PID文件实现 – 即.进程ID写入某个文件,并根据该数字,stop命令将终止进程(或重启之前).

当你考虑它时(或者如果你不喜欢它,那么search)你会发现这是有问题的,因为每个PID都可以重复使用.想象一下完整的服务器重启,你在启动时调用’./your-script.sh start'(例如crontab中的@reboot).现在你的-script.sh会杀死一个任意的PID,因为它在重启之前已经存储了PID.

我能想象的一个解决方法是存储一个额外的信息,这样你就可以做’ps -pid | grep’并且只有当它返回你杀死它的东西时.或者在可靠性和/或简单性方面有更好的选择吗?

#!/bin/bash

function start() {
  nohub java -jar somejar.jar >> file.log 2>&1 &
  PID=$!
  # one Could even store the "ps -$PID" @R_462_4045@ion but this makes the
  # killing too specific e.g. if some arguments will be added or similar
  echo "$PID somejar.jar" > $PID_FILE
}

function stop() {
  if [[ -f "$PID_FILE" ]]; then
    PID=$(cut -f1 -d' ' $PID_FILE)
    # Now get the second @R_462_4045@ion and grep the process list with this
    PID_INFO=$(cut -f2 -d' ' $PID_FILE)
    RES=$(ps -$PID | grep $PID_INFO)
    if [[ "x$RES" != "x" ]]; then
       kill $PID
    fi
  fi
}

解决方法:

PID文件的问题是多方面的,不仅限于回收和重启.

更大的问题是PID文件中的信息与进程状态之间存在不可避免的断开/竞争.

这是使用PID文件的流程:

>你叉子和执行一个过程. “父”进程知道fork的PID,并保证该PID专门为其fork保留.
>您的父级将fork的PID写入文件.
>你的父母死了,同时保证了PID排他性.
>另一个进程读取PID文件中的数字.
>不同的进程检查系统上是否存在与读取的PID相同的进程.
>不同的进程使用他读取的PID向进程发送信号.

在(1)一切都很好,花花公子.我们有一个PID,内核保证我们的数据是为我们的预期进程保留的.

在(2)中,您将控制PID到其他没有此保证的进程.本身不是一个问题,但这种行为很少,如果没有错.

在(3)中,您的父进程终止.它本身就具有PID独占性的核心保证.它可能会也可能没有对PID进行等待(2).预期过程的真实状态将丢失,我们剩下的只是PID文件中的标识符,该标识符可能会或可能不会引用预期的过程.

在(4)中,没有任何保证的过程读取PID文件,任何使用这个数字只能获得任意成功.

在(5)中,没有任何保证的进程实际上使用了标识符,这是我们实际做坏事的第一点:我们使用可能会或可能不会引用预期进程的进程标识符来查询内核.我们将得到的答案将取决于具有该PID的过程的状态,而不一定是我们预期的过程.

在(6)中我们犯了最大的错误:我们实际上正在执行一个变异动作,旨在影响我们最初启动的过程,但决不能保证这个意图.我们可以发信号通知任何随机系统过程.

为什么是这样?什么样的东西可以发生混乱PID?

在(1)之后的任何地方,真正的过程可能会死亡.只要父母保留对PID独占性的保证,内核就不会回收PID.它仍然存在并且引用过去的过程(我们将其称为“僵尸”过程,您的真实过程已经死亡,但PID仍然仅为其保留).没有其他过程可以使用此PID并发出信号,它根本不会到达任何进程.

一旦父母发布他的保证或在(3)之后,内核就会回收死进程的PID.僵尸已经消失,PID现在可以被任何其他分叉的新进程使用.假设您正在编译某些东西,会产生数千个小进程.内核为每个内核选择随机或顺序(取决于其配置)的新PID.你已经完成了,现在你重启了apache.内核重用了死进程的释放PID,用于重要的事情.

但是,PID文件仍然包含PID.任何读取PID文件(4)的进程都假设这个数字指的是你的长时间进程.

您使用所读数字执行的任何操作(5)(6)将以新进程为目标,而不是旧进程.

不仅如此,您还不能在行动之前执行任何检查,因为您可以执行的任何检查与您可以执行的任何操作之间存在不可避免的竞争.如果你第一次看ps来看看你的过程的“名称”是什么(不是这是一个真正令人敬畏的保证,请不要这样做),然后发出信号,你的ps检查和你之间的时间信号仍然可以看到过程死亡,和/或通过新过程回收.所有这些问题的根源是内核没有给你任何PID的独占使用保证,因为你不是它的父.

故事的道德:不要将你孩子的PID给别人.父级和只有父级应该使用它,因为他是系统中唯一一个(保存内核)对其存在和身份的任何保证.

这通常意味着保持父亲的生命,而不是发出信号来终止过程,而是与父母交谈;借助于插座等.见http://smarden.org/runit/等.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐