# 什么是 daemon 与服务(service)

简单说,你启动一个程序,这个程序提供你一些功能,那么这个程序就是 daemon,程序运行后提供的功能就是 service

比如:crontab 提供的定时任务,crond 是 daemon,crond 启动后提供的功能就是 service

所以不需要去区分它们两个,基本上可以视作是说同一个东西,毕竟程序需启动后才能提供功能

关于 daemon 的命名方式,一般会再原程序后面添加字母 d ,使用 ps 和 top 观察时就会发现很多后缀为 d 的 daemon 程序

# 早期 System V 的 init 管理行为中 daemon 的主要分类(可选知识)

第 1 章中谈到过的 Unix 的 system v 版本,是个很纯种的 Unix 版本,在那个年代,启动系统服务的管理方式被称为 SysV 的 init 脚本程序的处理方式,也就是系统核心的第一个程序是 init,init 去唤醒所有的系统所需要的服务,无论是本地还是网络服务

基本上 init 的管理机制有几个特色:

  • 服务的启动、关闭与观察等方式:

    所有的服务启动脚本通过放在 /etc/init.d/ 下,基本上都是使用 bash shell script 所写成的脚本程序,管理方式如下:

    • 启动:/etc/init.d/daemon start
    • 关闭:/etc/init.d/daemon stop
    • 重新启动:/etc/init.d/daemon restart
    • 状态观察:/etc/init.d/daemon status
  • 服务启动的分类

    init 服务的分类中,依据服务时独立启动或被一只总管程序管理而分为两大类:

    • 独立启动模式(stand alone):服务独立启动,该服务直接常驻于内存中,提供本机或用户的服务行为,反应速度快
    • 总管程序(super daemon):由特殊的 xinetd 或 inetd 这两个总管程序提供 socket 对应或 port 对应的管理。当没有用户要求某 socket 或 port 时,所需要的服务时不会被启动的。简单说当用户要求时就启动,要求结束就结束程序,缺点是通过总管程序启动有一定的延迟,好处是可以通过 super daemon 来管理
  • 服务的想依赖性

    比如:你要启动网络服务,但是系统没有网络、你需要联机到外部取得认证服务器的联机,该联机需求需要另一个 A 服务来达成,但是 A 服务没有启动,这就是服务依赖性问题。 init 在管理员自己手动处理这些服务时,是没有办法协助相依的服务的唤醒的

  • 执行等级的分类

    init 是开机后核心主动执行的,init 可根据用户自定义的执行等级(runlevel)来唤醒不同的服务,以进入不同的操作界面。基本上 LInux 提供 7 个执行等级:

    1. 单人维护模式
    2. 纯文本模式
    3. 文字加图形界面

    而各个执行等级的启动脚本是通过 /etc/rc.d/rc[0-6]/SXXdaemon 连结到 /etc/init.d/daemon,连结名 SXXdaemon 的功能为:

    • S:启动该服务
    • XX:是数值,启动顺序

    由于有 SXX 的设置,在开机时可以「依序执行」所有需要的服务,同时也能解决相依服务的问题。这点与管理员手动处理不太一样

  • 指定执行等级默认要启动的服务

    若要建立如上提到的 SXXdaemon,不需要手动建立连结文件,可以通过如下指令来达成:

    • 预设启动:chkconfig daemon on
    • 预设不启动:chkconfig daemon off
    • 观察预设启动状态:chkconfig --list daemon
  • 执行等级的切换行为

    当你要从纯文本界面(runlevel 3)切换到图形界面(5),不需要手动启动、关闭该执行等级的相关服务,只要 init 5 即可切换。 init 会主动分析 /etc/rc.d/rc[35].d/ 这两个目录内的脚本,然后启动转换 runlevel 中需要的服务,就完成了整体的切换

基本上 init 主要功能如上描述,CentOS 7 已经不使用 init 来管理服务了,不过考虑到某些脚本没法使用 systemd 来出来,就简单讲解下

# systemd 使用的 unit 分类

从 CentOS 7.x 后,改用 systemd 启动服务管理机制。好处如下

  • 平行处理所有服务,加速开机流程

    init 启动脚本是一项一项依序启动,不想依赖的服务也是一个一个等待启动,systemd 可以让所有服务同时启动,系统启动速度变快了

  • 一经要求就响应的 on-demand 启动方式

    systemd 全部只有一个 systemd 服务搭配 systemctl 指令来处理,无需其他额外的指令来支持。

  • 服务相互依赖自我检查

    systemd 可以自定义服务相依性检查,当你定义 B 依赖 A 时,你启动 B 服务时,会自动帮你启动 A 服务

  • 依 daemon 功能分类

    systemd 旗下管理的服务非常多,先定义所有的服务为一个服务单位(unit),并将 unit 归类到不同的服务类型(type)去。systemd 将服务单位(unit)区分为 service、socket、target、path、snapshot、timer 等多种不同的类型(type),方便管理员的分类与记忆。而旧的 init 仅分为 stand alone 与 super daemon

  • 将多个 saemons 集合成为一个群组

    systemd 将许多的功能集合成为一个所谓的 target 项目,只要在设计操作环境的配置,所以是集合了许多的 daemons,执行某个 target 就是执行好多个 daemon

    这个概念类似于 systemV 的 init 中的 runlevel

  • 向下兼容旧的 init 服务脚本

    但是更进阶的 systemd 功能没有办法支持 init 服务脚本,普通功能还是兼容的

systemd 某些地方无法完全取代 init,如:

- 在 runlevel 的对应上,大概仅有 1、3、4 有对应到 systemd 的某些 target 类型
- 全部的 systemd 都用 systemctl 管理,而systemctl 支持的语法有限制,无法像 `/etc/init.d/daemon` 那样纯脚本可以自定义参数,systemctl 不可自定义参数
- 如果某个服务启动时管理员自己通过程序指令手动启动的(如手动执行 crond),那么 systemd 将无法管理该服务
- systemd 启动过程中,无法与管理员通过 standard input 传入信息,因此,自行编写 systemd 的启动设置时,务必要取消互动机制,连通过启动时传进的标准输入信息也要避免

不过,光是同步启动服务脚本这个工具就可以节省很多开机时间,同时还有很多特殊的服务类型 type 可以提供更多的功能。

# systemd 的配置文件目录

systemd 将 daemon 执行脚本称为服务单位 unit,而每种服务单位按功能来区分时,分为不同的类型 type,类型太多,配置文件在以下位置

  • /usr/lib/systemd/system:每个服务最主要的启动脚本设置,类似以前的 /etc/init.d/下的文件
  • /run/systemd/system:系统执行过程中所产生的服务脚本,这些脚本的优先顺序比 /usr/lib/systemd/system
  • /etc/systemd/system:管理员按主机系统的需求所建立的执行脚本,该目录类似 /etc/rc.d/rc5.d/Sxx 之类的功能,执行优先顺序比 /run/systemd/system

也就是说,系统开机会不会执行某些服务其实是看 /run/systemd/system 下的设置。该目录下是一大堆的连结文件。而实际执行的 systemd 启动脚本配置文件,都放置在 /usr/lib/systemd/system 目录下。

如果要修改某个服务启动的设置,应该去 /usr/lib/systemd/system 下修改,/etc/systemd/system仅连结到正确的执行脚本配置文件而已

# systemd 的 unit 类型分类说明

可通过查看文件的扩展名,区分 /usr/lib/systemd/system 下的数据 type。下面来查看几个服务启动脚本

[root@study ~]# ll /usr/lib/systemd/system/ | grep -E '(vsftpd|multi|cron)'
-rw-r--r--. 1 root root  318 Aug  9  2019 crond.service
-rw-r--r--. 1 root root  492 Aug  8  2019 multi-user.target
drwxr-xr-x. 2 root root  258 Jan 17 14:39 multi-user.target.wants
-rw-r--r--. 1 root root  623 Aug  9  2019 multipathd.service
lrwxrwxrwx. 1 root root   17 Jan 17 14:39 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root   17 Jan 17 14:39 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root   17 Jan 17 14:39 runlevel4.target -> multi-user.target
-rw-r--r--. 1 root root  171 Oct 31  2018 vsftpd.service
-rw-r--r--. 1 root root   89 Oct 31  2018 vsftpd.target
-rw-r--r--. 1 root root  184 Oct 31  2018 vsftpd@.service

1
2
3
4
5
6
7
8
9
10
11
12

crond.service 通过该文件可以看出来,crond 算是系统服务(service);multi-user 是执行环节相关的类型(target type);根据这些扩展名的类型,大概可以找到几种比较常见的 systemd 的服务类型

扩展名 主要服务功能
.service 一般服务类型 service unit:主要是系统服务,包括服务器本身所需要的本地服务以及网络服务都是,比较经常使用到的大多是这种类型
.socket 内部程序数据交换的插槽服务 socket unit:主要是 IPC(Inter-process communication)的传输信息插槽文件(socket file)功能。 该类型的服务一般是比较不会被用到的服务,因此在开机时通常会延迟启动的时间。一般用于本地服务比较多
.target 执行环境类型 target unit:一群 unit 集合,例如上面 multi-user.target 其实就是一堆服务的集合
.mount、.automount 文件系统挂载相关的服务:例如来自网络的自动挂载、NFS 文件系统挂载等于文件系统相关性较高的程序管理
.path 侦测特定文件或目录类型:某些服务需要侦测某些特定的目录来提供队列服务,例如最长久的打印服务,就是通过侦测打印队列目录来启动打印功能,
.timer 循环执行的服务:类似 anacrontab,不过是由 systemd 主动提供的,比 anacrontab 更加有弹性