systemctl使用reload及踩坑

systemctl使用reload及踩坑

1.demo.service文件
[Unit]
Description=demo - demo server
Documentation=http://git.demo.com/demo
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=sample
User=root
PIDFile=/run/demo.pid
ExecStart=/home/codes/test/src/demo/demo/demo
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=0
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

[Unit]主要是描述和规定启动前后的顺序依赖关系

[Service]主要是核心的控制语句

[Install]主要是定义服务启动相关

2.程序代码

这里使用go做一个简单的信号量的捕获,

func main() {
	go signalHandle() // 信号量处理函数
	http.ListenAndServe("localhost:8080", nil) // 用于将进程挂起,避免退出
}

func signalHandle() {
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGHUP)
	sig := <-ch
	for {
		fmt.Printf("Signal received: %v", sig)
		if sig == syscall.SIGHUP {
			fmt.Println("syscall.SIGHUP")
			writeFile("syscall.SIGHUP received")
			return
		}
	}
}

func writeFile(wiriteString string) {
	var filename = "/home/codes/test/src/demo/demo/output.txt"
	var f *os.File
	f, err := os.Create(filename)
	if err != nil {
		fmt.Println(err)
		return
	}
	l, err := f.WriteString(wiriteString)
	if err != nil {
		fmt.Println(err)
		f.Close()
		return
	}
	fmt.Println(l, "bytes written successfully")
	err = f.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
}
3.测试

情况一:

实验步骤:

[root@bogon demo]# cat output.txt 
[root@bogon demo]# systemctl start demo.service 
[root@bogon demo]# ps -ef|grep demo
root      41159      1  0 14:30 ?        00:00:00 /home/codes/test/src/demo/demo/demo
root      41168  37883  0 14:30 pts/3    00:00:00 grep --color=auto demo
[root@bogon demo]# systemctl reload demo.service 
[root@bogon demo]# cat output.txt 
syscall.SIGHUP received[root@bogon demo]# 

systemctl start可以启动,进程存在,执行reload,进程可以捕获到SIGHUP信号量,执行了写文件操作,文件中输出syscall.SIGHUP received。

情况二:

有时候进程在启动时去读取配置文件,然后初始化log配置,及log输出路径后才会实现日志记录,在此之前或者有些没有打印日志的位置,怕程序跑飞,往往会用重定向来记录控制台日志,例如go的fmt。

service文件中ExecStart、ExecReload、ExecStop是不支持> 、>>等重定向符号的,这里可以用/bin/sh -c来实现。例如:

ExecStart=/bin/sh -c '/home/codes/test/src/demo/demo/demo >>/home/codes/test/src/demo/demo/reload.log  2>&1'

实验步骤:

[root@bogon system]# systemctl daemon-reload 
[root@bogon system]# systemctl start demo.service 
[root@bogon system]# systemctl reload demo.service 
Job for demo.service failed because the control process exited with error code. See "systemctl status demo.service" and "journalctl -xe" for details.
[root@bogon system]# systemctl status demo.service
● demo.service - demo - demo server
   Loaded: loaded (/usr/lib/systemd/system/demo.service; disabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since Thu 2019-07-11 14:42:33 CST; 1min 13s ago
     Docs: http://git.jd.com/database/jdcloud-rds
  Process: 41395 ExecStop=/bin/kill -s QUIT $MAINPID (code=exited, status=1/FAILURE)
  Process: 41394 ExecReload=/bin/kill -s HUP $MAINPID (code=exited, status=0/SUCCESS)
  Process: 41372 ExecStart=/bin/sh -c /home/codes/test/src/demo/demo/demo >>/home/codes/test/src/demo/demo/reload.log  2>&1 (code=killed, signal=HUP)
 Main PID: 41372 (code=killed, signal=HUP)

Jul 11 14:42:33 bogon kill[41395]: -p, --pid              print pids without signaling them
Jul 11 14:42:33 bogon kill[41395]: -l, --list [=<signal>] list signal names, or convert one to a name
Jul 11 14:42:33 bogon kill[41395]: -L, --table            list signal names and numbers
Jul 11 14:42:33 bogon kill[41395]: -h, --help     display this help and exit
Jul 11 14:42:33 bogon kill[41395]: -V, --version  output version information and exit
Jul 11 14:42:33 bogon kill[41395]: For more details see kill(1).
Jul 11 14:42:33 bogon systemd[1]: demo.service: control process exited, code=exited status=1
Jul 11 14:42:33 bogon systemd[1]: Reload failed for demo - demo server.
Jul 11 14:42:33 bogon systemd[1]: Unit demo.service entered failed state.
Jul 11 14:42:33 bogon systemd[1]: demo.service failed.

发现reload是报错的,查看status,发现ExecStop=/bin/kill -s QUIT $MAINPID (code=exited, status=1/FAILURE)失败。此时进程已经被杀掉了,执行systemctl strat将服务启动:

[root@bogon system]# ps -ef|grep demo
root      41435      1  0 14:45 ?        00:00:00 /bin/sh -c /home/codes/test/src/demo/demo/demo >>/home/codes/test/src/demo/demo/reload.log  2>&1
root      41436  41435  0 14:45 ?        00:00:00 /home/codes/test/src/demo/demo/demo
root      41444  37883  0 14:45 pts/3    00:00:00 grep --color=auto demo

可以看到,这次/bin/sh -c命令循环fork出了两个子进程,41435是该进程组的首进程,负责与终端tty交互,41436才是真正的demo进程,当执行reload时,实际上执行了ExecReload=/bin/kill -s HUP M A I N P I D , 这 个 MAINPID,这个 MAINPIDMAINPID其实是41435,此时的reload信号量是发给了首进程(41435),进程如果没做信号量的捕获,默认是执行中断操作,与此同时会给子进程发送SIGTREM信号杀掉子进程,所以systemctl命令报了错误。

如果在这种情况下还想实现reload,可以换一种实现方法,就是查到demo进程的真实pid,修改如下:

ExecReload=/bin/sh -c '/bin/kill -HUP $(pidof /home/codes/test/src/demo/demo/demo)'

通过pidof /home/codes/test/src/demo/demo/demo获取进程的pid,执行kill -HUP。

[root@bogon system]# systemctl start demo.service 
[root@bogon system]# ps -ef|grep demo
root      42728      1  0 15:26 ?        00:00:00 /bin/sh -c /home/codes/test/src/demo/demo/demo  >/home/codes/test/src/demo/demo/reload.log 2>&1
root      42729  42728  0 15:26 ?        00:00:00 /home/codes/test/src/demo/demo/demo
root      42736  37883  0 15:26 pts/3    00:00:00 grep --color=auto demo
[root@bogon system]# systemctl reload demo.service 
[root@bogon system]# cat /home/codes/test/src/demo/demo/reload.log 
Signal received: hangupsyscall.SIGHUP
23 bytes written successfully

这次可以看到reload没有报错,进程成功进到HUP信号量,cat reload.log 文件可以看到成功写入文件。

补充:为什么加入重定向就会循环fork出两个进程?

/bin/sh -c的原理就是fork+exec来产生一个进程,次进程是无法与tty(控制台)交互的后台进程,重定向需要与tty(控制台)交互,所以先fork出来一个重定向进程,再fork出一个真正的demo进程。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
systemctl reload是用于重新加载系统服务的命令。它会发送一个HUP信号给指定的服务进程,以使其重新加载配置文件或重新加载内部状态,而无需停止和启动整个服务。通常,它用于在不中断服务的情况下应用新的配置更改。 在引用中的示例中,通过修改ExecReload选项来实现reload使用命令"/bin/kill -HUP $(pidof /home/codes/test/src/demo/demo/demo)"发送HUP信号给指定进程,以执行reload操作。 在引用中的示例中,可以看到reload操作成功,进程成功进入HUP信号处理程序,并且reload操作的结果成功写入了reload.log文件。 然而,在引用中的示例中,reload操作报错。通过查看status可以发现,ExecStop选项的执行失败。此时,进程已经被杀掉。在这种情况下,可以通过执行systemctl start命令来重新启动服务,以恢复正常的运行状态。 综上所述,systemctl reload命令是用于重新加载系统服务的命令,可以在不中断服务的情况下应用新的配置更改。然而,需要注意处理reload操作可能出现的错误,并根据具体情况采取相应的措施。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [systemctl使用reload](https://blog.csdn.net/weixin_39992480/article/details/95484293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只努力的微服务

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值