零停机时间的目标,如何使用 upstart with sockets & (g)unicorn:
Goal of zero downtime, how to use upstart with sockets & (g)unicorn:
我的目标是电子商务应用程序的零停机部署,我正在以最佳方式尝试实现这一目标。
我在 nginx/unicorn/django 设置和单独服务器的 nginx/unicorn/rails 设置上执行此操作。
我的策略是在我的 guincorn.py
/unicorn.rb
文件中设置 preload_app=true
,然后通过向 PID 运行 服务器发送一个 USR2 信号来重新加载。这会分叉进程及其子进程,并且 pre_fork
/before_fork
可以接收并发送后续的 QUIT 信号。
这是我的 pre_fork 在 guincorn 版本中所做的示例:
# ...
pidfile='/opt/run/my-website/my-website.pid'
# socket doesn't come back after QUIT
bind='unix:/opt/run/my-website/my-website.socket'
# works, but I'd prefer the socket for security
# bind='localhost:8333'
# ...
def pre_fork(server, worker):
old_pid_file = '/opt/run/my-website/my-website.pid.oldbin'
if os.path.isfile(old_pid_file):
with open(old_pid_file, 'r') as pid_contents:
try:
old_pid = int(pid_contents.read())
if old_pid != server.pid:
os.kill(old_pid, signal.SIGQUIT)
except Exception as err:
pass
pre_fork=pre_fork
这里是我执行重新加载的 sysv 脚本的选择:
DESC="my website"
SITE_PATH="/opt/python/my-website"
ENV_PATH="/opt/env/my-website"
RUN_AS="myuser"
SETTINGS="my.settings"
STDOUT_LOG="/var/log/my-website/my-website-access.log"
STDERR_LOG="/var/log/my-website/my-website-error.log"
GUNICORN="/opt/env/my-website/bin/gunicorn.py"
CMD="$ENV_PATH/bin/python $SITE_PATH/manage.py run_gunicorn -c $GUNICORN >> $STDOUT_LOG 2>>$STDERR_LOG"
sig () {
test -s "$PID" && kill - `cat $PID`
}
run () {
if [ "$(id -un)" = "$RUN_AS" ]; then
eval
else
su -c "" - $RUN_AS
fi
}
reload () {
echo "Reloading $DESC"
sig USR2 && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$DESC' instead"
run "$CMD"
}
action=""
case $action in
reload)
reload
;;
esac
我选择了 preload_app=true,因为零停机时间的诉求。由于工作人员已将应用程序预加载到内存中,因此只要我正确切换进程,它应该会模拟零停机结果。反正就是这么想的。
这在我通过端口收听的地方有效,但我无法通过套接字使其正常工作。
我的问题如下:
- 你们其他人也是这样做的吗?
- 有没有更好的方法,比如HUP?我的理解是你不能将
preload_app=true
与 HUP 一起使用。
- 是否可以使用套接字来做到这一点?我的套接字在退出时一直消失,再也没有回来。我的想法是套接字更安全,因为您必须有权访问文件系统。
- 有人用
upstart
而不是 sysv
做这个吗?理想情况下,我很想这样做,我看到 an interesting way of accomplishing that 通过聚集 PID。这对 upstart 来说是一个挑战,因为一旦 gunicorn/unicorn 的 exec-fork 接管,upstart 就不再监视它最初管理的进程,需要以某种方式重新建立。
你应该看看我在 GDS 的同事 unicornherder,这是专门为管理这个问题而设计的:
Unicorn Herder is a utility designed to assist in the use of Upstart and similar supervisors with Unicorn.
我的目标是电子商务应用程序的零停机部署,我正在以最佳方式尝试实现这一目标。
我在 nginx/unicorn/django 设置和单独服务器的 nginx/unicorn/rails 设置上执行此操作。
我的策略是在我的 guincorn.py
/unicorn.rb
文件中设置 preload_app=true
,然后通过向 PID 运行 服务器发送一个 USR2 信号来重新加载。这会分叉进程及其子进程,并且 pre_fork
/before_fork
可以接收并发送后续的 QUIT 信号。
这是我的 pre_fork 在 guincorn 版本中所做的示例:
# ...
pidfile='/opt/run/my-website/my-website.pid'
# socket doesn't come back after QUIT
bind='unix:/opt/run/my-website/my-website.socket'
# works, but I'd prefer the socket for security
# bind='localhost:8333'
# ...
def pre_fork(server, worker):
old_pid_file = '/opt/run/my-website/my-website.pid.oldbin'
if os.path.isfile(old_pid_file):
with open(old_pid_file, 'r') as pid_contents:
try:
old_pid = int(pid_contents.read())
if old_pid != server.pid:
os.kill(old_pid, signal.SIGQUIT)
except Exception as err:
pass
pre_fork=pre_fork
这里是我执行重新加载的 sysv 脚本的选择:
DESC="my website"
SITE_PATH="/opt/python/my-website"
ENV_PATH="/opt/env/my-website"
RUN_AS="myuser"
SETTINGS="my.settings"
STDOUT_LOG="/var/log/my-website/my-website-access.log"
STDERR_LOG="/var/log/my-website/my-website-error.log"
GUNICORN="/opt/env/my-website/bin/gunicorn.py"
CMD="$ENV_PATH/bin/python $SITE_PATH/manage.py run_gunicorn -c $GUNICORN >> $STDOUT_LOG 2>>$STDERR_LOG"
sig () {
test -s "$PID" && kill - `cat $PID`
}
run () {
if [ "$(id -un)" = "$RUN_AS" ]; then
eval
else
su -c "" - $RUN_AS
fi
}
reload () {
echo "Reloading $DESC"
sig USR2 && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$DESC' instead"
run "$CMD"
}
action=""
case $action in
reload)
reload
;;
esac
我选择了 preload_app=true,因为零停机时间的诉求。由于工作人员已将应用程序预加载到内存中,因此只要我正确切换进程,它应该会模拟零停机结果。反正就是这么想的。
这在我通过端口收听的地方有效,但我无法通过套接字使其正常工作。
我的问题如下:
- 你们其他人也是这样做的吗?
- 有没有更好的方法,比如HUP?我的理解是你不能将
preload_app=true
与 HUP 一起使用。 - 是否可以使用套接字来做到这一点?我的套接字在退出时一直消失,再也没有回来。我的想法是套接字更安全,因为您必须有权访问文件系统。
- 有人用
upstart
而不是sysv
做这个吗?理想情况下,我很想这样做,我看到 an interesting way of accomplishing that 通过聚集 PID。这对 upstart 来说是一个挑战,因为一旦 gunicorn/unicorn 的 exec-fork 接管,upstart 就不再监视它最初管理的进程,需要以某种方式重新建立。
你应该看看我在 GDS 的同事 unicornherder,这是专门为管理这个问题而设计的:
Unicorn Herder is a utility designed to assist in the use of Upstart and similar supervisors with Unicorn.