【问题标题】:How to make sure an application keeps running on Linux如何确保应用程序继续在 Linux 上运行
【发布时间】:2008-11-18 13:48:42
【问题描述】:

我正在尝试确保脚本在开发服务器上保持运行。它整理统计数据并提供 Web 服务,因此它应该会持续存在,但一天有几次,它会因未知原因而死掉。当我们注意到我们只是再次启动它时,它是一个痛苦的背后,一些用户没有权限(或专有技术)来启动它。

我的程序员想花几个小时来找出问题的根源,但我的忙碌者认为必须有一种简单的方法来检测应用程序是否未运行,然后重新启动它。

我知道我可以 cron-script ps 通过 grep:

ps -A | grep appname

但同样,我又浪费了一个小时来做​​一些必须已经存在的事情......难道没有一个预制的应用程序可以传递可执行文件(可选地带有参数)并且可以让进程无限期运行?

如果有什么不同,那就是 Ubuntu。

【问题讨论】:

标签: linux


【解决方案1】:

我使用了一个带有 cron 的简单脚本来确保程序正在运行。如果不是,那么它将启动它。这可能不是您正在寻找的完美解决方案,但它很简单并且效果很好。

#!/bin/bash
#make-run.sh
#make sure a process is always running.

export DISPLAY=:0 #needed if you are running a simple gui app.

process=YourProcessName
makerun="/usr/bin/program"

if ps ax | grep -v grep | grep $process > /dev/null
then
    exit
else
    $makerun &
fi

exit

然后每分钟或每 5 分钟添加一个 cron 作业。

【讨论】:

  • 那是天才。它会在重新启动后继续存在,无需安装任何东西。
  • 我自己用过这个,因为它不需要root权限来安装。
  • @User 使用ps ax | grep XXX 只列出你的进程,然后XXX就是它。
  • 作为 cron one-liner,每分钟运行一次:* * * * * ps aux|grep -v grep|grep -q YourProcessName || /usr/bin/program &
  • 注意进程名称不是脚本名称或任何其他进程名称的一部分。
【解决方案2】:

Monit 非常适合:)

您可以编写简单的配置文件来告诉 monit 观看,例如TCP 端口、PID 文件等

monit 将在它监控的进程不可用/使用太多内存/占用 CPU 时间过长/等时运行您指定的命令。它还会弹出一封电子邮件警报,告诉您发生了什么以及它是否可以对此采取任何措施。

我们使用它来保持我们网站的负载运行,同时在出现问题时向我们提供早期警告。

-- 你忠实的员工,Monit

【讨论】:

  • 你如何保持Monit运行?
  • 这个很难学。我只想重新启动一个脚本(而不是一个服务),我阅读了它的文档几个小时但无法弄清楚。
【解决方案3】:

注意:Upstart 处于维护模式,使用 systemd 的 Ubuntu 为 abandoned。有关如何编写服务定义的详细信息,请查看 systemd'manual

由于您使用的是 Ubuntu,您可能对 Upstart 感兴趣,它已经取代了传统的 sysV init。一个关键功能是,如果服务意外死亡,它可以重新启动服务。 Fedora 已经成为新贵,而 Debian 处于实验阶段,因此可能值得研究。

不过,对于这种情况,这可能有点过头了,因为 cron 脚本需要 2 分钟才能实现。

#!/bin/bash
if [[ ! `pidof -s yourapp` ]]; then
    invoke-rc.d yourapp start
fi

【讨论】:

  • 我必须注意,配置 upstart 来管理您的服务并使其保持运行非常简单(您编写小的配置文件)。这个解决方案比任何其他“简单”的基于 cron/shell 脚本的监控更干净、更简单、更好。
  • @thor -(请注意,这是从 2008 年开始的,当时新贵是新的,文档更难获得)。我同意,“简单”的 cron 脚本只是为了说明脚本也不需要复杂来完成这项工作。
  • 我明白了。无论如何,我在发表评论时都赞成你的回答
【解决方案4】:

如果您使用的是基于 systemd 的发行版,例如 Fedora 和最近的 Ubuntu 版本,您可以使用 systemd 的 "Restart" capability 服务。如果它需要由特定用户管理和运行,它可以设置为系统服务或用户服务,在 OP 的特定情况下更可能是这种情况。

重启选项takes one ofnoon-successon-failureon-abnormalon-watchdogon-abortalways

要以用户身份运行它,只需将如下文件放入~/.config/systemd/user/something.service

[Unit]
Description=Something

[Service]
ExecStart=/path/to/something
Restart=on-failure

[Install]
WantedBy=graphical.target

然后:

systemctl --user daemon-reload
systemctl --user [status|start|stop|restart] something

无需 root 权限/修改系统文件,无需 cron 作业,无需安装,非常灵活(请参阅文档中的所有相关服务选项)。

有关使用每用户 systemd 实例的更多信息,另请参阅 https://wiki.archlinux.org/index.php/Systemd/User

【讨论】:

  • 很好的答案,但是 ~/.config/systemd/user/something.service 对我来说有点模棱两可。 “用户”部分是字面意义上的“用户”还是“您的用户名”?如果它是“你的用户名”,我觉得这是多余的,因为你在你的主目录中制作了这个文件。编辑:看起来就像字面上的“用户”
【解决方案5】:

我使用了来自 cron 的“killall -0 programname || /etc/init.d/programname start”。如果进程不存在, kill 将出错。如果它确实存在,它将向进程传递一个空信号(内核将忽略它并且不会打扰传递。)

这个成语很容易记住(恕我直言)。通常我会在我仍在尝试发现服务本身失败的原因时使用它。恕我直言,一个程序不应该只是意外消失:)

【讨论】:

    【解决方案6】:

    把你的运行放在一个循环中——所以当它退出时,它会再次运行...... while(true){ run my app.. }

    【讨论】:

    • 如果脚本因为未知原因而死掉,很可能它也会取消循环脚本,不是吗?
    • 我和 Garath 合作,如果它的系统杀死了长时间运行的进程,那么建议的循环 - 将在应用程序之前开始 - 将首先被杀死。
    • 回答您的两个 cmets:不,如果脚本因未知原因而死,则循环脚本不受影响,因为它在单独的进程中运行 - 但是是的,如果系统随机终止长时间运行过程那么这仍然是一个问题-但是我怀疑情况是否如此。系统的其余部分未报告为受影响,并且充满了其他长时间运行的进程,这些进程也将重新启动(仅提到这个脚本有问题)。
    【解决方案7】:

    由于某种原因,我无法让 Chris Wendt 解决方案正常工作,而且很难调试。这几乎相同,但更容易调试,从模式匹配中排除 bash。调试只需运行:bash ./root/makerun-mysql.sh。在以下使用 mysql-server 的示例中,只需为您的进程替换 processmakerun 的变量值。

    • 像这样创建一个 BASH 脚本 (nano /root/makerun-mysql.sh):
    #!/bin/bash
    process="mysql"
    makerun="/etc/init.d/mysql restart"
    if ps ax | grep -v grep | grep -v bash | grep --quiet $process
    then
        printf "Process '%s' is running.\n" "$process"
        exit
    else
        printf "Starting process '%s' with command '%s'.\n" "$process" "$makerun"
        $makerun
    fi
    exit
    
    • 通过添加适当的文件权限(即chmod 700 /root/makerun-mysql.sh)确保它是可执行的

    • 然后将其添加到您的 crontab (crontab -e):

    # Keep processes running every 5 minutes
    */5 * * * * bash /root/makerun-mysql.sh
    

    【讨论】:

    • 注意,与Chris Wendt的方案相比,这里的脚本不是作为后台任务启动的。
    【解决方案8】:

    daemontools 中的 supervise 工具是我的偏好 - 但 Dan J Bernstein 所写的一切都是我的偏好 :)

    http://cr.yp.to/daemontools/supervise.html

    您必须为您的应用程序启动脚本创建一个特定的目录结构,但使用起来非常简单。

    【讨论】:

      【解决方案9】:

      首先,你如何启动这个应用程序?它会将自己分叉到后台吗?它是从 nohup .. & 等开始的吗?如果是后者,检查它为什么在 nohup.out 中死掉,如果是第一个,则构建日志记录。

      至于您的主要问题:您可以 cron 它,或在后台运行另一个进程(不是最佳选择)并在 bashscript 中使用 pidof,这很容易:

      if [ `pidof -s app` -eq 0 ]; then
          nohup app &
      fi
      

      【讨论】:

        【解决方案10】:

        你可以让它成为一个从 inittab 启动的服务(尽管一些 Linux 已经转移到 /etc/event.d 中更新的东西)。这些内置系统可确保您的服务持续运行,而无需编写自己的脚本或安装新的东西。

        【讨论】:

          【解决方案11】:

          这是 DMD(守护进程监控守护进程)的工作。周围有几个;但是我通常只是编写一个脚本来检查守护程序是否正在运行,如果没有运行,则将其放入 cron 中以每分钟运行一次。

          【讨论】:

            【解决方案12】:

            查看"Unix Hater's Handbook" 的第 9 章(p197 或附近)中引用的“nanny”(该书的 PDF 版本之一)。

            【讨论】:

              【解决方案13】:

              一个不错的简单方法如下:

              1. 如果服务器无法侦听它期望的端口,则将其写入死机
              2. 设置一个 cronjob 以尝试每分钟启动一次服务器

              如果它没有运行它就会启动,如果它正在运行它就不会。在任何情况下,您的服务器都会一直处于运行状态。

              【讨论】:

                【解决方案14】:

                我认为更好的解决方案是您也测试该功能。例如,如果您必须测试 apache,仅测试系统上是否存在“apache”进程是不够的。

                如果你想测试apache是​​否OK,那么尝试下载一个简单的网页,并测试你的唯一代码是否在输出中。

                如果没有,请使用 -9 杀死 apache,然后重新启动。并将邮件发送到根目录(这是一个转发到公司/服务器/项目根目录的邮件地址)。

                【讨论】:

                • 这是真的。其他答案中建议的许多监控解决方案确实提供协议监控。
                【解决方案15】:

                它甚至更简单:

                #!/bin/bash
                
                export DISPLAY=:0
                
                process=processname
                makerun="/usr/bin/processname"
                
                if ! pgrep $process > /dev/null
                then
                    $makerun &
                fi
                

                您必须记住,以确保 processname 是唯一的。

                【讨论】:

                  【解决方案16】:

                  可以像这样安装分钟监控cronjob:

                  crontab -l > crontab;echo -e '* * * * * export DISPLAY=":0.0" && for “eiskaltdcpp-qt”“transmission-gtk”“尼古丁”中的应用程序;执行 ps aux|grep -v grep|grep "$app";done||"$app" &' >> crontab;crontab crontab

                  缺点是您输入的应用名称必须在ps aux|grep "appname" 输出中找到,同时可以使用该名称启动:"appname" &

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-07-02
                    • 1970-01-01
                    相关资源
                    最近更新 更多