运维 使用 Upstart + Inspeqtor 管理你的 Sidekiq (监控、崩溃自动重启、邮件通知)

lokyoung · 2016年04月17日 · 最后由 sdfsd 回复于 2020年10月02日 · 15512 次阅读
本帖已被管理员设置为精华贴

前言

最近在工作中碰到一个问题,服务器上的 Sidekiq 崩溃之后,由于我们在服务器端并没有对 Sidekiq 进行监控和管理,当察觉到 Sidekiq 进程崩溃时已经有大量的 background job 停留在队列中无法执行。 这无疑是一件相当痛苦的事,所以我开始找寻办法去解决这一问题。 而实际上,Sidekiq 的作者就已经给出了最好的解决方案 (可以参考他博客的文章Sidekiq and Upstart)——用 Ubuntu 自带的Upstart去保证 Sidekiq 不会因为 Ruby 虚拟机崩溃等原因停止工作,用Inspeqtor结合 Upstart 去监控你的 Sidekiq(Sidekiq 进程失败时发送邮件通知)。

Upstart

简介

Upstart 是 Ubuntu 系统自带的基于事件的初始化常驻程序,可以在系统开机和关机时启动和关闭服务,在系统运行时对服务进行监督。 Upstart 可以让被监督的进程在非正常关闭时,自动重启该进程,保证其在系统中正常稳定地运行。 可以使用系统自带的工具去解决问题,相比较使用第三方工具而言,无疑是更好的方式。所以我选择了 Upstart 来管理服务器上的 Sidekiq 进程。
PS: Upstart 除了可以在 Ubuntu 系统上使用外,在 Debian、Fedora、openSUSE、Chrome OS 等发行版上也有相关支持。而在最近两年一些 Linux 发行版的新版本中(Ubuntu 15.04, CentOS 7 等),可以使用更先进的 Systemd 实现 Upstart 的功能。Upstart 的详细信息,可以参考 Ubuntu 官方的Upstart Cookbook

Upstart 监督 Sidekiq 配置

在服务器的/etc/init 目录下新建一个*.conf文件,在这里我新建了一个名为sidekiq.conf的配置文件。

# /etc/init/sidekiq.conf - Sidekiq config

description "Sidekiq Background Worker"

# 在系统开机时启动服务,关机时关闭服务
start on runlevel [2345]
stop on runlevel [06]

# 在进程崩溃时自动重启进程
respawn
# 30秒之内尝试3次重启,如果失败,则放弃重启
respawn limit 3 30

# 正常退出所接收到的信号,0(Linux程序正常退出码)
# TERM是通过sidekiqctl停止sidekiq时发送的信号
# 除了这两种信号之外,其余任何终止sidekiq的方式都会触发respawn
normal exit 0 TERM

# 通过reload指令向正在运行的进程发送USR1信号(对于Sidekiq来说,USR1意味着停止接收新的background job)
reload signal USR1

# 通过upstart启动的sidekiq实例的序号
instance $index

script
# this script runs in /bin/sh by default
# respawn as bash so we can source in rbenv
exec /bin/bash <<'EOT'
  # Pick your poison :) Or none if you're using a system wide installed Ruby.
  # rbenv
  # source /home/apps/.bash_profile
  # OR
  # source /home/apps/.profile
  # OR system:
  # source /etc/profile.d/rbenv.sh
  #
  # rvm
  # source /home/apps/.rvm/scripts/rvm

  # Logs out to /var/log/upstart/sidekiq.log by default

  cd /var/www/app
  # 注:这里必须在bundle exec前加上exec,否则会在另外一个进程(不受Upstart监控)中开启sidekiq
  # sidekiq -i 的参数和之前传入是实例序号index一致
  exec bundle exec sidekiq -i ${index} -e production
EOT
end script

只需要上面这个简单的配置文件,就完成了 Upstart 中 sidekiq 的配置。接下来,我们需要通过 Upstart 来启动 sidekiq,这样才可以让 sidekiq 进程在 Upstart 的监督下运行。

# 由于在系统中可以开启多个sidekiq进程,所以你可以通过指定sidekiq进程的编号方便你对某一个sidekiq进程进行管理
# 下列启动序号为0的sidekiq实例(在我们我应用中,只需要一个sidekiq进程)
# 启动sidekiq
$ sudo service sidekiq start index=0

# 终止sidekiq
$ sudo service sidekiq stop index=0

# 重启sidekiq
$ sudo service sidekiq restart index=0

在通过 Upstart 的方式启动 sidekiq 之后,sidekiq 进程如果遇到异常情况造成崩溃,之后立刻重生(重新启动一个 sidekiq 进程)。你可以尝试使用 kill 的方式强制关闭 sidekiq,会发现 sidekiq 不会在你的进程列表中消失(pid 会改变)。现在你只能通过以上命令中的 stop 来关闭 sidekiq。

部署

sidekiq 部署的最佳实践,是尽可能早的让 sidekiq 处于 quiet 状态(停止接受新的 job,只处理当前在队列中的 job),并且尽可能晚的重启 sidekiq。 在/etc/init/sidekiq.conf 中我们曾指定过 reload signal USR1,这表示向当前 Upstart 进程发送 reload 命令时,传送一个名为 USR1 的信号过去。USR1 是 sidekiq 系统内置的一个信号量,当 sidekiq 接收到这个信号时,便会进入 quiet 状态。
在你的部署脚本的早期阶段执行以下命令:

$ sudo service sidekiq reload index=0

重启 sidekiq 也十分地方便,使用 Upstart 自带的 restart 即可,restart 命令会停止当前任务,之后再次启动。不过 restart 命令和单纯地先执行 stop 然后执行 start 不一样,restart 命令会保留当前任务停止时的各项配置,在重新启动时从硬盘中读取这些信息。这样就不会造成如果在重启时,如果正好有任务还在队列中执行,却因为重启而停止导致没有执行完的情况了。 在你的部署脚本中尽量靠后的位置运行重启命令:

$ sudo service sidekiq restart index=0

PS: 由于 sudo 需要输入密码,而在自动化部署时无法输入密码。而我们启动 Upstart 是通过 service 的方式,所以可以让部署用户在执行 service 命令时不需要输入密码。 打开 sudo 配置文件:

$ sudo visudo

在打开的配置文件中加上一行(用你的系统用户名替换 current_user)

current_user ALL=NOPASSWD:/usr/sbin/service

Inspeqtor

简介

Inspeqtor 是 Sidekiq 作者自己写的一个监控工具,可以对系统中的开启的服务(通过 init.d, systemd 或者 upstart 启动的进程)进行监控。 同时也可以监控进程的内存占用量和 CPU 使用量。你可以针对不同的进程配置相应的监控规则,在违反这些规则时重启进程或者向你发送邮件告知。 在之前我们通过配置 Upstart 启动 Sidekiq,所以可以使用 Inspeqtor 对 Sidekiq 进程进行监控(这里主要想实现的目标,是在 Sidekiq 崩溃重启时可以收到邮件通知)。

PS:Inspeqtor 和 God, bluepill 等基于 Ruby 的监控工具不同,Inspeqtor 不需要依赖于 Ruby,所以安装也更加方便。

环境搭建和通知邮箱配置

安装

Inspeqtor 的安装教程可以在官方 wiki中找到,在这里我只列出 Ubuntu 系统中的安装方式。

$ curl -L https://bit.ly/InspeqtorDEB | sudo bash
$ sudo apt-get install inspeqtor

命令行基本操作

这里同样参考自 wiki,有兴趣的朋友可以好好研读。 CentOS 6.5 / Ubuntu with Upstart

$ initctl start inspeqtor
$ initctl stop inspeqtor
$ initctl restart inspeqtor

inspeqtor 的 log 会在/var/log/upstart/inspeqtor.log 中输出。

邮箱配置

对发送 email 的配置在 inspeqtor 的全局配置文件/etc/inspeqtor/inspeqtor.conf 中。 可以通过配置 gmail,普通的 smtp 邮箱和服务器本机的 smtp 邮件服务三种方式发送邮件。 这里我列出普通 smtp 邮箱的配置

# /etc/inspeqtor/inspeqtor.conf

send alerts via email with
  username bubba,
  password "correct horse battery staple",
  smtp_server smtp.example.com,
  to_email [email protected],
  tls_port 587

更多的配置可以查看官方 wiki 中的Global Configuration

PS: inspeqtor 标准版只能指定一个收件邮箱,如果你想让多个邮箱接收 inspeqtor 邮件,可以使用邮件组。

监控 sidekiq

我们之前通过使用 Upstart 实现了让 sidekiq 意外崩溃时的自动重生,在这里我们需要的只是在 sidekiq 崩溃重启时发生邮件通知我们。 由于 inspeqtor 默认会在其监控下进程的 pid 改变时发送邮件通知,所以监控 sidekiq 的配置文件非常简单。 新建配置文件/etc/inspeqtor/services.d/sidekiq.inq。

PS: 按道理说,在这里我们只需要添加一个配置文件即可,不需要添加监控规则(因为 pid 改变时会自动发送邮件),但是我尝试过,如果不添加一条监控规则,inspeqtor 是不会对 sidekiq 进行监控的。所以我随意添加了一条 CPU 占用率 2 次大于 95% 时发送邮件通知的规则。

# /etc/inspeqtor/services.d/sidekiq.inq

check service sidekiq
  if cpu:user > 95% for 2 cycles then alert

配置完成后,执行 restart 指令重新启动 inspeqtor 便可以在 sidekiq 进程崩溃时收到邮件。

inspeqtor 部署集成

之前曾经提到过,inspeqtor 在进程的 pid 变化时会触发 alert(发送邮件)。而我们在部署时是会对 sidekiq 进行重启的(pid 会改变),那么在默认情况下,部署时会收到 inspeqtor 发来的通知邮件。很显然,这样的邮件是没有必要的。所以 inspeqtor 提供了针对部署时的指令,可以在应用部署期间暂停对进程的监控,这样就不会收到不必要的通知了。

# 在部署开始时运行这条指令(建议在部署脚本的第一步运行)
$ inspeqtorctl start deploy

# 在部署结束时运行(建议在部署脚本的最后执行)
$ inspeqtorctl finish deploy

PS: inspeqtorctl 默认情况下需要 sudo 才可以执行,可以通过修改 inspeqtor 的 Upstart 配置文件(/etc/init/inspeqtor.conf)指定当前用户所在 group,group 中的用户执行 inspeqtorctl 就不需要输入 sudo 了。

# /etc/init/inspeqtor.conf

setgid current_user_group

参考资料

Sidekiq and Upstart Upstart Cookbook

顶一个!越来越棒了!

#3 楼 @yangbodotnet 哈哈,谢谢支持。你和 David 帮我消除了零回复哈哈。

#5 楼 @embbnux 嗯,而且配置和使用都还挺方便的。

8 楼 已删除

nice article.

#7 楼 @hooooopo 谢谢!对大家有帮助就好!

#9 楼 @xiaoronglv 谢谢,得到认可很开心,个人感觉 Upstart 和 Inspeqtor(二者都不仅仅局限于 Sidekiq)还是挺实用的~

两天后 Ubuntu 16.04(2016 年 4 月 21 日)就会发布,届时 Ubuntu 的 init 会升级为 Systemd,这篇文章可能需要修订一下,或者根据不同的 Ubuntu 版本提供不同的配置建议。

https://github.com/seuros/capistrano-sidekiq#usage 我感觉使用 monit 更方便点。 用 monit 令人比较烦的一点是:在系统里装 monit 默认要 sudo 权限,我手动将 monit 相关的权限全部改成 deploy,然后设置:sidekiq_monit_use_sudo => false, 部署时就不用烦恼了。

很肉麻的说一句,『感谢分享』,最近正要处理相关环节,没想到现在能看到这么及时的经验贴。攒到内存溢出系统崩溃啊!!!!

#18 楼 @kungs 系统自带的进程管理工具已经足够标准且强大了,monit 成了非必需的第三方依赖,而 inspeqtor 做的事情跟系统进程管理工具各负其责,刚刚好不冲突。

#17 楼 @lgn21st 谢谢建议!对于最新 Ubuntu 系统(16.04)的确要不适用了,本文的适用群体应当是 Ubuntu 16.04 之前的系统。是的,Systemd 会是趋势,配置也更加方便。不过现在大部分服务器使用的是旧版本的系统,而服务器系统升级需要很大的成本,所以可能在很长一段时间里,旧版本系统的占有率还是会很高吧~

#19 楼 @liwei78 也谢谢你的支持!看到对大家有帮助,我也非常非常开心!我还是一个新手,如果有哪里疏漏的,也欢迎并且谢谢指正!

#17 楼 @lgn21st 其实当初碰到这个问题不知道怎么解决,还是在社区里搜索 sidekiq 相关问题,然后发现你在一个回答中推荐使用 Upstart/Systemd 并且给出了 Sidekiq 作者的那篇文章,我才去了解然后发现这对我而言几乎是最好的解决方案了。所以感谢!

#24 楼 @lokyoung 目测从下个月开始,Ubuntu 16.04 将会是新开服务器的默认选择,而且会流行至少两年,直到 18.04 发布。

我自己也做了同样的事情,包括研究过 upstart,systemd,以及 Inspeqtor(包括源码),以及小米运营团队开源出来的 open-falcon,但是我比较懒,没有像你一样把这些都写出来 :D

好像 supervisor 来做更简单些

#25 楼 @lgn21st 那看来是要与时俱进了。 啊哈,其实写出来也是让我自己把这些知识巩固下。看到这么多人支持,真心感觉到社区的好!

#26 楼 @huobazi 当时 supervisor 也是备选之一,由于后来使用了 Upstart 就没有去仔细了解了。不过 supervisor 应该仅仅是监控进程并且也需要安装相应的包。而 Upstart 是系统自带的,我们系统中的 Sidekiq 进程直接通过 Upstart 启动,进程本身也算是一个 Upstart 进程,这样解决我觉得更加彻底并且没有依赖。

Cool! 之前也有遇到过这个问题,我们是自己写脚本 10s 去检测一下sidekiq.pid是否存在,如果不存在就重启。

#!/bin/bash

file="/path/to/project/tmp/pids/sidekiq.pid"

while : ;do
    if ps -p `cat $file` >/dev/null; then
        echo "Sidekiq Started"
    else
        echo "Sidekiq Stopped"
        cd /path/to/project
        echo `pwd`
        nohup bundle exec rake sidekiq:restart RAILS_ENV=production >> /path/to/check_sidekiq_log &
    fi
    sleep 10
done

最近也有想把sidekiq的运行状态加到zabbix中去监控。 但是sidekiq为什么会 crash 掉,这个问题还在跟进。

:plus1:

respawn 3 30 处的语法有问题,可以用 init-checkconf /etc/init/sidekiq.conf 检查。有时间更新下:respawn limit 3 30

感谢分享~

#30 楼 @zoker 用 Upstart 吧,用脚本去检测感觉并不是种好的方式。

#30 楼 @zoker 推荐用 Upstart,用了你会发现你根本不需要 PID 文件。

我找出了之前项目中用 upstart 管理 sidekiq 的部署文档,贴到了我的 blog 上,跟 @lokyoung 的版本大同小异。

http://lvguoning.com/2016/04/20/using-upstart-to-manage-sidekiq/

监控方案就跟前端开发一样,框架多,总不够用

#37 楼 @unbug 至少对于 Sidekiq 来说,Upstart 算是最佳实践了。

用 monit 就够了,而且 https://github.com/seuros/capistrano-sidekiq#usage 本身就提供了支持

systemd 是王道,upstart 是要被淘汰的东西。

#39 楼 @vkill kill you dependency....此外现在投入生产环境的 Linux 服务器有很大一部分还不支持 Systemd,所以对现有服务器来说 Upstart 还是一种很好的解决方式。当然,Systemd 是趋势这毋庸置疑。

#34 楼 @lgn21st #40 楼 @lokyoung 😄 感谢建议,看完这篇文章就已经准备改用Upstart

不是有 god 吗?

#42 楼 @tq0fqeu 可以用 Upstart/Systemd 这种系统自带的方式,从进程本身角度解决监控和崩溃重启这些事。相比之下,god 就是不必要的依赖了。

使用了楼主的方式,测试环境一切正常,生产环境报如下异常,不知道各位是否遇到过~

DEBUG [57133839]    start: Unknown job: sidekiq
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as [email protected]: sudo exit status: 1
sudo stdout: Nothing written
sudo stderr: start: Unknown job: sidekiq

感觉 monit 就挺好的。

不错不错

需要 登录 后方可回复, 如果你还没有账号请 注册新账号