reload and restart

很早以前在电脑上插入U盘还需要重启系统,那时候大家都很能忍。后来有了热插拔技术才解决这个难题,这种技术让电子设备可以在不影响操作系统和程序正常运行的情况下重新加载硬件,后来软件上也开始使用这种技术,我们称之为热更新(reload)。

restart很好理解,就是重启,比如重启手机,重启电脑。重启会让系统停止运行。Windows系统重启至少需要半分钟,在这半分钟的时间里你只能盯着屏幕发呆……

这两个看似平淡无奇的命令隐含着无数技术细节。今天说说通过软件实现reload和restart有哪些不为人知的细节。

kill命令

这一切都要从kill命令说起。kill,英语中为杀死的意思,顾名思义就是用来杀死一些东西的命令,程序员们常用来杀死系统中的进程。

插入一则笑话:

A:紫禁城好大
B:哪个子进程?快杀了他

kill命令的设计者为如何『杀死』进程,提供了很多种参数,比如(只介绍两个通用的):

-g 杀死进程组
-w 等待进程死亡 

kill命令的重点不在于参数而在于信号,kill命令可以通过发送指定的信号到相应进程,实现外接和进程之间的单向通信。就像遥控器和电视,遥控器可以发送信号给电视,但电视不能发送信号给遥控器。通过kill命令的信号机制我们就能实现给程序所在的进程发送信号,让程序重启或者更新。

kill信号一共64个,这里只介绍10个:

1. SIGHUP   
2. SIGINT     
3. SIGQUIT     
4. SIGILL     
5. SIGTRAP
6. SIGABRT
7. SIGBUS     
8. SIGFPE     
9. SIGKILL    
10. SIGUSR1

kill命令的使用是kill -信号 进程编号,比如nginx reload 其实调用的是kill -USR1 9527 ,其中9527是nginx服务的进程编号,通常存储于nginx.pid文件中。

因为nginx源代码中对SIGUSR1信号做了接收和处理,所以通过kill -USR1 9527能实现热更新,kill命令写起来不直观,于是nginx封装了一层,在我们执行nginx reload时自动转换为kill -USR1 9527命令。

restart VS reload

restart的优缺点:

缺点: restart = stop + start,stop之后服务会中断。

优点: 解决内存泄露和资源锁的问题;

reload的优缺点:

缺点:无法解决内存泄露和资源锁的问题;

优点:不中断服务,速度快;

restart的实现细节

nginx程序并不自带restart命令,因为这个命令有风险。不止nginx程序没有,一些主流的程序都没有restart命令,比如MySQL,ElasticSearch,php-fpm等等。为什么没有?

为了拥有restart命令,很多人会选择注册服务的方式来实现,比如nginx注册成服务之后就能使用service nginx restart命令来实现重启,下面是service nginx restart命令的源码:

1
2
3
4
5
6
restart() {
configtest || return $?
stop
sleep 1
start
}

代码中有sleep 1命令,含义是等待nginx stop命令结束后休眠1秒,画重点,这就是主流程序都无法跨过的风险点。

假如stop命令运行了2秒才结束,start命令会提示端口被占用(处理不好的甚至会出现雪崩)。此时服务已经停止了,但是没启动起来(2秒才结束,1秒的时候运行的起来就是见鬼了)……你心跳加快,马上执行start,运气好的话你能成功,此时服务中断5秒。运气不好的话可能服务中断一小时,这一年肯定白干了。

如果运气再背一点,比如集群部署时,60台机器restart有10台stop超过2秒……是选择回滚代码还是卷铺盖滚回家?

最后,请不要嘲笑那些请高僧来给服务器开光的公司,计算机中很多问题就是会莫名其妙发生。对于常用 service XX restart 命令的人来说,信仰必须要有,不然墨菲定律伴你左右。