锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Linux基础知识之systemd详解

时间:2022-11-26 05:30:00 p48j5m密封连接器

  • 0x00 Systemd 简述

    • 1.Linux 启动流程

    • 2.主角登场

  • 0x01 Systemd Unit

    • 1.配置文件

    • 2.启动流程

    • 3.进程树(Process tree)

    • 4.运行级别

  • 0x02 Systemd Manager

    • 1.Systemctl 命令

    • 2.Journal 命令

    • 3.Systemd-analyze

  • 0x03 补充知识

0x00 Systemd 简述

描述:系统启动和服务器保护过程管理器负责在系统启动或运行过程中激活系统资源,并管理服务器过程和其他过程。Linux启动小伙伴系统时,首先运行systemd;

$ps aux USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND root          1  0.0  0.1 128204  5884 ?        Ss   3月25   2:19 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
1.Linux 启动流程

描述:想清楚 systemd 在 Linux 必须提到系统中的地位和作用 Linux 启动过程;
Linux 从按下电源键到进入用户交互界面的整个启动过程大致可分为四个阶段:

  • BIOS 阶段: 基本的硬件自检准备和加载 bootloader 程序;

  • BootLoader 阶段

  • kernel 加载阶段

  • init (systemd/sysvinit 初始化阶段)

(1) BIOS 阶段
Step 1.按下电源键(冷启动)后,CPU 程序计数器初始化为特定的内存地址(所以没有 CPU 主板无法启动 BIOS ),存储在只读存储器中(ROM)中的 BIOS 从这个特定的内存地址开始,值得注意的是嵌入式系统 CPU ,将加载引导区启动 flash/ROM 已知地址的程序;
Step2.BIOS 硬件的基本初始化也被称为上电自检,根据指导设备的优先级,将系统控制权交给硬件启动项(比如硬盘/网络/网络/U盘等),在这个阶段,我们可以进行外部中断 F12 或者 ESC 选择启动项的界面会弹出键(根据主板芯片组而异),这些键高度依赖硬件。
Step3.BIOS 选择硬件启动项后,硬件设备上的初级指导程序代码开始执行,对于 MBR 硬盘是第一个风扇区域(512字节)将被加载到内存中,并执行初始化代码来加载下一阶段 Bootloader

PS:此处以MBR以系统记录为例,MBR 主导记录是一个 512 位于硬盘第一扇区(0道0柱1扇区)的字节扇区 GPT/EFI 有经验的时候再讲解补充;

#dd 命令读取 MBR 主引导记录 dd if=/dev/sda of=mbr.bin bs=512 count=1  #od 命令查看二进制文件 od -xa mbr.bin # 0000000    63eb    0090    0000    0000    0000    0000    0000    0000 #           k   c dle nul nul nul nul nul nul nul nul nul nul nul nul nul # 0000020    0000    0000    0000    0000    0000    0000    0000    0000 #         nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul # * # 0000120    0000    0000    0000    0000    0000    8000    0800    0000 #         nul nul nul nul nul nul nul nul nul nul nul nul nul  bs nul nul # 0000140    0000    0000    faff    9090    c2f6    7480    f605    70c2 #         nul nul nul nul del   z dle dle   v   B nul   t enq   v   B   p # 0000160    0274    80b2    79ea    007c    3100    8ec0    8ed8    bcd0 #           t stx   2 nul   j   y   | nul nul   1   @  so   X  so   P   <

(2) BootLoader 阶段
加载主导记录 Bootloader(主要为GRUB)到 RAM 中之后,GRUB 可用的内核列表将根据需要显示(定义在/etc/grub.conf,/etc/grub/menu.lst和/etc/grub.conf的软连接
根据 GRUB 配置加载默认内核镜像和 initrd 镜像到内存中,当所有镜像准备好后,即跳转到内核镜像(针对于Windows可能有点不同,但都是一样的)。

(3) kernel 阶段
当BootLoader 阶段完成后,内核镜像(kernel image)被加载到内存中,系统的控制权就交给内核镜像由此内核阶段开始了;

内核镜像不是可执行的内核,而是压缩的内核镜像 (zImage 或 bzImage), 内核镜像头部有一个小程序 routine 设置少量硬件 ,然后自解压缩内核镜像,放入高端内存。
如果有初始磁盘镜像(initrd), routine 将拷贝 initrd 以后安装使用,然后 routine 启动内核调用。

在核心引导过程中,初始 RAM 磁盘(initrd)是由 BootLoader 它将被复制到内存中 RAM 并将其挂载到系统上。
initrd 作为 RAM 使用临时根文件系统,允许内核在没有任何物理磁盘的情况下完全指导(实际上)CentOS忘记使用恢复也主要取决于initrd),与外围设备交互所需的模块 initrd 因此,核心可以很小,但仍然支持大量可能的硬件配置
根文件系统可在内核启动后正式安装(通过 pivot_root),此时会将 initrd 根文件系统卸载并挂载真正的根文件系统。
initrd 可以创建一个小函数 Linux 内核,包括可加载模块编译的驱动程序, 该模块可以在磁盘和磁盘上访问文件系统,并为其他硬件提供驱动程序
由于根文件系统是磁盘上的一个文件系统,因此 initrd 函数将提供一种启动方法来访问磁盘,并悬挂真正的根文件系统。但在没有硬盘的嵌入式目标中,initrd 它可以是最终的根文件系统,也可以是网络文件系统(NFS)将最终的根文件系统挂载。

#使用 dmesg 查看加载内核后的流程 $ dmesg [    0.000000] Linux version 5.0.0-1031-gcp (buildd@lcy01-amd64-020) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #32-Ubuntu SMP Tue Feb 11 03:55:48 UTC 2020 (Ubuntu 5.0.0-1031.32-gcp 5.0.21) [    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-5.0.0-1031-gcp root=PARTUUID=9b22aacc-c8b9-497a-9583-a20c1be968c4 ro scsi_mod.use_blk_mq=Y console=ttyS0 [    0.000000] KERNEL supported cpus: [    0.000000]   Intel GenuineIntel [    0.000000]   AMD AuthenticAMD [    0.000000]   Hygon HygonGenuine [    0.000000]   Centaur CentaurHauls …………………………………………………………………………………………………… [    2.486896] Write protecting the kernel read-only data: 22528k [    2.489395] Freeing unused kernel image memory: 2016K [    2.490937] Freeing unused kernel image memory: 1708K [   2.500867] x86/mm: Checked W+X mappings: passed, no W+X pages found.
[    2.503126] x86/mm: Checking user space page tables
[    2.513767] x86/mm: Checked W+X mappings: passed, no W+X pages found.
[    2.516258] Run /sbin/init as init process
[    3.992535] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
[    4.002297] systemd[1]: Detected virtualization kvm.
[    4.004593] systemd[1]: Detected architecture x86-64.
[    4.031531] systemd[1]: Set hostname to .
[    5.343604] systemd[1]: Reached target Swap.
[    5.355156] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[    5.367360] systemd[1]: Created slice User and Session Slice.
[    5.379321] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[    5.395189] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[    5.411078] systemd[1]: Reached target Local Encrypted Volumes.
[    5.644759] EXT4-fs (sda1): re-mounted. Opts: (null)
[   11.663490] bpfilter: Loaded bpfilter_umh pid 456

(4)init 阶段
当内核自解压完成启动并初始化后,内核启动第一个用户空间应用程序即 systemd 进程(其实是老式 System V 系统的 init 程序的替代品)并将控制权移交给它; 这是系统启动后调用的第一个使用标准 C 库编译的程序,在此进程之前还没有执行任何标准的 C 应用程序,至此整个系统引导过程的结束;

此时 kernel和 systemd 处于工作运行状态然后就由systemd来管理各项程序,有可能您从dmesg输错的日志上该阶段首先执行/sbin/init命令而对于采用systemd的发行版来说,实际上/sbin/init 是指向 /lib/systemd/systemd的软链接文件;

[    2.516258] Run /sbin/init as init process
[    3.992535] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)

2.主角登场

Q:为什么为systemd是 Linux 的小伙伴?
答:其实广义上来讲 Linux 是众多 Linux 系统发行版的集合,但严格来讲 Linux 仅仅是一个 OS 的 kernel 而已,仅仅有一个内核是无法组成一个系统的,所以 Linux kernel 还需要他的几个兄弟比如 GNU 、 systemd 、X Window 、GNOME 、 KDE 、Xfce 等等其他用户层面的程序来构建出一套完整的操作系统出来

比如: GNU/Linux 将 Debian 哲学与方法论,GNU 工具集、Linux 内核,以及其他重要的自由软件结合在一起所构成的独特的软件发行版称为 Debian GNU/Linux。

systemd 简介
描述:在片头的时候我大致对systemd的工作做了一个总结,在本章节我对其深入的讲解

systemd 是一个 Linux 系统基础组件的集合,提供了一个系统和服务管理器,运行为 PID 1 并负责启动其它程序。
功能包括:

  • 支持并行化任务;

  • 同时采用 socket 式与 D-Bus 总线式激活服务;

  • 按需启动守护进程(daemon);

  • 利用 Linux 的 cgroups 监视进程; 比如systemctl 显示 CPU 和 Mem 信息就是基于此哦

  • 支持快照和系统恢复;

  • 维护挂载点和自动挂载点;

  • 各服务间基于依赖关系进行精密控制。

  • systemd* 支持 SysV 和 LSB 初始脚本,可以替代 sysvinit。

  • 除此之外功能还包括日志进程、控制基础系统配置,维护登陆用户列表以及系统账户、运行时目录和设置,可以运行容器和虚拟机,可以简单的管理网络配置、网络时间同步、日志转发和名称解析等。

systemd 设计目标
描述:在Redhat、CentOS等系列发行版中从7.x ~ 8.x 正式采用systemd作为系统服务管理工具的内核系统服务;它融合之前service和chkconfig的功能于一体,所以说它也能在 /etc/init.d/ 启动脚本进行扫描查看相程序;

主要目标:

  • 改进效能:使用二进制代码替换松散的SYSV启动脚本,减少频繁的进程创建/ 库加载/ 内核/用户切换;

  • 启动并行化: 利用 Dbus 进程间通讯与 socket 激活机制,解决任务启动时的依赖问题

  • 实现任务(daemons)精确控制:使用内核的 cgroup 机制,不依赖 pid 来追踪进程,即使是两次 fork之后生成的守护进程也不会脱离 systemd 的控制

  • 统一任务定义: 用户不需要自行编写 shell 脚本,而仅依据 systemd 制定的 unit 规则;

systemd 体系架构
systemd体系架构如下:

  • 1.最底层:systemd 内核层面依赖 cgroup、autofs、kdbus

  • 2.第二层:systemd libraries 是 systemd 依赖库

  • 3.第三层:systemd Core 是 systemd 自己的库

  • 4.第四层:systemd daemons 以及 targets 是自带的一些基本 unit、target,类似于 sysvinit 中自带的脚本

  • 5.最上层就是和 systemd 交互的一些工具,比如我们下面将要学习的systemctl;

c285a2e7acdf7aac98fc294a71a4849a.png

Linux 整体硬件与systemd体系架构:


0x01 Systemd Unit

描述:systemd核心概念unit(单元)类型:unit表示不同类型的systemd对象,并提供了处理不同单元之间依赖关系的能力,通过配置文件进行标识和配置;

文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息;

type name 作用
Service unit .service 用于封装一个后台服务进程
Target unit .target 用于将多个单元在逻辑上组合在一起。
Device unit .device 用于定义内核识别的设备,在 sysfs(5) 里面作为 udev(7) 设备树展示
Socket unit .socket 用于标识进程间通信用到的socket文件
Snapshot unit .snapshot 管理系统快照
Swap unit .swap 用于标识swap 文件或设备
Mount unit .mount 用于封装一个文件系统挂载点(也向后兼容传统的 /etc/fstab 文件)
Automount unit .automount 用于封装一个文件系统自动挂载点
Path unit .path 用于根据文件系统上特定对象的变化来启动其他服务。
Time unit .timer 用于封装一个基于时间触发的动作。取代传统的 crond 等任务计划服务
Slice unit *.slice 用于控制特定 CGroup 内所有进程的总体资源占用。

systemd 只在内存中加载最小化的一组单元 只有至少满足下列条件之一的单元,才会被加载到内存中:

  • 1.处于 活动(active)、启动中(activating)、停止中(deactivating)、失败(failed) 状态之一(也就是停止(inactive)之外的状态)

  • 2.至少有一个作业正在作业队列中

  • 3.至少有一个其他已经加载到内存中的单元依赖于它

  • 4.仍然占有某些资源 (例如一个已停止的服务单元的进程忽略了终止请求,仍在逗留)

  • 5.被 D-Bus 调用以程序化的方式固定到了内存中

    实际上用户并不能显而易见的看到某个单元是否已被加载到内存用 systemctl list-units –all 命令可以显示当前已加载到内存中的所有单元不满足加载条件(见上文)的单元会被立即从内存中卸载,并且它的记帐数据(accounting data)也会被清空。不过因为每当一个单元关闭时,都会生成一条日志记录声明该单元所消耗的资源, 所以这些数据通常不会彻底消失。

1.配置文件
  • 在 CentOS/RedHat 发行版中 man systemd.unit

    Table 1.  Load path when running in system mode (--system).
    ┌────────────────────────┬─────────────────────────────┐
    │Path                    │ Description                 │
    ├────────────────────────┼─────────────────────────────┤
    │/etc/systemd/system     │ Local configuration         │
    ├────────────────────────┼─────────────────────────────┤
    │/run/systemd/system     │ Runtime units               │
    ├────────────────────────┼─────────────────────────────┤
    │/usr/lib/systemd/system │ Units of installed packages │
    └────────────────────────┴─────────────────────────────┘
  • 在 Ubuntu/Debian 发行版中 man systemd.unit

    Table 1.  Load path when running in system mode (--system).
    ┌────────────────────┬─────────────────────────────┐
    │Path                │ Description                 │
    ├────────────────────┼─────────────────────────────┤
    │/etc/systemd/system │ Local configuration         │
    ├────────────────────┼─────────────────────────────┤
    │/run/systemd/system │ Runtime units               │
    ├────────────────────┼─────────────────────────────┤
    │/lib/systemd/system │ Units of installed packages │
    └────────────────────┴─────────────────────────────┘

    在使用 yum/apt 或其他包管理器,以及 rpm/deb 等软件包安装软件的时候,如果该软件支持 systemd 管理的话,就会自动在/usr/lib/systemd/system目录添加一个配置文件(针对于CentOS说明),此时可以采用systemctl cat name 来查看该软件的 systemd 单元文件

    但是如果软件没有自带 systemd 配置文件的话,我们可以自己搓一个配置文件出来,并复制到相应的目录下即可(后续我会简单配置一个实例[Webp Server Go](https://github.com/webp-sh/webp_server_go)

    service unit文件格式说明(类似于windows下的ini):

man systemd.service  #参考
  
  [unit]
  Description:描述信息
  After:定义unit的启动次序,表示当前unit应该晚于哪些unit启动,其功能与Before相反
  Requires:依赖到的其它units,强依赖,被依赖的units无法激活时,当前unit也无法激活
  Wants:依赖到的其它units,弱依赖
  Conflicts:定义units间的冲突关系			
  
  [Service] #与特定类型相关的专用选项;此处为Service类型
  Type:定义影响ExecStart及相关参数的功能的unit进程启动类型
      simple:默认值,这个daemon主要由ExecStart接的指令串来启动,启动后常驻于内存中
      forking:由ExecStart启动的程序透过spawns延伸出其他子程序来作为此daemon的主要服务。原生父程序在启动结束后就会终止
      oneshot:与simple类似,不过这个程序在工作完毕后就结束了,不会常驻在内存中
      dbus:与simple类似,但这个daemon必须要在取得一个D-Bus的名称后,才会继续运作.因此通常也要同时设定BusNname=才行
      notify:在启动完成后会发送一个通知消息。还需要配合 NotifyAccess 来让 Systemd 接收消息
      idle:与simple类似,要执行这个daemon必须要所有的工作都顺利执行完毕后才会执行。这类的daemon通常是开机到最后才执行即可的服务
  EnvironmentFile=/etc/sysconfig/sshd   #环境file
  ExecStart=/usr/sbin/sshd -D $OPTIONS  #启动
  ExecReload=/bin/kill -HUP $MAINPID  #重启
  KillMode=process     #关闭
  Restart=on-failure   # Restart: fail 时重启
  RestartSec=42s
  
  [Target]
  #.target定义了一些基础的组件,供.service文件调用
  
  [Mount]
  #.mount文件定义了一个挂载点,[Mount]节点里配置了What,Where,Type三个数据项
  #等同于以下命令:mount -t hugetlbfs /dev/hugepages hugetlbfs
  What=hugetlbfs
  Where-/dev/hugepages
  Type=hugetlbfs
  
  [Install]:#定义由“systemctl enable”以及"systemctl disable“命令在实现服务启用或禁用时用到的一些选项
  Alias:别名,可使用systemctl command Alias.service
  RequiredBy:被哪些units所依赖,强依赖
  WantedBy:被哪些units所依赖,弱依赖 多用户模式下需要的
  Also:安装本服务的时候还要安装别的相关服务

注意事项:

  • 不同的发行版 systemd unit 的 path 不一样,但是总体来说systemd 的配置文件主要位于以下三个目录中

    • /usr/lib/systemd/system 或 /lib/systemd : 使用包管理器安装的软件的 systemd unit 件实际配置文件的存放位置

    • /run/systemd/system:在运行时创建的s ystemd unit 文件。该目录优先于已安装服务单元文件的目录。

    • /etc/systemd/system优先级最高,由 systemctl 命令创建的 systemd unit 文件以及为扩展服务而添加的 unit 文件都将启用。

2.启动流程

当内核加载到内存中后开始执行 systemd,并且根据 dmesg 的日志我们可以了解到 systemd 启动后执行了哪一些操作

[    2.516258] Run /sbin/init as init process
[    3.992535] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
[    4.002297] systemd[1]: Detected virtualization kvm.
[    4.004593] systemd[1]: Detected architecture x86-64.
[    4.031531] systemd[1]: Set hostname to .
[    5.343604] systemd[1]: Reached target Swap.
[    5.355156] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[    5.367360] systemd[1]: Created slice User and Session Slice.
[    5.379321] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[    5.395189] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[    5.411078] systemd[1]: Reached target Local Encrypted Volumes.
[    5.644759] EXT4-fs (sda1): re-mounted. Opts: (null)
[    5.702603] RPC: Registered named UNIX socket transport module.
[    5.704115] RPC: Registered udp transport module.
[    5.705318] RPC: Registered tcp transport module.
[    5.706573] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    5.825727] Loading iSCSI transport class v2.0-870.
[    5.912079] iscsi: registered transport (tcp)
[    5.942499] systemd-journald[196]: Received request to flush runtime journal from PID 1
[    5.973269] systemd-journald[196]: File /var/log/journal/7bc72ce3e0aa559e38159aa4fa0547f9/system.journal corrupted or uncleanly shut down, renaming and replacing.

下面的图表解释了 这些具有特定含义的 target 单元之间的依赖关系 以及各自在启动流程中的位置。图中的箭头表示了单元之间的依赖关系与先后顺序, 整个图表按照自上而下的时间顺序执行。

local-fs-pre.target
            |
            v
   (various mounts and   (various swap   (various cryptsetup
    fsck services...)     devices...)        devices...)       (various low-level   (various low-level
            |                  |                  |             services: udevd,     API VFS mounts:
            v                  v                  v             tmpfiles, random     mqueue, configfs,
     local-fs.target      swap.target     cryptsetup.target    seed, sysctl, ...)      debugfs, ...) #主要单元Unti
            |                  |                  |                    |                    |
            \__________________|_________________ | `_______________` |____________________/
                                                 \|/
                                                  v
                                           sysinit.target
                                                  |
             `________________________________` /|\________________________________________
            /                  |                  |                    |                    \
            |                  |                  |                    |                    |
            v                  v                  |                    v                    v
        (various           (various               |                (various          rescue.service
       timers...)          paths...)              |               sockets...)               |
            |                  |                  |                    |                    v
            v                  v                  |                    v             *rescue.target
      timers.target      paths.target             |             sockets.target
            |                  |                  |                    |
            v                  \_________________ | `_______________` /
                                                 \|/
                                                  v
                                            basic.target
                                                  |
             `________________________________` /|                                 emergency.service
            /                  |                  |                                         |
            |                  |                  |                                         v
            v                  v                  v                                *emergency.target
        display-        (various system    (various system
    manager.service         services           services)
            |             required for            |
            |            graphical UIs)           v
            |                  |          *multi-user.target
            |                  |                  |
            \_________________ | `_____________` /
                              \|/
                               v
                  *graphical.target

(1) systemd 执行的第一个目标是 default.target。但实际上 default.target 是指向 graphical.target 的软链接。Graphical.target 的实际位置是/usr/lib/systemd/system/graphical.target

$ cat /usr/lib/systemd/system/graphical.target
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target #注意依赖
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes

(2) 在default.target这个阶段,会启动multi-user.target而这个 target 将自己的子单元放在目录/etc/systemd/system/multi-user.target.wants里。这个 target 为多用户支持设定系统环境。非 root用户会在这个阶段的引导过程中启用。防火墙相关的服务也会在这个阶段启动。multi-user.target会将控制权交给另一层basic.target

cat /usr/lib/systemd/system/multi-user.target

[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target #注意依赖
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

(3)basic.target单元用于启动普通服务特别是图形管理服务。它通过/etc/systemd/system/basic.target.wants目录来决定哪些服务会被启动,basic.target 之后将控制权交给 sysinit.target.

$ tree /etc/systemd/system/multi-user.target.wants
/etc/systemd/system/multi-user.target.wants
├── auditd.service -> /usr/lib/systemd/system/auditd.service
├── chronyd.service -> /usr/lib/systemd/system/chronyd.service
├── crond.service -> /usr/lib/systemd/system/crond.service
├── docker.service -> /usr/lib/systemd/system/docker.service
├── firewalld.service -> /usr/lib/systemd/system/firewalld.service
├── gitlab-runner.service -> /etc/systemd/system/gitlab-runner.service
├── irqbalance.service -> /usr/lib/systemd/system/irqbalance.service
├── kdump.service -> /usr/lib/systemd/system/kdump.service
├── NetworkManager.service -> /usr/lib/systemd/system/NetworkManager.service
├── postfix.service -> /usr/lib/systemd/system/postfix.service
├── remote-fs.target -> /usr/lib/systemd/system/remote-fs.target
├── rhel-configure.service -> /usr/lib/systemd/system/rhel-configure.service
├── rsyslog.service -> /usr/lib/systemd/system/rsyslog.service
├── sshd.service -> /usr/lib/systemd/system/sshd.service
└── tuned.service -> /usr/lib/systemd/system/tuned.service

(4) sysinit.target会启动重要的系统服务例如系统挂载,内存交换空间和设备,内核补充选项等等。sysinit.target 在启动过程中会传递给local-fs.target

tree /etc/systemd/system/basic.target.wants
/etc/systemd/system/basic.target.wants
├── microcode.service -> /usr/lib/systemd/system/microcode.service
└── rhel-dmesg.service -> /usr/lib/systemd/system/rhel-dmesg.service

(5) local-fs.target,这个 target 单元不会启动用户相关的服务,它只处理底层核心服务。这个 target 会根据 /etc/fstab 和 /etc/inittab 来执行相关操作。

cat /usr/lib/systemd/system/sysinit.target

[Unit]
Description=System Initialization
Documentation=man:systemd.special(7)
Conflicts=emergency.service emergency.target
Wants=local-fs.target swap.target
After=local-fs.target swap.target emergency.service emergency.target
3.进程树(Process tree)

使用 pstree 命令来看一哈进程树的状态,用户空间的进程都挂在 PID 为 1 的 systemd 下,注意该命令不是发行版本内置的需要进行安装 yum install pstree;

╭─root@sg-02 ~
╰─# pstree -p
systemd(1)─┬─accounts-daemon(661)─┬─{accounts-daemon}(689)
           │                      └─{accounts-daemon}(729)
           ├─agetty(971)
           ├─agetty(992)
           ├─aria2c(1010)
           ├─atd(653)
           ├─containerd(2915)─┬─{containerd}(2928)
           │                  ├─{containerd}(2929)
           │                  ├─{containerd}(2930)
           │                  ├─{containerd}(2934)
           │                  ├─{containerd}(2935)
           │                  ├─{containerd}(2950)
           │                  ├─{containerd}(2951)
           │                  ├─{containerd}(2978)
           │                  ├─{containerd}(5360)
           │                  └─{containerd}(8299)
           ├─cron(639)───cron(20506)───sh(20507)───monitor.sh(20509)───ffmpeg(20514)
           ├─dbus-daemon(664)
           ├─dockerd(17771)─┬─{dockerd}(17783)
           │                ├─{dockerd}(17784)
           │                ├─{dockerd}(17785)
           │                ├─{dockerd}(17791)
           │                ├─{dockerd}(17793)
           │                ├─{dockerd}(17800)
           │                ├─{dockerd}(17803)
           │                ├─{dockerd}(3030)
           │                └─{dockerd}(3031)
           ├─fail2ban-server(755)─┬─{fail2ban-server}(1059)
           │                      └─{fail2ban-server}(1060)
           ├─iscsid(896)
           ├─iscsid(897)
           ├─lvmetad(392)
           ├─networkd-dispat(622)───{networkd-dispat}(982)
           ├─nginx(3305)───nginx(17700)
           ├─php-fpm7.2(7497)─┬─php-fpm7.2(1295)
           │                  ├─php-fpm7.2(1296)
           │                  └─php-fpm7.2(5611)
           ├─polkitd(808)─┬─{polkitd}(820)
           │              └─{polkitd}(822)
           ├─rngd(981)
           ├─rpcbind(7125)
           ├─rsyslogd(11567)─┬─{rsyslogd}(11598)
           │                 ├─{rsyslogd}(11599)
           │                 └─{rsyslogd}(11600)
           ├─ss-server(17126)───obfs-server(17138)
             ├─sshd(5357)─┬─sshd(15490)───sshd(15598)───zsh(15619)───pstree(20539)
           │            ├─sshd(20413)───sshd(20414)
           │            └─sshd(20517)
           ├─systemd(5715)───(sd-pam)(5718)
           ├─systemd-journal(12866)
           ├─systemd-logind(652)
           ├─systemd-network(12827)
           ├─systemd-resolve(12839)
           ├─systemd-timesyn(12852)───{systemd-timesyn}(12861)
           └─systemd-udevd(8171)
4.运行级别

描述: 如今systemd 引入了一个和启动级别(一个旧的概念)功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每一个目标都有名字和独特的功能,而且能同一时候启用多个,一些目标继承其它目标的服务,并启动新服务。

SysV 启动级别 Systemd 目标 描述
0 runlevel0.target, poweroff.target 中断系统(halt)
1, s, single runlevel1.target, rescue.target 单用户模式
2, 4 runlevel2.target, runlevel4.target, multi-user.target 用户自己定义启动级别。通常识别为级别3。
3 runlevel3.target, multi-user.target 多用户,无图形界面。用户能够通过终端或网络登录。
5 runlevel5.target, graphical.target 多用户。图形界面。继承级别3的服务。并启动图形界面服务。
6 runlevel6.target, reboot.target 重新启动
emergency emergency.target 急救模式(Emergency shell)

0x02 Systemd Manager

控制 systemd 的主要命令主要有以下几种:

  • systemctl 命令控制 systemd 的管理系统和服务的命令行工具

  • systemsdm 命令控制 systemd 的管理和服务的图形化工具

  • journalctl 命令查询systemd 日志系统

  • loginctl 命令控制 systemd 登入管理器

  • systemd-analyze 分析系统启动效能(类似开机时间)

1.Systemctl 命令

systemctl help <单元> ## 显示单元的手冊页(必须由单元文件提供):

#unit类型或者单元:
service :文件扩展名为.service, 用于定义系统服务
target :文件扩展名为.target,用于模拟实现运行级别
device  :用于定义内核识别的设备
mount:定义文件系统挂载点
socket:用于标识进程间通信用的socket文件,也可在系统启动时,延迟启动服务,实现按需启动
snapshot :管理系统快照
swap:用于标识swap设备
automount :文件系统的自动挂载点
path:用于定义文件系统中的一个文件或目录使用,常用于当文件系统变化时,延迟激活服务

Systemctl 新特性:

  • 系统引导时实现服务并行启动

  • 按需启动守护进程

  • 自动化的服务依赖关系管理

  • 同时采用socket式与D-Bus总线式激活服务

  • 系统状态快照

优先级从低到高各自是:

  • /usr/lib/systemd/system/: 软件包安装的单元 #(Centos) Ubuntu:/lib/systemd/system

  • /etc/systemd/system/: 系统管理员安装的单元

  • /etc/init.d/ :软件安装服务单元(#任然有部分软件采用和用户自定义脚本)

  • 当systemd执行在用户模式下时,使用的载入路径是全然不同的;systemd 单元名仅能包括 ASCII 字符, 下划线和点号. 其它字符须要用 C-style “\x2d” 替换. 參阅 man systemd.unit 和 man systemd-escape.}}

参数语法

#0.启动/重启/停止/重载服务
systemctl start NAME
systemctl restart NAME
systemctl stop NAME
systemctl reload NAME

#1.查看服务状态
systemctl status NAME

#2.重启守护程序-修改过服务单元配置文件必须执行它(扫描新的或有变动的单元)
systemctl daemon-reload

#3.可以实现对其他机器的远程控制,该功能使用 SSH 连接。
systemctl 参数中添加 -H <用户名>@<主机名>

#4.杀死服务
systemctl kill NAME

基本用法

#示例0.自启与启动等常用命令
systemctl enable nginx.service
systemctl disable xinetd.service  #关闭自启动服务

systemctl start nginx.service
systemctl stop  xinetd.service     #停止服务
systemctl restart xinetd.service   #重启服务

systemctl status firewalld          #查看状态
systemctl status cobbler.service
# ● cobbler.service - SYSV: cobbler
#    Loaded: loaded (/etc/rc.d/init.d/cobbler; bad; vendor preset: disabled)
#    Active: inactive (dead)
#      Docs: man:systemd-sysv-generator(8)


#示例1.显示当前已加载到内存中的所有单元(Active)
systemctl list-units --all
#UNIT                                                                LOAD      ACTIVE   SUB       DESCRIPTION
#proc-sys-fs-binfmt_misc.automount                                   loaded    active   running   Arbitrary Executable File Formats File System Automount Point
#dev-block-8:2.device                                                loaded    active   plugged   LVM PV dKOf4k-3rna-sW69-3GHn-79gA-cfLX-DbC5oJ on /dev/sda2 2
systemctl list-units --type=target  #获取指定单元目标
UNIT                  LOAD   ACTIVE SUB    DESCRIPTION
basic.target          loaded active active Basic System
cryptsetup.target     loaded active active Local Encrypted Volumes

 
#示例2.查看该软件的 systemd 单元文件信息
systemctl cat docker
# /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket


#示例3.查看服务是否开机启动,服务是否激活
$systemctl is-enabled firewalld.service
# disabled
systemctl is-enabled sshd.service
# enabled
systemctl is-active sshd
# active


#示例4.列出 systemd目录下面的服务单元
systemctl list-unit-files
systemctl list-unit-files | grep mysqld  #查看mysqld服务是不是启动
systemctl list-unit-files | grep enabled  #查看已启动的服务列表
# auditd.service                                enabled
# autovt@.service                               enabled
# chronyd.service                               enabled
# crond.service                                 enabled
systemctl list-unit-files --failed #查看启动失败的服务列表
# UNIT FILE STATE
# 0 unit files listed.


#示例5.欲查看对特定 target 启用的服务请执行
systemctl list-dependencies
systemctl list-dependencies [target]
systemctl list-dependencies microcode.service
# microcode.service
# ● ├─system.slice
# ● └─basic.target
#   │ └─...
#注意:该输出结果只显示 SysV 服务,并不包含原生 systemd 服务,SysV 配置数据可能被原生 systemd 配置覆盖。


#示例6.切换并查看启动级别/目标
$systemctl set-default multi-user.target
rm '/etc/systemd/system/default.target'
ln -s '/usr/lib/systemd/system/multi-user.target' '/etc/systemd/system/default.target'
#能够在 systemctl 的输出中看到命令执行的效果:链接 /etc/systemd/system/default.target 被创建。指向新的默认启动级别。

$systemctl isolate graphical.target  #等价于telinit 3 或 telinit 5。

$systemctl get-default
graphical.target #当前为 graphical.target 修改为命令模式multi-user.target:


#示例7.查看unit中的类型
systemctl -t service
# UNIT                               LOAD   ACTIVE SUB     DESCRIPTION
# auditd.service                     loaded active running Security Auditing Service
systemctl --type target
# UNIT                  LOAD   ACTIVE SUB    DESCRIPTION
# basic.target          loaded active active Basic System


#示例8.禁用和取消禁用单元
# 禁用一个单元(禁用后,间接启动也是不可能的):
systemctl mask <单元>
# 取消禁用一个单元:
systemctl unmask <单元>


#示例9.电源管理
#安装 polkit 后才干够一般用户身份使用电源管理。
#假设你正登录在一个本地的systemd-logind用户会话。且当前没有其它活动的会话。那么下面命令无需root权限就可以执行。否则(比如当前有还有一个用户登录在某个tty),systemd 将会自己主动请求输入rootpassword。
$ systemctl reboot  #重新启动
$ systemctl poweroff  #退出系统并停止电源
$ systemctl suspend  #待机
$ systemctl hibernate  #休眠
$ systemctl hybrid-sleep #混合休眠模式(同一时候休眠到硬盘并待机):


#示例10.远程控制其他服务器的 systemd
systemctl status nginx -H root@weiyigeek.top
2.Journal 命令

描述:systemd 的第二个主要部分是 journal 日志系统,类似于 syslog 但也有些显著区别。

如果你喜欢用 sed 、grep 、awk 三剑客来处理日志,那么当你面对 journal 日志系统的时候你就准备掀桌儿吧!因为这是个二进制日志,无法使用常规的命令行文本处理工具来解析它

Systemd Journal 的优点如下:

* 简单性:代码少,依赖少,抽象开销最小。
* 零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
* 移植性:日志 文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
* 性能:添加和浏览 日志 非常快。
* 最小资源占用:日志 数据文件需要较小。
* 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。Syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
* 扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
* 安全性:日志 文件是可以验证的,让无法检测的修改不再可能。

日志的优先级和分类

系统日记按(优先级Priority level)和(设施Facility)对信息进行分类。日志分类对应于经典的Syslog协议(RFC 5424)。
注:下面表格最后一列 (wc -l) 是统计的记录数比例,总数是3个月的日志,大约100万条数据。

(1)优先级:

(2)设施分类:

journalctl 命令帮助

journalctl -h	  	 
#Options:	  	 
--system 	Show the system journal 	显示系统日志
--user 	Show the user journal for the current user 	显示当前用户的用户日志

-M 	--machine=CONTAINER 	Operate on local container 	在本地容器上操作
-S 	--since=DATE 	Show entries not older than the specified date 	显示不早于指定日期的条目
-U 	--until=DATE 	Show entries not newer than the specified date 	显示不比指定日期更新的条目
-c 	--cursor=CURSOR 	Show entries starting at the specified cursor 	显示从指定光标开始的条目
  	--after-cursor=CURSOR 	Show entries after the specified cursor 	在指定的光标后显示条目
  	--show-cursor 	Print the cursor after all the entries 	在所有条目之后打印光标
  	--cursor-file=FILE 	Show entries after cursor in FILE and update FILE 	在FILE中显示光标后的条目并更新FILE
-b 	--boot[=ID] 	Show current boot or the specified boot 	显示当前引导或指定的引导
  	--list-boots 	Show terse information about recorded boots 	显示有关录制的靴子的简洁信息
-k 	--dmesg 	Show kernel message log from the current boot 	显示当前引导的内核消息日志
-u 	--unit=UNIT 	Show logs from the specified unit 	显示指定单位的日志
  	--user-unit=UNIT 	Show logs from the specified user unit 	显示指定用户单元的日志
-t 	--identifier=STRING 	Show entries with the specified syslog identifier 	显示具有指定syslog标识符的条目
-p 	--priority=RANGE 	Show entries with the specified priority 	显示具有指定优先级的条目
-g 	--grep=PATTERN 	Show entries with MESSAGE matching PATTERN 	显示MESSAGE匹配PATTERN的条目
  	--case-sensitive[=BOOL] 	Force case sensitive or insenstive matching 	强制区分大小写或不区分匹配
-e 	--pager-end 	Immediately jump to the end in the pager 	立即跳到寻呼机的末尾
-f 	--follow 	Follow the journal 	关注期刊, 最新的
-n 	--lines[=INTEGER] 	Number of journal entries to show 	要显示的日记帐分录数
  	--no-tail 	Show all lines, even in follow mode 	即使在跟随模式下也显示所有行
-r 	--reverse 	Show the newest entries first 	首先显示最新的条目
-o 	--output=STRING 	Change journal output mode (short, short-precise, short-iso, short-iso-precise, short-full, short-monotonic, short-unix, (precise精确,monotonic单调) 	更改日志输出模式: verbose, export,
json, json-pretty, json-sse, json-seq,
cat, with-unit)
  	--output-fields=LIST 	Select fields to print in verbose/export/json modes 	选择要以详细/导出/ json模式打印的字段
  	--utc 	Express time in Coordinated Universal Time (UTC) 	协调世界时(UTC)的快车时间
-x 	--catalog 	Add message explanations where available 	添加消息说明(如果有)
  	--no-full 	Ellipsize fields 	Ellipsize字段
-a 	--all 	Show all fields, including long and unprintable 	显示所有字段,包括长字段和不可打印字段
-q 	--quiet 	Do not show info messages and privilege warning 	不显示信息消息和权限警告
  	--no-pager 	Do not pipe output into a pager 	不要将输出传输到寻呼机
  	--no-hostname 	Suppress output of hostname field 	禁止输出主机名字段
-m 	--merge 	Show entries from all available journals 	显示所有可用期刊的条目
-D 	--directory=PATH 	Show journal files from directory 	显示目录中的日志文件
  	--file=PATH 	Show journal file 	显示日志文件
  	--root=ROOT 	Operate on files below a root directory 	对根目录下的文件进行操作
  	--interval=TIME 	Time interval for changing the FSS sealing key 	更改FSS密封键的时间间隔
  	--verify-key=KEY 	Specify FSS verification key 	指定FSS验证密钥
  	--force 	Override of the FSS key pair with --setup-keys 	使用--setup-keys覆盖FSS密钥对
  	  	  	 
  	Commands:	  	 
-h 	--help 	Show this help text 	显示此帮助文本
  	--version 	Show package version 	显示包版本
-N 	--fields 	List all field names currently used 	列出当前使用的所有字段名称
-F 	--field=FIELD 	List all values that a specified field takes 	列出指定字段所需的所有值
  	--disk-usage 	Show total disk usage of all journal files 	显示所有日志文件的总磁盘使用情况
  	--vacuum-size=BYTES 	Reduce disk usage below specified size 	将磁盘使用量降低到指定大小以下
  	--vacuum-files=INT 	Leave only the specified number of journal files 	只保留指定数量的日志文件
  	--vacuum-time=TIME 	Remove journal files older than specified time 	删除早于指定时间的日志文件
  	--verify 	Verify journal file consistency 	验证日志文件一致性
  	--sync 	Synchronize unwritten journal messages to disk 	将未写入的日志消息同步到磁盘
  	--flush 	Flush all journal data from /run into /var 	将/ run中的所有日志数据刷新到/var
  	--rotate 	Request immediate rotation of the journal files 	请求立即轮换日志文件
  	--header 	Show journal header information 	显示日记标题信息
  	--list-catalog 	Show all message IDs in the catalog 	显示目录中的所有消息ID
  	--dump-catalog 	Show entries in the message catalog 	在消息目录中显示条目
  	--update-catalog 	Update the message catalog database 	更新消息目录数据库
  	--setup-keys 	Generate a new FSS key pair 	生成新的FSS密钥对

实际案例:

#实例1.显示bootloader启动信息
$ sudo journalctl -b           #启动信息23565
$ sudo journalctl -b -0
$ sudo journalctl -b -1        #前一次启动信息... 通过查询引导列表可看到最多能查看前几次启动信息
$ sudo journalctl --list-boots #引导列表

#实例2.显示不早于指定日期的条目
$ sudo journalctl --since="2019-06-13 16:42:34"
$ sudo journalctl --since "20 min ago"  #Show all messages since 20 minutes ago: 最近20分钟
$ sudo journalctl -S "20 min ago"

#实例3.持续显示最新新消息默认10条
$ sudo journalctl -f

#实例4.显示特定可执行文件的信息
$ sudo journalctl /usr/lib/systemd/systemd

#实例5.显示特定进程PID的日志信息
$ sudo journalctl _PID=1

#实例6.显示特定单元日志信息
$ sudo journalctl -u man-db.service

#实例7.显示当前引导的内核消息日志(--dmesg)
$ sudo journalctl -k

#实例8.-p 显示具有指定优先级的条目(0-7)
$ sudo journalctl -p err..alert
$ sudo journalctl -p 3..1 //3-1
$ sudo journalctl -p 3 //3-0
$ sudo journalctl -p 3 -r //3-0; 加-r选项,首先显示最新的条目

#实例9.通过在syslog工具上进行过滤来显示等效的auth.log
$ sudo journalctl SYSLOG_FACILITY=10
# 0 kern 内核;
# 1 user 用户;
# 3 daemon 守护进程;
# 4 auth 授权;
# 10 authpriv 授权;
$ sudo journalctl SYSLOG_FACILITY=0 -r
$ sudo journalctl -k -r
$ sudo journalctl SYSLOG_FACILITY=4 |wc -l
#14516
$ sudo journalctl SYSLOG_FACILITY=10 |wc -l
#9049

#实例10.如果日志目录(默认位于/var/log/journal下)包含大量日志数据,那么journalctl可能需要几分钟来过滤输出。
#它可以通过使用——file选项来强制journalctl只查看最近的日志,从而显著加快速度:
$ sudo journalctl --file /var/log/journal/*/system.journal -f

#实例11.手动清理日志文件删除已归档的日志文件
$ sudo journalctl --vacuum-size=100M #直到它们使用的磁盘空间低于100M:
$ sudo journalctl --vacuum-time=2weeks #使所有日记文件不包含超过2周的数据。

配置文件设置:

(1)日志大小限制设置
默认为基础文件系统的10%,但上限为4GB。
例如本机/var/log/journal/位于30Gb分区上,日志最多需要3Gb。超过40Gb的分区,日志文件需要最大值都为4Gb。

可以通过取消注释和更改以下内容来控制持久日志的最大大小:

$vim /etc/systemd/journald.conf
SystemMaxUse=50M

#也可以使用drop-in snippets配置覆盖机制,而不是编辑全局配置文件。在这种情况下,将覆盖置于[Journal]标题下:
$vim /etc/systemd/journald.conf.d/00-journal-size.conf
[Journal]
SystemMaxUse=50M

修改后重新启动日志系统 systemd-journald.service 即 systemctl restart systemd-journald.service;

3.Systemd-analyze
#Linux系统开机时间流程所耗费时间一览
[root@initiator ]$ systemd-analyze
Startup finished in 473ms (kernel) + 3.990s (initrd) + 40.050s (userspace) = 44.515s

0x03 补充知识

1.自定义服务单元

方式1:

描述:为了避免和 pacman 冲突,不应该直接编辑软件包提供的文件. 要更改由软件包提供的单元文件,先创建名为/etc/systemd/system/<单元名>.d/ 的文件夹(如 /etc/systemd/system/httpd.service.d/);然后放入 *.conf 文件,当中能够加入或重置參数,这里设置的參数优先级高于原来的单元文件。

实际案例:

#1.比如假设想加入一个额外的依赖。创建这么一个文件就可以:
/etc/systemd/system/.d/customdependency.conf
[Unit]
Requires=<新依赖>
After=<新依赖>

/etc/systemd/system/unit.d/customexec.conf
[Service]
#想知道为什么改动 ExecStart 前必须将其置空
ExecStart=
ExecStart=new command

#自己主动重新启动服务
Restart=always
RestartSec=30


#2.然后执行下面命令使更改生效:
systemctl daemon-reload
systemctl restart <单元>

此外,把旧的单元文件从 /usr/lib/systemd/system/ 拷贝到 /etc/systemd/system/,然后进行改动,也能够达到相同效果。

总结:

  • 在 /etc/systemd/system/ 文件夹中的单元文件的优先级总是高于 /usr/lib/systemd/system/ 文件夹中的同名单元文件

  • 用 systemd-delta 命令来查看哪些单元文件被覆盖、哪些被改动,系统维护的时候须要及时了解哪些单元已经有了更新。

方法2

自定义软件的 Systemd 单元实例:

[Unit]
Description=WebP Server Go
Documentation=https://github.com/webp-sh/webp_server_go
After=nginx.target

[Service]
Type=simple
StandardError=journal
WorkingDirectory=/opt/webps
ExecStart=/opt/webps/webp-server --config /opt/webps/config.json
Restart=always
RestartSec=3s

[Install]
WantedBy=multi-user.target

然后将其保存在/usr/lib/systemd/system/docker.service/webp.service,并且 执行 systemctl daemon-reload重载守护服务; 之后将可以通过systemctl status webp.service 对我们编写的服务单元进行管理;

关于 systemd 的单元配置文件如何书写,因为根据不同的单元类型包含的配置项实在是巨多。建议参考官方文档/社区翻译文档


2.自定义配置

(1)基于systemd实现显示服务CPU 和 Memory 信息

$vim /etc/systemd/system.conf
DefaultCPUAccounting=yes
DefaultMemoryAccounting=yes
DefaultTasksAccounting=yes

修改重启系统即可看见;

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章