systemctl使用reload及踩坑

systemctl使用reload及踩坑1 demo service 文件 Unit Description demo demoserverDo http git demo com demoAfter network targetremote fs targetnss lookup target Service Type sampleUser rootPIDFile run demo

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进程。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232412.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • kaptcha验证码[通俗易懂]

    kaptcha验证码[通俗易懂]kaptcha是一个非常实用的验证码生成工具。有了它,你可以生成各种样式的验证码,因为它是可配置的。kaptcha工作的原理是调用com.google.code.kaptcha.servlet.KaptchaServlet,生成一个图片。同时将生成的验证码字符串放到HttpSession中。使用kaptcha可以方便的配置: 验证码的字体验证码字体的大小验证码字体的字

    2022年6月18日
    28
  • java 4舍5入_java四舍五入问题

    java 4舍5入_java四舍五入问题//#1publicdoubleround(doublein){doubledec=in-(int)in;doubleout=dec>=0.5?(int)i+((int)((dec-0.5)/0.25))*0.5+0.5:(int)i+((int)(dec/0.25))*0.5;returnout;}//Math.round(…

    2022年5月22日
    34
  • IDEA怎么生成UML类图

    IDEA怎么生成UML类图最近在开发的过程当中,对于已有的代码,想将相关类绘制成UML类图,虽然现在有很多UML类图的优秀软件,比如ProcessOn(可视化编辑)、draw.io(可视化编辑)、PlantUML(代码生成),其实看到这里我就想IDEA中有没有像PlantUML一样的自动生成的插件,本着怀疑的态度百度了一下,果然IDEA还是很强大的,这个插件都是自带的,接下稍微讲述如何利用IDEA生成UML类图的教程。…

    2022年7月12日
    79
  • Django 教程[通俗易懂]

    Django 教程[通俗易懂]Django 实战网址:http://study.163.com/course/courseMain.htm?courseId=1004369003菜鸟教程网址:http://www.runoob.com/django/django-tutorial.html

    2025年10月7日
    2
  • oracle 11g安装教程_暖气片安装方法图解

    oracle 11g安装教程_暖气片安装方法图解Oracle11G安装图解标签(空格分隔):oracleOracle介绍  OracleDatabase,又名OracleRDBMS,或简称Oracle是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的

    2022年9月21日
    2
  • 统一登录的基本原理

    请参考OAuth2.0的相关文章,OAuth2.0我更愿意称为第三方安全认证登录。而“统一登录”是自有系统的一次性用户名、密码验证,各系统间跳转,不再需要用户名密码验证。基本原理如下图。上图中的OAuthToken,只是一个随机串,例如MoRHmjRfdpUNWvOon5RfZ4COnd81Uz6N注意:假设各应用系统的域名分别如下a.test.comb.test.comc.test

    2022年4月4日
    150

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号