当前位置:   article > 正文

systemctl使用reload及踩坑_systemctl reload

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

[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
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
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]# 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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'
  • 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.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

发现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

  • 1
  • 2
  • 3
  • 4
  • 5

可以看到,这次/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)'
  • 1

通过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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/155453
推荐阅读
相关标签
  

闽ICP备14008679号