在 Linux 上开发时,往往需要将自己的程序做成服务(获取其他中间件服务,如:nginx、tomcat、mysql 等等),并且实现服务开机自动重启,以及服务崩溃后自动重启功能,本文就对该功能的实现做简单介绍,实现方法很简单,使用 Linux 系统的 systemd 即可实现。
历史上,Linux 的启动一直采用 init 进程,比如:
$ sudo /etc/init.d/apache2 start
或者
$ service apache2 start
但是,这种方法有两个缺点:
缺点一:启动时间长。init 进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
缺点二:启动脚本复杂。init 进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
systemd 就是为了解决这些问题而诞生的。
systemd 的设计目标是,为系统的启动和管理提供一套完整的解决方案。根据 Linux 惯例,字母 d 是守护进程(daemon)的缩写。
systemd 这个名字的含义,就是它要守护整个系统。使用了 Systemd,就不需要再用 init 了。
Systemd 取代了initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。
systemctl 是 Systemd 的主命令,用于管理系统。对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service):
立即启动一个服务:systemctl start apache.service
立即停止一个服务:systemctl stop apache.service
重启一个服务:systemctl restart apache.service
杀死一个服务的所有子进程:systemctl kill apache.service
重新加载一个服务的配置文件:systemctl reload apache.service
重载所有修改过的配置文件:systemctl daemon-reload
显示某个 Unit 的所有底层参数:systemctl show httpd.service
显示某个 Unit 的指定属性的值:systemctl show -p CPUShares httpd.service
设置某个 Unit 的指定属性:systemctl set-property httpd.service CPUShares=500
这里我们写一个 php 的服务脚本 server.php,用来实现一个服务。脚本如下:
<?php $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); socket_bind($sock, '0.0.0.0', 10000); for (;;) { socket_recvfrom($sock, $message, 1024, 0, $ip, $port); $reply = str_rot13($message); socket_sendto($sock, $reply, strlen($reply), 0, $ip, $port); } ?>
运行后可使用 lsof 指令来查看端口占用情况,如下:
hxstrive@localhost:~$ lsof -i:10000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME php 40446 lthpc 3u IPv4 37381218 0t0 UDP *:10000
使用 nc 指令模拟客户端测试,如下:
$ nc -u 127.0.0.1 10000 Hello, world! Uryyb, jbeyq!
接下来使用 systemd 创建一个服务,写一个服务配置文件 /etc/systemd/system/rot13.service,如下:
[Unit] Description=ROT13 demo service After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=always RestartSec=1 WorkingDirectory=/path/ ExecStart=/usr/bin/env php /path/to/server.php [Install] WantedBy=multi-user.target
有几点需要注意,为了使服务能够自动无限次重启,需要增加以下几个配置:
StartLimitIntervalSec=0 Restart=always RestartSec=1
如果要设置环境变量,则需要在 Service 中添加 Environment,比如:
Environment=PYTHONPATH=$PYTHONPATH:/root/robot/models-master/research/:/root/robot/models-master/research/slim
也可以把环境变量的配置写在一个文件中,然后使用 EnvironmentFile 指定环境变量文件的位置。
设置好后,可以运行如下语句启动服务:
$ systemctl start rot13
启动时如果报错 The name org.freedesktop.PolicyKit1 was not provided by any .service files,则是因为权限问题,在启动命令前加 sudo 即可。
运行后,便启动了名为 rot13 的服务,可使用 status 查看服务状态,如下:
hxstrive@localhost:~$ systemctl status rot13 ● rot13.service - ROT13 demo service Loaded: loaded (/etc/systemd/system/rot13.service; disabled; vendor preset: enabled) Active: active (running) since 一 2019-10-28 11:25:43 CST; 1min 28s ago Main PID: 44532 (php) Tasks: 1 Memory: 5.2M CPU: 24ms CGroup: /system.slice/rot13.service └─44532 php /home/lthpc/workspace_zong/tcptest/server.php 10月 28 11:25:43 lthpc systemd[1]: Started ROT13 demo service.
为了开机自动启动,执行下以下命令:
$ systemctl enable rot13
同样的,可以使用 nc 指令模拟客户端测试,可以看到服务已经正常启动运行了!
如果想取消开机自动启动,使用以下命令:
$ systemctl disable rot13
为了测试是否可以正常自动重启,我们手动杀掉启动的服务进程,再查看进程号发现已经更换 PID 号了,说明重启过进程,并且使用 nc -u 127.0.0.1 10000 指令测试依然可以调用服务。如下:
$ systemctl status rot13 | grep PID Main PID: 44532 (php) $ sudo kill 44532 $ systemctl status rot13 | grep PID Main PID: 44255 (php)
注意输入 systemctl stop rot13 时服务是不会重启的,所以如果有参数需要修改,直接运行 stop 指令改完再 start 就可以了。
可以使用 journalctl 工具查看指定服务的输出,使用 -u 指定服务名称,使用 -f 可以实时输出,例如:
sudo journalctl -n -f -u baoshen.service
-n 表示 返回最新的日志
-f 表示 持续显示最新的日志,类似 tail -f
-u 表示只显示哪个service的日志
-r 反向倒序输出
上边介绍的服务默认是用 root 权限执行,如果要创建普通用户的服务,方法如下:
cd ~/.config mkdir systemd && cd systemd mkdir user && cd user touch test.service
按照上边的格式写一个服务的内容,启动的方法是:
systemctl --user daemon-reload systemctl --user start test.service
其它命令与 root 的类似,只需要加 --user 关键字即可
原文链接:https://blog.csdn.net/zong596568821xp/article/details/102739649