赞
踩
[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]主要是定义服务启动相关
这里使用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 } }
情况一:
实验步骤:
[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,这个 MAINPID,这个MAINPID其实是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进程。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。