码迷,mamicode.com
首页 > 系统相关 > 详细

郝健:Linux下服务程序启动管理方式的分析与总结

时间:2020-12-02 12:13:20      阅读:7      评论:0      收藏:0      [点我收藏+]

标签:内核   产品   tab   des   服务器系统   进程id   调试   信息   速度   

原创 郝健 Linux阅码场 1月20日


作者:郝健

目前就职于瑞星咖啡,负责4层负载均衡的研究与开发。曾就职于天融信,赛尔网络,云杉网络几家公司。主要感兴趣的方向:linux内核网络子系统,dpdk。

技术图片

目前,Linux平台下主流的服务程序启动管理方式有以下几种:

  1. daemon
  2. sysvinit
  3. systemd
  4. nohup

1. daemon


守护进程是在后台运行不受控端控制的进程,通常情况下守护进程在系统启动时自动运行。

1.1 概念说明

进程组

每个进程除了有一进程ID( PID )之外,还属于一个进程组。进程组是一个或多个进程的集合。每个进程组有一个唯一的进程组ID( PGID )。进程组ID类似于进程ID, 它是一个正整数,并可存放在pid_t数据类型中。函数getpgrp返回调用进程的进程组ID。
技术图片

会话期(session)

会话期是一个或多个进程组的集合。通常是由shell的管道将几个进程编成一组的。比如,下图中的安排 可能是由下列形式的shell命令形成的:

procl | proc2 &

proc3 | proc4 | proc5
技术图片
一般,登陆一个shell时就会创建一个会话期。进程调用setsid函数就可建立一个新会话期。
技术图片
如果调用此函数的进程不是一个进程组的组长,则此函数创建一个新会话期,结果为:

  1. 此进程变成该新会话期的会话期首进程(session leader,会话期首进程是创建该会话期的进 程)。此进程是该新会话期中的唯一进程。

  2. 此进程成为一个新进程组的组长进程。新进程组ID是此调用进程的进程ID。

  3. 此进程没有控制终端。如果在调用setsid之前此进程有一个控制终端,那么这种联系也被解除。如果此调用进程已经是一个进程组的组长,则此函数返回出错。为了保证不处于这种情况,通常先 调用fork,然后使其父进程终止,而子进程则继续。因为子进程继承了父进程的进程组ID,而其进程ID则是新分配的,两者不可能相等,所以这就保证了子进程不是一个进程组的组长。

控制终端(terminal)

会话期和进程组有一些其他特性:

  1. 一个会话期可以有一个单独的控制终端(controlling terminal)。这通常是我们在其上登录的终端设备(终端登录情况)或伪终端设备(网络登录情况)。
  2. 建立与控制终端连接的会话期首进程,被称为控制进程(controlling process)。
  3. 一个会话期中的几个进程组可被分成一个前台进程组(foreground process group)以及一个或 几个后台进程组(background process group)。
  4. 如果一个会话期有一个控制终端,则它有一个前台进程组,其他进程组则为后台进程组。
  5. 无论何时键入中断键(常常是DELETE或Ctrl -C)或退出键(常常是Ctrl -\),就会造成将中断信号或退出信号送至前台进程组的所有进程。
  6. 如果终端界面检测到网络已经断开连接,则将挂断信号送至控制进程(会话期首进程)。通常,我们不必关心控制终端,登录时,将自动建立控制终端。

1.2 创建方法

创建守护进程,应该创建一个进程然后将其放到一个新的会话期中。

  1. 首先要做的是调用umask将文件模式创建屏蔽字设置为0。
  2. 调用fork(子进程会是将来的守护进程),然后使父进程退出(exit),保证子进程不是进程组组长(这 是setsid调用的必要前提条件)。
  3. 调用setsid创建新的会话期。
  4. 将当前目录改为根目录(如果不改为根目录可能导致不能umount某个目录)。
  5. 关闭不再需要的文件描述符。
  6. 某些守护进程打开/dev/null使其具有描述符0、1和2(将标准输入、标准输出、标准错误重定向 到/dev/null)。

技术图片

或者直接调用daemon函数

技术图片

2. sysvinit


sysvinit主要依赖于Shell脚本,在/etc/rc.d/rc*.d建立软连接。在RedHat系列发行版中,还提供了 service,chkcon?g 等命令行工具,来方便来管理 init 系统。sysvinit的主要问题是启动慢,已经逐渐 被淘汰。

目前Ubuntu和Centos等主流发行版都以移步到systemd,但仍然兼容老的写法,这里简单举个的例 子,编写一个simple脚本,添加执行权限后,保存到/etc/init.d/目录下。
技术图片
测试:
技术图片

3. systemd


systemd是目前主流Linux发型版采用的init项目,systemd起初饱受争议,可以搜索“the software that currently breaks your audio”查看。但随着越来越稳定和使用c开发,高效启动,已经逐渐成为主角。Linus也表示:Torvalds says he has no strong opinions on systemd

https://www.itwire.com/business-it-news/open-source/65402-torvalds-says-he-has-no-strong-opinions-on-systemd

我们简单实现一个simple-server来感受一下systemd,主要步骤如下:

1. 编写一个需要作为守护的程序,如:simple-server.c
技术图片

2. 编写service文件
技术图片
具体的说明详见;

https://www.freedesktop.org/software/systemd/man/systemd.service.html

其中Restart=always代表在任何情况下service被杀死后,都需要自动重启,其他说明详见如上链接中的 Table 2。

3. sudo cp simple-server.service /lib/systemd/system 
4. sudo systemctl enable simple-server 设置为开机启动,会自动创建软连接 /etc/systemd/system/multi-user.target.wants/simpleserver.service -> /lib/systemd/system/simple-server.service 
5. sudo systemctl start simple-server 启动 
6. sudo systemctl status simple-server 查看状态 
7. cat /var/log/syslog 查看日志输出 
8. pstree | grep simple-server 
9. sudo killall simple-server 杀死服务,验证是否自动重启。

几点说明:

  1. 修改simple-server.service后,需要执行systemctl daemon-reload重新加载。
  2. 在自daemon的方式中,是无法决定服务程序信息输出的位置的,只能重定向到/dev/null,而 systemd的方式可以灵活配置重定向的位置,/var/log/syslog为默认日志路径。
  3. service文件中Restart选项体现了"子死父知因"的重要性。

4. nohup


一个terminal一旦关闭,其绑定的shell会收到SIGHUP信号,且shell在退出之前会将SIGHUP信号广播 给其上的进程组,即其上所有进程都会退出。这也是自daemon需要调用setsid脱离terminal的原因。nohup命令并不是真正脱离terminal,而是忽略SIGHUP。将标准输入重定向到/dev/null,标准输出和标准出错重定向到nohup.out,且不会随着terminal的关闭而退出。验证:

1)正常启动一个死循环程序
技术图片

2)nohup启动同样的死循环程序
技术图片

对比总结


  1. daemon 通过自实现daemon,可以清楚的看出一个守护进程实现的原理,方便理清概念。但缺点是在实际工程中默认将输出重定向/dev/null,无法保存服务日志,排查服务问题,即使在程序中重定向到 某个日志目录,也只能写死,修改位置需要重新编译,不够灵活。
  2. sysvinit sysvinit的优点是简单,只需要编写脚本。将服务添加到某个runlevel时,只需要创建软链接文件 即可,DevOPs兴起之前,传统运维人员可以很快上手。顺序执行,方便排查问题。但顺序执行既 是优点也是缺点,带来的弊端是运行效率慢,这也是逐渐被淘汰的主要原因。毕竟现在Linux不只 用于服务器系统,终端用户更追求fast boot的用户体验。
  3. systemd systemd是目前主流Linux发行版中最新的初始化系统,主要的设计目标就是提高系统的启动速 度。.service文件中包含很多选项,配置灵活,比如日志位置和重启方式等。当然,最主要的卖点 还是并行启动速度快。
  4. nohup 在实际工程中,nohup也挺常用。比如一个类服务程序的调试,简单执行即可在一段时间通过 nohup.out文件观察问题,但其并不能算正真的守护程序。

综上,systemd看起来可以满足一个产品级别服务程序的两个最重要的需求:根据不同情况重启;记录 日志灵活可查,而这是daemon和nohup方式无法快速方便满足的。sysvinit简单清晰,但启动慢,就作为传统运维人员的美好记忆保留吧。

郝健:Linux下服务程序启动管理方式的分析与总结

标签:内核   产品   tab   des   服务器系统   进程id   调试   信息   速度   

原文地址:https://blog.51cto.com/15015138/2555438

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!