Loading

十、系统管理

十、系统管理

10.1 进程管理

10.1.1 进程概述

​ 一个程序被加载到内存当中运作,那么在内存内的那个数据就被称为进程(process)。触发任何一个事件时,系统都会将他定义成为一个进程,并且给予这个进程一个 ID ,称为 PID,同时依据启发这个进程的用户与相关属性关系,给予这个 PID 一组有效的权限设定。

​ 如何产生一个进程呢?其实很简单啦,就是执行一个程序或命令就可以触发一个事件而取得一个 PID !每个程序都有三组人马的权限,每组人马都具有 r/w/x 的权限,所以不同的使用者身份执行这个程序时,系统给予的权限也都不相同!

​ 举个更常见的例子,我们要操作系统的时候,通常是利用远程登陆或者直接在主机前面登入,然后取得我们的shell 对吧!那么,我们的 shell 是 bash 对吧,这个 bash 在 /bin/bash 对吧,那么同时间的每个人登入都是执行 /bin/bash 对吧!不过,每个人取得的权限就是不同!

image-20230115153313234


进程大致总结,也就是运行起来的程序,命令,软件。

  • 程序软件,也就是存放在磁盘上面的程序代码
  • 守护进程(服务),持续运行的进程,这些一般是系统必备进程(服务软件)

10.1.2 父进程与子进程

​ 当我们登入系统后,会取得一个 bash 的 shell ,然后,我们用这个 bash 提供的接口去执行另一个指令,例如 /usr/bin/passwd 或者是 touch 等等,那些另外执行的指令也会被触发成为 PID ,那个后来执行指令才产生的 PID 就是子进程了,而在我们原本的 bash 环境下,就称为父进程了!


示例

​ ps显示当前进程的状态,得知bash的进程是2168。通过ps -l 2168查询此进程的详细信息,此处得知父进程为2118。通过pstree -p 2118来查询父进程与子进程的树关系表示。

image-20230115160337539


​ 有时候将有问题的进程关闭了,怎么过一阵子它又自动的产生? 而且新产生的那个进程的 PID 与原先的还不一样,这是怎么回事呢?

不要怀疑,如果不是 crontab 工作的影响,肯定有一支父进程存在,所以你杀掉子进程后, 父进程就会主动再生一支。解决方法就是找出那支父进程,然后将它kill即可。


fork and exec 进程呼叫的流程

​ 其实子进程与父进程之间的关系还挺复杂的,最大的复杂点在于进程互相之间的呼叫。在 Linux 的进程呼叫通常称为 fork-and-exec 的流程。进程都会藉由父进程以复制(fork)的方式产生一个一模一样的子进程, 然后被复制出来的子进程再以 exec 的方式来执行实际要进行的程序,最终就成为一个子进程的存在。 整个流程有点像底下这张图:

image-20230115161354166


就如下图环境所示

image-20230115161426452

​ 系统先以 fork 的方式复制一个与父进程相同的暂存进程,这个进程与父进程唯一的差别就是 PID不同! 但是这个暂存进程还会多一个 PPID 的参数,PPID 就是父进程的进程标识符!暂存进程开始以 exec 的方式加载实际要执行的程序,以上述的图来讲,新的程序名称为 pstree ,最终子进程的程序代码就会变成 pstree 了!


10.1.3 进程的生命周期

进程正常处理流程:

  • 子进程在处理任务代码时,父进程会进入等待状态中...
  • 子进程在处理任务代码后,会执行退出,然后唤醒父进程来回收子进程的资源。
  • 异常情况:如果子进程在处理任务过程中异常退出,而父进程没有回收子进程的资源。

10.1.4 进程监控
10.1.4.1 ps命令(查看进程数据)
[root@localhost ~]# ps aux <==观察系统所有的进程数据
[root@localhost ~]# ps -l <==仅列出与你的操作环境 (bash) 有关的进程数据
[root@localhost ~]# ps axjf <==连同部分进程树状态
选项与参数:
-A :所有的 process 均显示出来,与 -e 具有同样的效用;
-a :不与 terminal 有关的所有 process ;
-u :有效使用者 (effective user) 相关的 process ;
x :通常与 a 这个参数一起使用,可列出较完整信息。
输出格式规划:
-l :较长、较详细的将该 PID 的的信息列出;
-j :工作的格式 (jobs format)
-f :做一个更为完整的输出。

示例

1.仅列出与你的操作环境 (bash) 有关的进程数据

[root@localhost ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 R     0   3598 127209  0  80   0 - 38324 -      pts/0    00:00:00 ps
4 S     0 127209 127197  0  80   0 - 29085 do_wai pts/0    00:00:00 bash

F:代表这个进程旗标 (process flags),说明这个进程的总结权限,常见号码有:
    若为 4 表示此进程的权限为 root ;
    若为 1 则表示此子进程仅进行复制(fork)而没有实际执行(exec)。
	
S:代表这个进程的状态 (STAT),主要的状态有:
    R (Running):该程序正在运作中;
    S (Sleep):该程序目前正在睡眠状态(idle),但可以被唤醒(signal)。
    D :不可被唤醒的睡眠状态,通常这支程序可能在等待 I/O 的情况(ex>打印)
    T :停止状态(stop),可能是在工作控制(背景暂停)或除错 (traced) 状态;
    Z (Zombie):僵尸状态,进程已经终止但却无法被移除至内存外。
    
UID/PID/PPID:代表此进程被该 UID 所拥有/进程的 PID 号码/此进程的父进程 PID 号码

C:代表 CPU 使用率,单位为百分比;

PRI/NI:Priority/Nice 的缩写,代表此进程被 CPU 所执行的优先级,数值越小代表该进程越快被 CPU 执行。

ADDR/SZ/WCHAN:都与内存有关,ADDR 是 kernel function,指出该进程在内存的哪个部分,如果是个running 的进程,一般就会显示『 - 』 / SZ 代表此进程用掉多少内存 / WCHAN 表示目前进程是否运作中,同样的, 若为 - 表示正在运作中。

TTY:登入者的终端机位置,若为远程登录则使用动态终端接口 (pts/n);

TIME:使用掉的 CPU 时间,注意,是此进程实际花费 CPU 运作的时间,而不是系统时间;

CMD:就是 command 的缩写,造成此进程的触发程序之指令为何。

2.观察目前所有的正在内存当中的进程(系统所有)

[root@localhost ~]# ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     127209  0.0  0.0 116456  2980 pts/0    Ss   22:09   0:00 -bash
root     127279  0.0  0.1 167948  6696 ?        Ss   22:09   0:00 sshd: chen [priv]
root     127282  0.0  0.1 167952  6544 ?        Ss   22:09   0:00 sshd: chen [priv]
chen     127283  0.0  0.0 168280  2904 ?        S    22:09   0:00 sshd: chen@pts/2
chen     127285  0.0  0.0 167952  2552 ?        S    22:09   0:00 sshd: chen@notty
chen     127301  0.0  0.0 116464  3064 pts/2    Ss+  22:09   0:00 -bash
chen     127453  0.0  0.1 149464  5244 pts/2    T    22:09   0:00 vim .bash_profile
.....(节选部分).....

USER:该 process 属于那个使用者账号的。
PID :该 process 的进程标识符。
%CPU:该 process 使用掉的 CPU 资源百分比。
%MEM:该 process 所占用的物理内存百分比。
VSZ :该 process 使用掉的虚拟内存量 (Kbytes)
RSS :该 process 占用的固定的内存量 (Kbytes)
TTY :该 process 是在那个终端机上面运作,若与终端机无关则显示 ?,另外, tty1-tty6 是本机上面的登入者进程,若为 pts/0 等等的,则表示为由网络连接进主机的进程。
STAT:该进程目前的状态,状态显示与 ps -l 的 S 旗标相同 (R/S/T/Z)
START:该 process 被触发启动的时间。
TIME :该 process 实际使用 CPU 运作的时间。
COMMAND:该进程的实际指令为何。[]括起来的是内核进程, 其他是系统进程.

3.找出与 cron 与 rsyslog 这两个服务有关的 PID 号码

[root@localhost ~]# ps aux | egrep '(cron|rsyslog)'
root       1177  0.0  0.1 216400  5552 ?        Ssl  Jan15   0:02 /usr/sbin/rsyslogd -n
root       1188  0.0  0.0 126388  1600 ?        Ss   Jan15   0:00 /usr/sbin/crond -n
root      84240  0.0  0.0 112816  1000 pts/0    S+   01:39   0:00 grep -E --color=auto (cron|rsyslog)

4.只显示某些内容(进程所属用户、进程ID、CPU占用情况、内存占用情况、进程信息)

[root@localhost ~]# ps aux |awk '{print $1,$2,$3,$4,$11}' | head -5
USER PID %CPU %MEM COMMAND
root 1 0.0 0.1 /usr/lib/systemd/systemd
root 2 0.0 0.0 [kthreadd]
root 4 0.0 0.0 [kworker/0:0H]
root 6 0.0 0.0 [ksoftirqd/0]
[root@localhost ~]# ps -xo user,pid,%cpu,%mem,command | head -5
USER        PID %CPU %MEM COMMAND
root          1  0.0  0.1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2  0.0  0.0 [kthreadd]
root          4  0.0  0.0 [kworker/0:0H]
root          6  0.0  0.0 [ksoftirqd/0]

5.取出某一个服务(crond)的进程信息(pid,%cpu,%mem,command)

[root@localhost ~]# ps --no-heading -xo user,pid,%cpu,%mem,command |grep crond
root       1188  0.0  0.0 /usr/sbin/crond -n
root      13109  0.0  0.0 grep --color=auto crond

ps aux 中进程状态详解

[root@localhost ~]# ps aux <== Linux比较常见的进程状态:R+、R、S、T、D、Ss、Ssl、S<
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     127209  0.0  0.0 116456  2980 pts/0    Ss   22:09   0:00 -bash
STAT基本状态 描述
R(running) 进程运行
S 可中断进程(可以随时停止)
T(terminate) 进程被暂停(挂起) ctrl +z
D 不可中断进程(IO 读写)
Z(zombie) 僵尸进程
STAT状态+符号(附加状态) 描述
s(小写) 进程是控制进程
< 进程运行在高优先级上,S<优先级较高的进程
N 进程运行在低优先级上,SN优先级较低的进程
+ 当前进程运行在前台,R+该表示进程在前台运行
l(小写L) Ssl表示该进程是有多线程的

R+ 前台正在运行的进程
[root@localhost ~]# ps aux | grep R+
root      94502  0.0  0.0 155452  1884 pts/0    R+   02:04   0:00 ps aux

R 正在运行的进程(后台)

[root@localhost ~]# dd if=/dev/zero of=/tmp/big bs=1k count=9999999 &
[1] 95030
[root@localhost ~]# ps aux | grep dd
root      95030 95.5  0.0 108100   620 pts/0    R    02:05   0:09 dd if=/dev/zero of=/tmp/big bs=1k count=9999999

S可中断的进程

#大部分进程都是S

T 进程被后台挂起( ctrl + z )

[root@localhost ~]# vim /etc/host
host.conf    hostname     hosts        hosts.allow  hosts.deny
[root@localhost ~]# vim /etc/hosts
[1]+  Stopped                 vim /etc/hosts
[root@localhost ~]# ps aux | grep hosts
root      96460  0.4  0.1 149316  5028 pts/0    T    02:09   0:00 vim /etc/hosts

D不可中断进程 D+

[root@localhost ~]# tar zcf /tmp/var.tar.gz /var/ &
[2] 97897
[root@localhost ~]# tar: Removing leading `/' from member names
tar: Removing leading `/' from hard link targets

[root@localhost ~]# ps aux | grep tar
root      34621  0.0  0.1 1285392 7264 ?        S<l  Jan15   0:03 /usr/bin/pulseaudio --start
root      97897 14.5  0.0 123780  1328 pts/0    D    02:12   0:00 tar zcf /tmp/var.tar.gz /var/

Ss 可中断进程,管理进程(主进程)

[root@localhost ~]# ps aux | grep httpd
root      98952  0.0  0.1 224080  5016 ?        Ss   02:15   0:00 /usr/sbin/httpd -DFOREGROUND

S< 可中断进程,高优先级,大多为内核进程,也就是带括号的

[root@localhost ~]# ps aux | grep "S<"
root          4  0.0  0.0      0     0 ?        S<   Jan15   0:00 [kworker/0:0H]
root         10  0.0  0.0      0     0 ?        S<   Jan15   0:00 [lru-add-drain]
root         16  0.0  0.0      0     0 ?        S<   Jan15   0:00 [kworker/1:0H]
root         21  0.0  0.0      0     0 ?        S<   Jan15   0:00 [kworker/2:0H]

Ssl 可中断进程,管理进程(主进程),多线程

[root@localhost ~]# yum install -y mariadb-server
[root@localhost ~]# systemctl start mariadb

[root@localhost ~]# ps aux | grep mysql   <==查出mysql的进程状态是Sl
mysql    110802  0.2  0.0 113416  1608 ?        Ss   02:43   0:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
mysql    110967  2.3  2.0 968924 80812 ?        Sl   02:43   0:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --pid-file=/var/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
root     111057  0.0  0.0 112812   980 pts/0    S+   02:43   0:00 grep --color=auto mysql

[root@localhost ~]# pstree -p 110967   <==通过pstree查myspl进程派生的线程 {}括号的就是表示线程
mysqld(110967)─┬─{mysqld}(110971)
               ├─{mysqld}(110972)
               ├─{mysqld}(110973)
               ├─{mysqld}(110974)
               ├─{mysqld}(110975)
.....(省略其余线程).....

10.1.4.2 top命令(查看系统及进程整体运作状态)

top 可以持续侦测进程运作的状态,以及系统的整体状态情况。

选项与参数:
-d :后面可以接秒数,就是整个进程画面更新的秒数。预设是 5 秒;
-b :以批次的方式执行 top ,还有更多的参数可以使用喔!通常会搭配数据流重导向来将批次的结果输出成为文件。
-n :与 -b 搭配,意义是,需要进行几次 top 的输出结果。
-p :指定某些个 PID 来进行观察监测而已。

在 top 执行过程当中可以使用的按键指令:
    ? :显示在 top 当中可以输入的按键指令;
    P :以 CPU 的使用资源排序显示;
    M :以 Memory 的使用资源排序显示;
    N :以 PID 来排序喔!
    T :由该 Process 使用的 CPU 时间累积 (TIME+) 排序。
    k :给予某个 PID 一个讯号 (signal)
    r :给予某个 PID 重新制订一个 nice 值。
    q :离开 top 软件的按键。

top整体信息详解

image-20230116160028401


信息输出各字段的意义

  • PID:进程的ID
  • USER:进程所有者
  • PR:进程的优先级别,越小越优先被执行
  • NInice:NI 是优先值,是用户层面的概念, PR是进程的实际优先级, 是给内核(kernel)看(用)的。一般情况下,PR=NI+20
  • VIRT:进程占用的虚拟内存
  • RES:进程占用的物理内存
  • SHR:进程使用的共享内存
  • S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数。
  • %CPU:进程占用CPU的使用率
  • %MEM:进程使用的物理内存和总内存的百分比
  • TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
  • COMMAND:进程启动命令名称
[root@localhost ~]# top
top - 16:12:41 up 15:39,  4 users,  load average: 0.00, 0.01, 0.05
Tasks: 266 total,   1 running, 263 sleeping,   2 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.2 sy,  0.0 ni, 99.8 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3861292 total,   742416 free,  1073384 used,  2045492 buff/cache
KiB Swap:  8257532 total,  8256508 free,     1024 used.  2471508 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
110967 mysql     20   0  968924  85480   7204 S   0.7  2.2   0:01.40 mysqld
     1 root      20   0  191528   4540   2656 S   0.3  0.1   0:14.92 systemd
123313 root      20   0  162236   2420   1592 R   0.3  0.1   0:00.02 top
127197 root      20   0  168284   7076   5328 S   0.3  0.2   0:26.78 sshd
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.03 kthreadd

10.1.4.3 pstree命令(查看进程之间的树关系)

可以列出目前系统上面所有的进程的树关系。

选项与参数:
-A :各进程树之间的连接以 ASCII 字符来连接;
-U :各进程树之间的连接以万国码的字符来连接。在某些终端接口下可能会有错误;
-p :并同时列出每个 process 的 PID;
-u :并同时列出每个 process 的所属账号名称。

示例

1.列出目前系统上面所有的进程树的相关性,同时显示PID(pstree -p)

image-20230116205627197


2.列出目前系统上面所有的进程树的相关性,同时显示PID和进程所属用户信息(pstree -pu)

​ 在括号 () 内的即是 PID 以及该进程的所属者!一般来说,如果该进程的所有人与父进程同,就不会列出,但是如果与父进程不一样,那就会列出该进程的拥有者!

image-20230116205815504


10.1.5 僵尸进程

​ 僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程释放子进程占用的资源,此时子进程的进程描述符仍然保存在系统中,将成为一个僵尸进程。进程号会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。


模拟过程

模拟僵尸进程的代码

#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
desc: 用于模拟僵尸进程.代码.
*/
int main(int argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid == 0) {
int iPid = (int)getpid();
fprintf(stderr,"I am child,%d\n",iPid);
sleep(1);
fprintf(stderr, "Child exits\n");
return EXIT_SUCCESS;
}
int iPid = (int)getpid();
fprintf(stderr,"I am parent,%d\n",iPid);
fprintf(stderr, "sleep....\n");
sleep(600);
fprintf(stderr, "parent exits\n");
return EXIT_SUCCESS;
}

进行编译和运行测试

[root@localhost ~]# gcc zombine.c -o zombine
[root@localhost ~]# ./zombine
I am parent,64160
sleep....
I am child,64161
Child exits

再开个远程窗口进行操作,检查僵尸进程,已存在,STAT状态为Z的进程

[root@localhost ~]# ps aux | grep Z
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      64161  0.0  0.0      0     0 pts/0    Z+   16:38   0:00 [zombine] <defunct>
root      64488  0.0  0.0 112816   964 pts/3    R+   16:38   0:00 grep --color=auto Z

解决方法

结束他的父进程,如果还不行,最终方案重启Linux系统。

[root@localhost ~]# ps aux | grep Z  <==查看僵尸进程ID
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      64161  0.0  0.0      0     0 pts/0    Z+   16:38   0:00 [zombine] <defunct>
root      64488  0.0  0.0 112816   964 pts/3    R+   16:38   0:00 grep --color=auto Z
[root@localhost ~]# kill -9 64161    <==kill僵尸进程ID(当然这一步还是不行的)
[root@localhost ~]# ps aux | grep Z  <==查看是否还在,果然还在,因为僵尸进程无法接收kill的信号
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      64161  0.0  0.0      0     0 pts/0    Z+   16:38   0:00 [zombine] <defunct>
root      66182  0.0  0.0 112816   964 pts/3    S+   16:43   0:00 grep --color=auto Z
[root@localhost ~]# pstree -p | grep zombine  <==查看僵尸进程的父进程ID
           |-sshd(1139)-+-sshd(2754)-+-bash(2766)---zombine(64160)---zombine(64161)
[root@localhost ~]# kill -9 64160  <==kill僵尸进程的父进程
[root@localhost ~]# pstree -p | grep zombine  <==再次查看,已经没有相关僵尸进程以及父进程的进程信息
[root@localhost ~]# ps aux | grep Z           <==再次查看,已经没有相关僵尸进程以及父进程的进程信息
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      66789  0.0  0.0 112816   964 pts/3    S+   16:44   0:00 grep --color=auto Z

10.1.6 孤儿进程

孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程,孤儿进程会被系统直接接管(systemd进程)。


模拟过程

模拟孤儿进程的代码

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

int main()
{
    pid_t pid;
    //创建一个进程
    pid = fork();
    //创建失败
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    //子进程
    if (pid == 0)
    {
        printf("I am the child process.\n");
        //输出进程ID和父进程ID
        printf("pid: %d\tppid:%d\n",getpid(),getppid());
        printf("I will sleep five seconds.\n");
        //睡眠5s,保证父进程先退出
        sleep(5);
        printf("pid: %d\tppid:%d\n",getpid(),getppid());
        printf("child process is exited.\n");
    }
    //父进程
    else
    {
        printf("I am father process.\n");
        //父进程睡眠1s,保证子进程输出进程id
        sleep(1);
        printf("father process is  exited.\n");
    }
    return 0;
}

进行编译和运行测试

[root@localhost ~]# gcc yinjay.c -o yinjay
[root@localhost ~]# ./yinjay
I am father process.
I am the child process.
pid: 60579      ppid:60578
I will sleep five seconds.
father process is  exited.
[root@localhost ~]# pid: 60579  ppid:1
child process is exited.

解决方法

结束孤儿进程,重启对应服务。如果遇到重启服务出错,继续通过pstree -p命令排查相关进程。


10.2 工作管理

10.2.1 工作管理概述

​ 这个工作管理 (job control) 是用在 bash 环境下的,也就是说:当我们登入系统取得 bash shell 之后,在单一终端机接口下同时进行多个工作的行为管理。举例来说,我们在登入 bash 后, 想要一边复制文件、一边进行资料搜寻、一边进行编译,还可以一边进行 vim 程序撰写! 当然我们可以重复登入那六个文字接口的终端机环境中,不过,能不能在一个 bash 内达成? 当然可以!

​ 进行工作管理的行为中, 其实每个工作都是目前 bash 的子进程,亦即彼此之间是有相关性的。 我们无法以 job control 的方式由 tty1 的环境去管理 tty2 的bash。假设我们只有一个终端接口,可以出现提示字符让你操作的环境就称为前景(foreground),至于其他工作就可以让你放入背景 (background) 去暂停或运作。


进行 bash 的 job control 必须要注意到的限制是:

  • 这些工作所触发的进程必须来自于 shell 的子进程(只管理自己的 bash)
  • 前景:你可以控制与下达指令的这个环境称为前景的工作 (foreground)
  • 背景:可以自行运作的工作,但无法使用 [ctrl]+c 终止它,可使用 bg/fg 呼叫该工作
  • 背景中执行的进程不能等待 terminal/shell 的输入(input)

10.2.2 job control 的管理
10.2.2.1 直接将指令丢到背景中执行的 &

​ 在只有一个 bash 的环境下,如果想要同时进行多个工作, 那么可以将某些工作直接丢到背景环境当中,让我们可以继续操作前景的工作!最简单的方法就是利用 & 举个简单的例子,要将 /etc/ 整个备份为/tmp/etc.tar.gz 且不想要等待,那么可以这样做:

image-20230115230446089

​ bash 会给予这个指令一个工作号码,也就是[1],而89073是PID。回车,我们可以继续操作 bash。此时打包任务在后台进行,如何知道任务在什么状态,是否已经完成?如果你输入几个指令后,突然出现上图这个Done字样的数据,那就说明此项指令执行已经完成。


10.2.2.2 将目前的工作丢到背景中暂停 ctrl+z

​ 如果正在使用 vim ,却发现有个文件不知道放在哪里,需要到 bash 环境下进行搜寻,所以暂时将 vim 丢到背景当中等待即可。(那个 + 代表最近一个被丢进背景的工作)

image-20230115231635065


10.2.2.3 观察目前的背景工作状态 jobs

image-20230115232251942

选项与参数:
-l :除了列出 job number 与指令串之外,同时列出 PID 的号码。
-r :仅列出正在背景 run 的工作。
-s :仅列出正在背景当中暂停 (stop) 的工作。

​ 想要知道目前有多少的工作在背景当中,就用 jobs 这个指令。一般来说,直接下达 jobs 即可! 不过,如果还想要知道该 job number 的 PID 号码,可以加上 -l 这个参数。

​ 在输出的信息当中,例如上表,仔细看到那个 + - 号!那个 + 代表预设的取用工作。目前我有两个工作在背景当中,两个工作都是暂停的, 而如果我仅输入 fg 时,那么那个 [2] 会被拿到前景当中来处理。如果超过最后第三个以后的工作,就不会有 +/- 符号存在。


10.2.2.4 将背景工作拿到前景来处理 fg

​ 通过fg指令可以将背景工作拿到前景来处理。

#先以 jobs 观察工作,再将工作取出。
[root@localhost /]# jobs -l
[1]- 92719 Stopped                 vim /etc/ssh/sshd_config
[2]+ 96419 Stopped                 vim /root/.bash_profile
[root@localhost /]# fg    #预设取出那个 + 的工作,亦即 [2]。立即按下[ctrl]-z
[root@localhost /]# fg 1  #直接规定取出的那个工作号码!再按下[ctrl]-z
[root@localhost /]# jobs -l
[1]+ 92719 Stopped                 vim /etc/ssh/sshd_config
[2]- 96419 Stopped                 vim /root/.bash_profile

10.2.2.5 让工作在背景下的状态变成运作中 bg

​ 那个 [ctrl]-z 可以将目前的工作丢到背景底下去暂停, 那么如何让一个工作在背景底下 Run 呢?可以在底下这个案例来测试。

#执行 find / -perm /7000 > /tmp/text.txt 后,立刻丢到背景去暂停!(立刻按下 [ctrl]-z)
[root@localhost /]# find / -perm /7000 > /tmp/text.txt

#让该工作在背景下进行,并且观察它!!
[root@localhost /]# jobs ; bg 3 ; jobs

那个状态栏已经由 Stopping 变成了 Running 。

image-20230115233455028


10.2.2.6 管理背景当中的工作 kill

​ 那么如果想要将该工作直接移除呢?或者是将该工作重新启动呢?这个时候就得需要给予该工作一个讯号 (signal) 。

选项与参数:
-1 :重新读取一次参数的配置文件 (类似 reload);
-9 :立刻强制删除一个工作;
-15:以正常的进程方式终止一项工作。与 -9 是不一样的。

#示例:目前的 bash 环境下的背景工作,并将该工作强制删除。
[root@localhost /]# jobs -l
[1]+ 92719 Stopped                 vim /etc/ssh/sshd_config
[2]  96419 Stopped                 vim /root/.bash_profile
[root@localhost /]# kill -9 92719
[root@localhost /]# jobs -l
[1]+ 92719 Killed                  vim /etc/ssh/sshd_config
[2]  96419 Stopped                 vim /root/.bash_profile
[root@localhost /]# jobs -l
[2]+ 96419 Stopped                 vim /root/.bash_profile

#以 ps 找出 rsyslogd 这个进程的 PID 后,再使用 kill 传送讯息,使得 rsyslogd 可以重新读取配置文件。

#由于需要重新读取配置文件,因此 signal 是 1 号。至于找出 rsyslogd 的 PID 可以是这样做:
ps aux | grep 'rsyslogd' | grep -v 'grep'| awk '{print $2}'
#
#接下来则是实际使用 kill -1 PID,因此,整串指令会是这样:
kill -SIGHUP $(ps aux | grep 'rsyslogd' | grep -v 'grep'| awk '{print $2}')

#确认有没有重新启动 syslog 
tail -5 /var/log/messages

#确认有以下类似信息
Jan 16 21:11:38 localhost rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="118198" x-info="http://www.rsyslog.com"] start

10.3 资源观察

10.3.1 free命令(观察内存使用情况)
选项与参数:
-b :直接输入 free 时,显示的单位是 Kbytes,我们可以使用 b(bytes), m(Mbytes)
k(Kbytes), 及 g(Gbytes) 来显示单位喔!也可以直接让系统自己指定单位 (-h)
-t :在输出的最终结果,显示物理内存与 swap 的总量。
-s :可以让系统每几秒钟输出一次,不间断的一直输出的意思!对于系统观察挺有效!

#显示目前系统的内存容量
[root@localhost ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           3.7G        1.0G        705M         26M        2.0G        2.4G
Swap:          7.9G        1.0M        7.9G

10.3.2 uname命令(查看系统与核心相关信息)
选项与参数:
-a :所有系统相关的信息,包括底下的数据都会被列出来;
-s :系统核心名称
-r :核心的版本
-m :本系统的硬件名称,例如 i686 或 x86_64 等;
-p :CPU 的类型,与 -m 类似,只是显示的是 CPU 的类型!
-i :硬件的平台 (ix86)

[root@localhost ~]# uname -a
Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost ~]# uname -s
Linux
[root@localhost ~]# uname -r
3.10.0-1160.el7.x86_64
[root@localhost ~]# uname -m
x86_64
[root@localhost ~]# uname -p
x86_64
[root@localhost ~]# uname -i
x86_64

10.3.3 uptime命令(查看系统启动时间与工作负载)
[root@localhost ~]# uptime
 22:36:02 up 22:02,  4 users,  load average: 0.00, 0.01, 0.05
#以上表示系统时间,本机器正常运行22个钟了,目前有4个用户在线,工作负载依次是1分钟、5分钟、15分钟内的情况

10.4 后台运行

10.4.1 概述
前台/后台 基本介绍
前台 占用我们窗口终端(进程标记+) 始终开启窗口终端,如果终端断开,操作就结束了
后台 一般是系统服务软件 即使连接断开也不会影响操作

10.4.2 常用方案
后台运行方案 概述 应用场景
& (and) 让程序进程后台运行 大部分命令后台运行,缺点输出到屏幕,但是可以通过重定向方法保存输出。
ctrl + z 然后按bg 后台挂起,bg继续后台运行。 前台进程,转入后台运行。
screen 创建虚拟空间,让服务/命令/脚本在这个空间中运行,相当于是后台运行。 更稳定的后台运行命令/进程方式。screen里面运行的命令,外部看不到。
nohup xxxx & 与第1个类似,但会在运行当前的目录生成日志。 一般让后台运行的生成日志。

&符方案

[root@localhost ~]# sleep 88 &
[1] 124241
[root@localhost ~]# ps aux | grep 'sleep 88'
root     124241  0.0  0.0 108056   360 pts/0    S    21:44   0:00 sleep 88
root     124327  0.0  0.0 112812   980 pts/0    S+   21:44   0:00 grep --color=auto sleep 88
[root@localhost ~]# jobs -l
[1]+ 124241 Running                 sleep 88 &
[root@localhost ~]# 
[1]+  Done  <==任务已完成                  sleep 88

ctrl+z 然后使用bg

#让命令进入后台运行,刚开始使用的时候是前台运行,运行的时候转入后台运行
[root@localhost ~]# sleep 88  
^Z   #很明显的按下Ctrl + Z
[1]+  Stopped                 sleep 88  #以下信息能看出T标志,为停止、挂起状态
[root@localhost ~]# ps aux | grep 'sleep 88'
root     120260  0.0  0.0 108056   360 pts/0    T    21:33   0:00 sleep 88
root     120402  0.0  0.0 112812   980 pts/0    S+   21:33   0:00 grep --color=auto sleep 88
[root@localhost ~]# jobs -l  #查看工作管理信息,被挂起
[1]+ 120260 Stopped                 sleep 88
[root@localhost ~]# bg   #bg是让暂停的工作开始后台运行
[1]+ sleep 88 &
[root@localhost ~]# jobs -l   #已经running状态
[1]+ 120260 Running                 sleep 88 &
[root@localhost ~]# ps aux | grep 'sleep 88'
root     120260  0.0  0.0 108056   360 pts/0    S    21:33   0:00 sleep 88
root     120506  0.0  0.0 112812   976 pts/0    S+   21:33   0:00 grep --color=auto sleep 88

screen

#01 安装
yum install -y screen

#02 案例:让命令/进程通过screen运行 ,命令运行结束自动退出 screen窗口
screen tar zcvf /tmp/etc.tar.gz /etc/

screen -ls #查看保存会话(窗口)
screen -r 窗口id  #恢复
screen -S #创建窗口的时候指定会话名字

#03 案例2 让命令/进程通过screen运行 ,通过Ctrl+A,按d手动退出窗口,窗口还会继续运行
[root@localhost ~]# screen -ls   <==现在没有运行scrren
No Sockets found in /var/run/screen/S-root.

[root@localhost ~]# screen       <==进入scrren 
for n  in {1..10000}
do
 echo $n
 sleep 1
done
#然后Ctrl+A,按d手动退出窗口
[detached from 25886.pts-0.localhost]
[root@localhost ~]# screen -ls   <==查看screen会话窗口
There is a screen on:
        25886.pts-0.localhost   (Detached)
1 Socket in /var/run/screen/S-root.

[root@localhost ~]# screen -r  25886   <==通过-r参数,后者为会话id进入到里面,程序还在运行
[detached from 25886.pts-0.localhost]
[root@localhost ~]#

nohup + &

效果与使用和 &一致,只不过nohup + &运行后台命令如果有输出,写入到一个文件中默认是nohup.out


10.5 平均负载

10.5.1 平均负载概述

负载:衡量系统繁忙程度指标,用于初步判断系统运行情况。

[root@localhost ~]# uptime
 14:34:01 up 12:15,  1 user,  load average: 0.04, 0.03, 0.05
 #分别是当前时间、系统运行时间以及正在登录用户数。依次则是过去 1 分钟、5 分钟、15 分钟的平均负载(Load Average)。

10.5.2 衡量系统负载高低

系统负载数值与当前系统的cpu核心总数对比, 越接近cpu核心总数,负载越高。接近于cpu核心总数70-80%的时候,就会出现卡顿或者运行慢等现象出现。

查看cpu核心总数: lscpu top按1

image-20230120144732524

image-20230120144818137


10.5.3 理解系统平均负载

平均负载是指单位时间内,系统处于可运行状态(R、S)和不可中断状态(D)的平均进程数,也就是平均活跃进程数。系统负载高的原因,通常是CPU使用导致负载高或者大量IO消耗导致系统负载高。

  • 可运行状态(R、S):需要消耗CPU资源
  • 不可中断状态(D): 需要消耗IO资源

10.5.4 stress 模拟负载命令

stress 命令主要用来模拟系统负载较高时的场景,可以测试Linux系统的CPU、内存、磁盘I/O等的负载。

[root@localhost ~]#yum install -y stress
Example: stress --cpu 8  --vm 2 --hdd 2 --hdd-bytes 2g --vm-bytes 128M --timeout 10s
--cpu 测试 CPU 
--hdd 测试IO读写
--vm  测试内存   --vm-bytes 128M #内存读写占用多少内存空间
--hdd 2 --hdd-bytes 2g 
--timeout 10s  #测试持续10秒

10.5.5 模拟CPU使用率高导致系统负载高
[root@localhost ~]# stress --cpu 2  --timeout 99999   <==开启测试,占用两个核心

#开启另外一个远程连接,监控资源情况。可见得有两个cpu被占用100%,同时也看得出有两个stress进程占用率100%。视同平均负载已经慢慢在飙升,达到1.72,还会持续飙升的。本测试机核心数是4。
[root@localhost ~]# top    
top - 15:14:44 up 12:56,  2 users,  load average: 1.72, 0.68, 0.28
Tasks: 215 total,   3 running, 212 sleeping,   0 stopped,   0 zombie
%Cpu0  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.3 us,  0.7 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3861292 total,  1489360 free,   603052 used,  1768880 buff/cache
KiB Swap:  8257532 total,  8257532 free,        0 used.  2980756 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 47578 root      20   0    7312    100      0 R 100.0  0.0   1:58.94 stress
 47579 root      20   0    7312    100      0 R 100.0  0.0   1:58.94 stress

10.5.6 模拟IO使用率高导致系统负载高
#开始测试,开启三个线程不断执行write和unlink函数的进程(创建文件,写入内容,删除文件),2g的文件大小测试。
[root@localhost ~]# stress  --hdd 2 --hdd-bytes 2g

#可以看到每个cpu核心的io使用率(wa),同时平均负载也在升高。进程信息为D,不可中断,也就是IO读写。
[root@localhost ~]# top
top - 15:29:59 up 13:11,  2 users,  load average: 1.91, 1.45, 0.99
Tasks: 215 total,   2 running, 213 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  2.1 sy,  0.0 ni, 22.7 id, 70.1 wa,  0.0 hi,  5.2 si,  0.0 st
%Cpu1  :  1.7 us,  4.2 sy,  0.0 ni, 74.8 id, 19.3 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  1.1 us,  8.5 sy,  0.0 ni, 41.5 id, 48.9 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  4.7 sy,  0.0 ni,  0.0 id, 94.2 wa,  0.0 hi,  1.2 si,  0.0 st
KiB Mem :  3861292 total,  1145300 free,   561852 used,  2154140 buff/cache
KiB Swap:  8257532 total,  8257532 free,        0 used.  3021104 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 54552 root      20   0    8212   1124     32 D  58.3  0.0   0:02.20 stress
 54550 root      20   0    8212   1124     32 D  42.6  0.0   0:01.78 stress

10.5.7 系统负载过高排查流程
  • 发现Linux系统负载高(可通过监控软件得知)现在通过top/uptime/w命令查看。

  • 分析什么原因导致的

    • CPU导致

    • 磁盘IO导致

  • 根据具体原因然后解决

image-20230120155435418


10.5.8 vmstat 辅助排查系统负载高命令
vmstat 中第1列 r和第2列的b表示什么 
       r: The number of runnable processes (running or waiting for run time).
          当前可运行的进程数量(正在运行中或准备要运行) 类似于进程状态R
       b: Number of processes blocked waiting for I/O to complete.
          正在进行io进程(不可中断进程)
          
r数量高,很可能是cpu占用导致系统负载高。
b数量高,很可能是io占用导致系统负载高。

[root@localhost ~]# vmstat 1  #每1秒执行1次。
[root@localhost ~]# vmstat 1  #每1秒执行1次,一共执行10次。
---------------------------------------------------------------------------------
[root@localhost ~]# stress --cpu 2  --timeout 99999   <==开启测试,占用两个核心

#在另外的远程窗口进行监控状态
[root@localhost ~]# vmstat 1 
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  0      0 2867044     96 429352    0    0     7    83   50   47  0  0 99  0  0
 2  0      0 2867100     96 429352    0    0     0     0 2197  206 51  1 48  0  0
 2  0      0 2866840     96 429352    0    0     0     0 2143  189 50  0 50  0  0
 2  0      0 2867076     96 429352    0    0     0     0 2145  180 50  0 50  0  0
 2  0      0 2867012     96 429352    0    0     0     0 2155  183 50  0 50  0  0
 2  0      0 2866996     96 429352    0    0     0     0 2154  182 50  0 50  0  0
 2  0      0 2867028     96 429352    0    0     0     0 2141  176 50  0 50  0  0
 2  0      0 2866736     96 429352    0    0     0     0 2245  296 50  1 49  0  0
^C

#开始测试,开启三个线程不断执行write和unlink函数的进程(创建文件,写入内容,删除文件),2g的文件大小测试。
[root@localhost ~]# stress  --hdd 2 --hdd-bytes 2g

#在另外的远程窗口进行监控状态
[root@localhost ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  4      0 1277716     96 2014256    0    0     7    88   50   47  0  0 99  0  0
 0  4      0 1160420     96 2131644    0    0     0 98304  556  491  0  4 24 72  0
 1  4      0 1042076     96 2249196    0    0     0 114184  529  495  0  3 17 80  0
 0  4      0 926384     96 2365540    0    0     0 114688  566  499  0  4 22 74  0
 1  3      0 817364     96 2473896    0    0     0 81920  494  465  0  4 36 60  0
 1  4      0 707516     96 2584384    0    0     0 98304  584  586  0  4 43 54  0
 0  4      0 599544     96 2691824    0    0     0 98304  575  585  0  3 39 58  0
^C

10.6 服务管理

10.6.1 早期 System V的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

​ 服务是可能会有相依性的,例如,你要启动网络服务,但是系统没有网络, 那怎么可能可以唤醒网络服务呢?如果你需要联机到外部取得认证服务器的联机,但该联机需要另一个 A 服务的需求,问题是,A 服务没有启动, 因此,你的认证服务就不可能会成功启动的!这就是所谓的服务相依性问题。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

Tips:早期System V的init管理机制可以查看《鸟哥的Linux私房菜 · 基础篇》第十七篇。


10.6.2 Systemd 启动服务管理机制

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

​ 旧的 init 启动脚本是『一项一项任务依序启动』的模式,因此不相依的服务也是得要一个一个的等待。但目前我们的硬件主机系统与操作系统几乎都支持多核心架构了, 没道理未相依的服务不能同时启动啊!systemd 就是可以让所有的服务同时启动,因此你会发现到,系统启动的速度变快了。


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

​ systemd 全部就是仅有一只 systemd 服务搭配 systemctl 指令来处理,无须其他额外的指令来支持。不像systemV 还要 init, chkconfig, service... 等等指令。 此外, systemd 由于常驻内存,因此任何要求(on-demand) 都可以立即处理后续的 daemon 启动的任务。


3.服务相依性的自我检查

​ 由于 systemd 可以自定义服务相依性的检查,因此如果 B 服务是架构在 A 服务上面启动的,那当你在没有启动 A 服务的情况下仅手动启动 B 服务时, systemd 会自动帮你启动 A 服务!这样就可以免去管理员得要一项一项服务去分析的麻烦。


4.依 daemon 功能分类

​ systemd 旗下管理的服务非常多,为了厘清所有服务的功能,因此,首先 systemd 先定义所有的服务为一个服务单位 (unit),并将该 unit 归类到不同的服务类型 (type) 去。 旧的 init 仅分为 stand alone 与 super daemon 实在不够看,systemd 将服务单位 (unit) 区分为 service, socket, target, path, snapshot,timer 等多种不同的类型(type), 方便管理员的分类与记忆。


5.将多个 daemons 集合成为一个群组

​ 如同 systemV 的 init 里头有个 runlevel 的特色,systemd 亦将许多的功能集合成为一个所谓的 target 项目,这个项目主要在设计操作环境的建置, 所以是集合了许多的 daemons,亦即是执行某个 target 就是执行好多个 daemon 的意思。


6.向下兼容旧有的 init 服务脚本

​ 基本上, systemd 是可以兼容于 init 的启动脚本的,因此,旧的 init 启动脚本也能够透过 systemd 来管理,只是更进阶的 systemd 功能就没有办法支持就是了。


10.6.3 Systemd 的配置文件目录

​ systemd 将过去所谓的 daemon 执行脚本通通称为一个服务单位 (unit),而每种服务单位依据功能来区分时,就分类为不同的类型 (type)。 基本的类型有包括系统服务、数据监听与交换的插槽档服务 (socket)、储存系统状态的快照类型、提供不同类似执行等级分类的操作环境 (target) 等等。

  • /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/ 高!

​ 也就是说,到底系统开机会不会执行某些服务其实是看 /etc/systemd/system/ 底下的设定,所以该目录底下就是一大堆连结档。而实际执行的 systemd 启动脚本配置文件, 其实都是放置在/usr/lib/systemd/system/ 底下的喔!因此如果你想要修改某个服务启动的设定,应该要去/usr/lib/systemd/system/ 底下修改才对! /etc/systemd/system/ 仅是连结到正确的执行脚本配置文件而已。所以想要看执行脚本设定,应该就得要到 /usr/lib/systemd/system/ 底下去查阅才对。


看扩展名区分不同的类型 (type)

​ /usr/lib/systemd/system/ 以下的数据,sshd 与 crond 其实算是系统服务 (service),而 multi-user 要算是执行环境相关的类型 (target type)。

[root@localhost ~]# ll /usr/lib/systemd/system/ | grep -E '(sshd|multi|cron)'
-rw-r--r--. 1 root root  574 Oct  2  2020 anaconda-sshd.service
-rw-r--r--. 1 root root  318 Aug  9  2019 crond.service
-rw-r--r--. 1 root root  623 Sep 30  2020 multipathd.service
-rw-r--r--. 1 root root  492 Oct  2  2020 multi-user.target
drwxr-xr-x. 2 root root  258 Jul  3  2022 multi-user.target.wants
lrwxrwxrwx. 1 root root   17 Jul  3  2022 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root   17 Jul  3  2022 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root   17 Jul  3  2022 runlevel4.target -> multi-user.target
-rw-r--r--. 1 root root  313 Aug  9  2019 sshd-keygen.service
-rw-r--r--. 1 root root  373 Aug  9  2019 sshd.service
-rw-r--r--. 1 root root  260 Aug  9  2019 sshd@.service
-rw-r--r--. 1 root root  181 Aug  9  2019 sshd.socket

几种比较常见的 systemd 的服务类型如下:

image-20230201232223393


10.6.4 systemctl 管理单一服务 (service unit) 的启动/开机启动与观察状态

​ 一般来说,服务的启动有两个阶段,一个是开机的时候设定要不要启动这个服务以及你现在要不要启动这个服务。

[root@localhost ~]# systemctl [command] [unit]
command 主要有:
start :立刻启动后面接的 unit
stop :立刻关闭后面接的 unit
restart :立刻关闭后启动后面接的 unit,亦即执行 stop 再 start 的意思
reload :不关闭后面接的 unit 的情况下,重载配置文件,让设定生效
enable :设定下次开机时,后面接的 unit 会被启动
disable :设定下次开机时,后面接的 unit 不会被启动
status :目前后面接的这个 unit 的状态,会列出有没有正在执行、开机预设执行否、登录等信息等!
is-active :目前有没有正在运作中
is-enable :开机时有没有预设要启用这个 unit


#看看目前 sshd 这个服务的状态为何
[root@localhost ~]# systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)  #后面跟着的第一个enabled就是开机自启动
   Active: active (running) since Thu 2023-01-19 16:10:24 CST; 1 weeks 6 days ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 1171 (sshd)
   CGroup: /system.slice/sshd.service
           └─1171 /usr/sbin/sshd -D

Jan 20 15:12:40 localhost.localdomain sshd[47453]: Accepted password for root from 192.168.100.1 port 50943 ssh2
Jan 20 15:12:41 localhost.localdomain sshd[47455]: Accepted password for root from 192.168.100.1 port 50944 ssh2

# Loaded:这行在说明,开机的时候这个 unit 会不会启动,enabled 为开机启动,disabled 开机不会启动
# Active:现在这个 unit 的状态是正在执行 (running) 或没有执行 (dead)
# 后面几行则是说明这个 unit 程序的 PID 状态以及最后一行显示这个服务的登录文件信息!
# 登录文件信息格式为:『时间』 『讯息发送主机』 『哪一个服务的讯息』 『实际讯息内容』

Active的几个常见的状态

  • active (running):正有一只或多只程序正在系统中执行的意思,举例来说,正在执行中的 sshd 就是这种模式。

  • active (exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行。 举例来说,开机或者是挂载时才会进行一次的 quotaon 功能,就是这种模式! quotaon 不须一直执行~只须执行一次之后,就交给文件系统去自行处理!通常用 bash shell 写的小型服务,大多是属于这种类型 (无须常驻内存)。

  • active (waiting):正在执行当中,不过还再等待其他的事件才能继续处理。举例来说,打印的队列相关服务就是这种状态! 虽然正在启动中,不过,也需要真的有队列进来 (打印作业) 这样他才会继续唤醒打印机服务来进行下一步打印的功能。

  • inactive:这个服务目前没有运作的意思。


daemon预设状态

  • enabled:这个 daemon 将在开机时被执行

  • disabled:这个 daemon 在开机时不会被执行

  • static:这个 daemon 不可以自己启动 (enable 不可),不过可能会被其他的 enabled 的服务来唤醒(相依属性的服务)

  • mask:这个 daemon 无论如何都无法被启动!因为已经被强制注销(非删除),可透过 systemctl unmask 方式改回原本状态。


10.6.5 systemctl 观察系统上所有的服务

​ 系统上面有多少的服务存在呢?这个时候就得要透过 list-units 及 list-unit-files 来观察。

[root@localhost ~]# systemctl [command] [--type=TYPE] [--all]
command:
list-units :依据 unit 列出目前有启动的 unit。若加上 --all 才会列出没启动的。
list-unit-files :依据 /usr/lib/systemd/system/ 内的文件,将所有文件列表说明。
--type=TYPE:就是之前提到的 unit type,主要有 service, socket, target 等

#列出系统上面有启动的 unit
[root@localhost ~]# systemctl
UNIT                                                                   LOAD   ACTIVE SUB       DESCRIPTION
crond.service                                                          loaded active running   Command Scheduler
cups.service                                                           loaded active running   CUPS Printing Service
dbus.service                                                           loaded active running   D-Bus System Message Bus
gdm.service                                                            loaded active running   GNOME Display Manager
gssproxy.service                                                       loaded active running   GSSAPI Proxy Daemon
irqbalance.service                                                     loaded active running   irqbalance daemon
# 列出的项目中,主要的意义是:
# UNIT :项目的名称,包括各个 unit 的类别 (看扩展名)
# LOAD :开机时是否会被加载,默认 systemctl 显示的是有加载的项目而已。
# ACTIVE :目前的状态,须与后续的 SUB 搭配!就是我们用 systemctl status 观察时,active 的项目!
# DESCRIPTION :详细描述
# 另外,systemctl 都不加参数,其实预设就是 list-units 的意思!


#列出所有已经安装的unit有哪些
[root@localhost ~]# systemctl list-unit-files
UNIT FILE                                     STATE
cups.path                                     enabled
crond.service                                 enabled
dbus.service                                  static
httpd.service                                 disabled
#使用 systemctl list-unit-files 会将系统上所有的服务通通列出来,而不像 list-units 仅以 unit 分类作大致的说明。 至于 STATE 状态就是前面谈到的开机是否会加载的那个状态项目!主要有enabled / disabled / mask / static 等等。


# 只想要知道 service 这种类别的 daemon 而已,而且不论是否已经启动,通通要列出来。(只剩下 *.service 的项目才会出现)
[root@localhost ~]# systemctl list-units --type=service --all

10.6.6 systemctl 管理不同的操作环境 (target unit)

主要有底下几个:

  • graphical.target:就是文字加上图形界面,这个项目已经包含了底下的 multi-user.target 项目。
  • multi-user.target:纯文本模式。
  • rescue.target:在无法使用 root 登入的情况下,systemd 在开机时会多加一个额外的暂时系统,与你原本的系统无关。这时你可以取得 root 的权限来维护你的系统。 但是这是额外系统,因此可能需要动到 chroot 的方式来取得你原有的系统。
  • emergency.target:紧急处理系统的错误,还是需要使用 root 登入的情况,在无法使用 rescue.target 时,可以尝试使用这种模式。
  • shutdown.target:就是关机的流程。
  • getty.target:可以设定你需要几个 tty 之类的,如果想要降低 tty 的项目,可以修改这个东西的配置文件。
[root@localhost ~]# systemctl [command] [unit.target]
选项与参数:
    command:
    get-default :取得目前的 target
    set-default :设定后面接的 target 成为默认的操作模式
    isolate :切换到后面接的模式
    
#我们的测试机器默认是图形界面,先观察是否真为图形模式,再将默认模式转为文字界面
[root@localhost ~]# systemctl get-default
graphical.target
[root@localhost ~]# systemctl set-default multi-user.target
[root@localhost ~]# systemctl get-default
multi-user.target

#在不重新启动的情况下,将目前的操作环境改为纯文本模式,关掉图形界面
[root@localhost ~]# systemctl isolate multi-user.target

#若需要重新取得图形界面呢?
[root@localhost ~]# systemctl isolate graphical.target

​ 在正常的切换情况下,使用上述 isolate 的方式即可。不过为了方便起见, systemd 也提供了数个简单的指令给我们切换操作模式之用! 大致上如下所示:

[root@localhost ~]# systemctl poweroff 系统关机
[root@localhost ~]# systemctl reboot 重新启动
[root@localhost ~]# systemctl suspend 进入暂停模式
[root@localhost ~]# systemctl hibernate 进入休眠模式
[root@localhost ~]# systemctl rescue 强制进入救援模式
[root@localhost ~]# systemctl emergency 强制进入紧急救援模式

10.6.7 systemctl 分析各服务之间的相依性

​ 如何追踪某一个 unit 的相依性呢? 举例,我们怎么知道 graphical.target 会用到 multi-user.target 呢?那graphical.target 底下还有哪些东西呢?

[root@localhost ~]# systemctl list-dependencies [unit] [--reverse]
选项与参数:
--reverse :反向追踪谁使用这个 unit 的意思!


#列出目前的 target 环境下,用到什么特别的 unit
[root@localhost ~]# systemctl get-default
graphical.target
[root@localhost ~]# systemctl list-dependencies
default.target
● ├─accounts-daemon.service
● ├─gdm.service
● ├─initial-setup-reconfiguration.service
● ├─network.service
● ├─rtkit-daemon.service
● ├─systemd-readahead-collect.service
● ├─systemd-readahead-replay.service
● ├─systemd-update-utmp-runlevel.service
● ├─udisks2.service
● └─multi-user.target
●   ├─abrt-ccpp.service
●   ├─abrt-oops.service
●   ├─abrt-vmcore.service
...(以下省略)...

#根据线条联机的流程,我们也能够知道, multi-user.target 其实还会用到 basic.target + getty.target + remote-fs.target 三大项目, 而basic.target 又用到了 sockets.target + sysinit.target + timers.target... 等一堆~,所以从这边就能够清楚的查询到每种 target 模式底下还有的相依模式。

#那么如果要查出谁会用到 graphical.target 呢?
[root@localhost ~]# systemctl get-default
graphical.target

#reverse 本来就是反向的意思,所以加上这个选项,代表谁还会用到我的服务的意思~ 所以看得出来
[root@localhost ~]# systemctl list-dependencies --reverse
default.target

#graphical.target 又使用了多少的服务呢?
[root@localhost ~]# systemctl list-dependencies graphical.target
graphical.target
● ├─accounts-daemon.service
● ├─gdm.service
● ├─initial-setup-reconfiguration.service
● ├─network.service
● ├─rtkit-daemon.service
● ├─systemd-readahead-collect.service
● ├─systemd-readahead-replay.service
● ├─systemd-update-utmp-runlevel.service
● ├─udisks2.service
● └─multi-user.target
●   ├─abrt-ccpp.service
...(以下省略)...

#所以可以看得出来,graphical.target 就是在 multi-user.target 底下再加上 accounts-daemon, gdm,network, rtkit-deamon, systemd-update-utmp-runlevel 等服务而已,了解 daemon 之间的相关性也是很重要!出问题时,可以找到正确的服务相依流程。

10.6.8 与 systemd 的 daemon 运作过程相关的目录

​ systemd 启动脚本配置文件在 /usr/lib/systemd/system/,/etc/systemd/system/ 目录下,那还有哪些目录跟系统的 daemon 运作有关呢?

  • /usr/lib/systemd/system/:使用 CentOS 官方提供的软件安装后,默认的启动脚本配置文件都放在这里,这里的数据尽量不要修改~要修改时,请到 /etc/systemd/system 底下修改较佳!
  • /run/systemd/system/:系统执行过程中所产生的服务脚本,这些脚本的优先序要比/usr/lib/systemd/system/ 高!
  • /etc/systemd/system/:管理员依据主机系统的需求所建立的执行脚本,其实这个目录有点像前/etc/rc.d/rc5.d/Sxx 之类的功能!执行优先顺序又比 /run/systemd/system/ 高!
  • /etc/sysconfig/*:几乎所有的服务都会将初始化的一些选项设定写入到这个目录下,举例来说,mandb 所要更新的 man page索引中,需要加入的参数就写入到此目录下的 man-db 当中!而网络的设定则写在/etc/sysconfig/network-scripts/ 这个目录内。所以,这个目录内的文件也是挺重要的!
  • /var/lib/:一些会产生数据的服务都会将他的数据写入到 /var/lib/ 目录中。举例来说,数据库管理系统Mariadb 的数据库默认就是写入 /var/lib/mysql/ 这个目录下啦!
  • /run/:放置了好多 daemon 的暂存档,包括 lock file 以及 PID file 等等。

10.6.9 systemctl 针对 service 类型的配置文件
10.6.9.1 systemctl 配置文件相关目录

​ 服务的管理是透过 systemd,而 systemd 的配置文件大部分放置于/usr/lib/systemd/system/ 目录内。但是 Red Hat 官方文件指出, 该目录的文件主要是原本软件所提供的设定,建议不要修改!而要修改的位置应该放置于 /etc/systemd/system/ 目录内。如果你想要额外修改 vsftpd.service 的话, 他们建议要放置到哪些地方呢?

  • /usr/lib/systemd/system/vsftpd.service:官方释出的预设配置文件。
  • /etc/systemd/system/vsftpd.service.d/custom.conf:在 /etc/systemd/system 底下建立与配置文件相同文件名的目录,但是要加上 .d 的扩展名。然后在该目录下建立配置文件即可。另外,配置文件最好附档名取名为 .conf较佳! 在这个目录下的文件会『累加其他设定』进入 /usr/lib/systemd/system/vsftpd.service 内!
  • /etc/systemd/system/vsftpd.service.wants/*:此目录内的文件为链接档,设定相依服务的连结。意思是启动了vsftpd.service 之后,最好再加上这目录底下建议的服务。
  • /etc/systemd/system/vsftpd.service.requires/*:此目录内的文件为链接档,设定相依服务的连结。意思是在启动 vsftpd.service 之前,需要事先启动哪些服务的意思。

Tips:基本上,在配置文件里面你都可以自由设定相依服务的检查,并且设定加入到哪些 target 里头去。但是如果是已经存在的配置文件,或者是官方提供的配置文件, Red Hat 是建议你不要修改原设定,而是到上面提到的几个目录去进行额外的客制化设定比较好!如果你硬要修改原始的/usr/lib/systemd/system 底下的配置文件,那也是 OK 没问题的!并且也能够减少许多配置文件的增加。


10.6.9.2 systemctl 配置文件内容详解

了解了配置文件的相关目录与文件之后,再来了解一下配置文件本身的内容了,看一下sshd.service 的内容。

[root@localhost ~]# cat /usr/lib/systemd/system/sshd.service
[Unit]  #这个项目与此unit的解释、执行服务相依性有关
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service

[Service]  #这个项目与实际执行的指令参数有关
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]  #这个项目说明此unit要挂载哪个target底下
WantedBy=multi-user.target

将整个设定分为三个部份,就是:

  • [Unit]: unit 本身的说明,以及与其他相依 daemon 的设定,包括在什么服务之后才启动此 unit 之类的设定值。
  • [Service], [Socket], [Timer], [Mount], [Path]..:不同的 unit type 就得要使用相对应的设定项目。目前拿的是sshd.service 来当模板,所以这边就使用 [Service] 来设定。 这个项目内主要在规范服务启动的脚本、环境配置文件档名、重新启动的方式等等。
  • [Install]:这个项目就是将此 unit 安装到哪个 target 里面去的意思。

​ 设定规则还是得要说明一下:设定项目通常是可以重复的,例如可以重复设定两个 After 在配置文件中,不过,后面的设定会取代前面的!因此,如果想要将设定值归零, 可以使用类似『 After= 』的设定,亦即该项目的等号后面什么都没有,就将该设定归零了 (reset)。如果设定参数需要有『是/否』的项目 (布尔值, boolean),可以使用 1, yes, true, on 代表启动,用 0, no, false,off 代表关闭!

Tips:更多关于systemctl配置文件内容的哥参数详解,可以查看《鸟哥的Linux私房菜 · 基础篇》第十七篇。


10.7 日志管理

10.7.1 什么是登录档

​ 当你的 Linux 系统出现不明原因的问题时,要查阅一下登录文件才能够知道系统出了什么问题了,所以说, 了解登录档是很重要的事情呢。登录文件可以记录系统在什么时间、哪个主机、哪个服务、出现了什么讯息等信息, 这些信息也包括用户识别数据、系统故障排除须知等信息。如果能够善用这些登录文件信息的话,系统出现错误时, 将可以在第一时间发现,而且也能够从中找到解决的方案,而不是昏头转向的乱问人呢。 此外,登录文件所记录的信息量是非常大的,要人眼分析实在很困难。此时利用 shell script 或者是其他软件提供的分析工具来处理复杂的登录档,可以帮助你很多很多!


那么什么是登录档呢?

简单的说,就是记录系统活动信息的几个文件, 例如:何时、何地 (来源 IP)、何人(什么服务名称)、做了什么动作。 换句话说就是:记录系统在什么时候由哪个程序做了什么样的行为时,发生了何种的事件等等。


10.7.2 Linux 常见的登录档档名
  • /var/log/boot.log:开机的时候系统核心会去侦测与启动硬件,接下来开始各种核心支持的功能启动等。这些流程都会记录在/var/log/boot.log 里面! 不过这个文件只会存在这次开机启动的信息,前次开机的信息并不会被保留下来!
  • /var/log/cron:crontab 排程有没有实际被进行? 进行过程有没有发生错误?/etc/crontab 是否撰写正确?在这个登录档内查询看看。
  • /var/log/lastlog:可以记录系统上面所有的账号最近一次登入系统时的相关信息。lastlog 命令就是利用这个文件的记录信息来显示的。
  • /var/log/maillog 或 /var/log/mail/*:记录邮件的往来信息,其实主要是记录 postfix (SMTP 协议提供者) 与 dovecot (POP3 协议提供者) 所产生的信息啦。 SMTP 是发信所使用的通讯协议, POP3 则是收信使用的通讯协议。
  • /var/log/messages:这个文件相当的重要,几乎系统发生的错误信息 (或者是重要的信息) 都会记录在这个文件中; 如果系统发生莫名的错误时,这个文件是一定要查阅的登录档之一。
  • /var/log/secure:基本上,只要牵涉到『需要输入账号密码』的软件,那么当登入时 (不管登入正确或错误) 都会被记录在此文件中。 包括系统的 login 程序、图形接口登入所使用的 gdm 程序、 su, sudo 等程序、还有网络联机的ssh, telnet 等程序, 登入信息都会被记载在这里。

10.8 启动流程

​ 例如想要多重引导,那要怎么安装系统?如果 root 密码忘记了,那要如何救援?如果默认登入模式为图形界面,那要如何在开机时直接指定进入纯文本模式? 如果因为 /etc/fstab 配置错误,导致无法顺利挂载根目录,那要如何在不重装的情况下修改 /etc/fstab 让它变成正常?这些都需要了解开机流程。


10.8.1 开机流程一览
  1. 按下开机键,加载 BIOS 的硬件信息与进行自我测试,并依据设定取得第一个可开机的装置。

  2. 读取并执行第一个开机装置内 MBR,GPT的 boot Loader(亦即是 grub2, spfdisk 等程序)。

  3. 依据 boot loader 的设定加载 Kernel ,Kernel 会开始检测硬件与加载驱动程序。

  4. 在硬件驱动成功后,Kernel 会主动呼叫 systemd 程序,并以 default.target 流程开机。

    • systemd 执行 sysinit.target 初始化系统及 basic.target 准备操作系统

    • systemd 启动 multi-user.target 下的本机与服务器服务

    • systemd 执行 multi-user.target 下的 /etc/rc.d/rc.local 文件

    • systemd 执行 multi-user.target 下的 getty.target 及登入服务

    • systemd 执行 graphical 需要的服务


10.8.2 Systemd的工作

​ 在核心加载完毕、进行完硬件检测与驱动程序加载后,此时核心会主动的呼叫第一个程序,那就是 systemd 的 PID 号码是一号,systemd 最主要的功能就是准备软件执行的环境,包括系统的主机名、网络设定、语系处理、文件系统格式及其他服务的启动等。 而所有的动作都会透过 systemd 的默认启动服务集合,亦即是/etc/systemd/system/default.target来规划。


10.8.2.1 Systemd使用default.target

​ 当取得了 /etc/systemd/system/default.target 这一个预设操作界面的设定之后它会链接到/usr/lib/systemd/system/ 这个目录下去取得multi-user.target 或 graphical.target这两个其中之一

[root@localhost ~]# ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 36 Jul  3  2022 /etc/systemd/system/default.target -> /lib/systemd/system/graphical.target

#为什么不是链接到/usr?因为/lib就是从/usr/lib链接过来的
[root@localhost ~]# ls -l /lib
lrwxrwxrwx. 1 root root 7 Jul  3  2022 /lib -> usr/lib

接着下来 systemd 会去找两个地方的配置,如下的目录:

  • /etc/systemd/system/graphical.target.wants/:使用者设定加载的 unit
  • /usr/lib/systemd/system/graphical.target.wants/:系统默认加载的 unit

​ 查看/usr/lib/systemd/system/graphical.target的文件内容,这表示 graphical.target 必须要完成 multi-user.target 之后才能够进行,而进行完 graphical.target 之后,还得要启动 display-manager.service 才行的意思。

image-20230204005345060


继续查看multi-user.target 要执行完毕得要加载的项目有哪些

image-20230204005508754


使用者自定义要加载的 unit 又有哪些

image-20230204005753080

​ 通过上面的结果,能知道 multi-usre.target 需要在 basic.target 运作完毕才能够载入上述的许多 unit !然后再去 basic.target 里头找数据等等~

Tips:最终这些数据就可以通过 systemctllist-dependencies graphical.target 这个命令来列出所有的相关性的服务!这就是 systemd 的呼叫所需要的服务的流程。


10.8.2.2 Systemd 执行 sysinit.target 初始化系统
  • 特殊文件系统装置的挂载:包括 dev-hugepages.mount dev-mqueue.mount 等挂载服务,主要在挂载跟巨量内存分页使用与消息队列的功能。 挂载成功后,会在 /dev 底下建立 /dev/hugepages/, /dev/mqueue/ 等目录。
  • 特殊文件系统的启用:包括磁盘阵列、网络驱动器 (iscsi)、LVM 文件系统、文件系统对照服务 (multipath)
    等等,也会在这里被侦测与使用到!
  • 开机过程的信息传递与动画执行:使用 plymouthd 服务搭配 plymouth 指令来传递动画与信息
  • 日志式登录文件的使用:就是 systemd-journald 这个服务的启用啊!
  • 加载额外的核心模块:透过 /etc/modules-load.d/*.conf 文件的设定,让核心额外加载管理员所需要的核心模
    块!
  • 加载额外的核心参数设定:包括 /etc/sysctl.conf 以及 /etc/sysctl.d/*.conf 内部设定!
  • 启动系统的随机数生成器:随机数生成器可以帮助系统进行一些密码加密演算的功能
  • 设定终端机 (console) 字形
  • 启动动态设备管理器:就是 udevd 这个东西!用在动态对应实际装置存取与装置文件名对应的一个服务!

Tips:不论使用哪种操作环境来使用系统,这个 sysinit.target 都是必要的工作!从上面你也可以看的出来,基本的核心功能、文件系统、文件系统装置的驱动等等, 都在这个时刻处理完毕~所以,这个 sysinit.target 的阶段是挺重要的!


10.8.2.3 Systemd 执行 basic.target 准备系统

这个 basic.target 的阶段主要启动的服务大概有这些:

  • 加载 alsa 音效驱动程序:这个 alsa 是个音效相关的驱动程序,会让你的系统有音效产生。
  • 载入 firewalld 防火墙:CentOS 7.x 以后使用 firewalld 取代 iptables 的防火墙设定,虽然最终都是使用
    iptables 的架构, 不过在设定上面有差别。
  • 加载 CPU 的微指令功能
  • 启动与设定 SELinux 的安全本文:如果由 disable 的状态改成 enable 的状态,或者是管理员设定强制重
    新设定一次 SELinux 的安全本文, 也在这个阶段处理。
  • 将目前的开机过程所产生的开机信息写入到 /var/log/dmesg 当中。
  • 由 /etc/sysconfig/modules/*.modules 及 /etc/rc.modules 加载管理员指定的模块。
  • 加载 systemd 支持的 timer 功能。

Tips:在这个阶段完成之后,系统已经可以顺利的运作!就差一些需要的登入服务、网络服务、本机认证服务等等的 service 类别!于是就可以进入下个服务启动的阶段了!


10.8.2.4 Systemd 启动 multi-user.target 下的服务

​ 在加载核心驱动硬件后,经过 sysinit.target 的初始化流程让系统可以存取之后,加上 basic.target 让系统成为操作系统的基础, 之后就是服务器要顺利运作时,需要的各种主机服务以及提供服务器功能的网络服务的启动了。这些服务的启动则大多是附挂在 multi-user.target 这个操作环境底下,可以到/etc/systemd/system/multi-user.target.wants/ 里头去瞧瞧预设要被启动的服务。


一般来说服务的启动脚本设定都是放在底下的目录内:

  • /usr/lib/systemd/system(系统默认的服务启动脚本设定)
  • /etc/systemd/system (管理员自己开发与设定的脚本设定)

​ 而用户针对主机的本地服务与服务器网络服务的各项服务若要 enable 的话,就是将它放到/etc/systemd/system/multi-user.target.wants/ 这个目录底下做个链接~ 这样就可以在开机的时候去启动它。

#例子
[root@localhost ~]# systemctl disable httpd
Removed symlink /etc/systemd/system/multi-user.target.wants/httpd.service.
[root@localhost ~]# systemctl enable httpd
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.

​ 不是从 /etc/systemd/system/multi-user.target.wants/ 里面删除链接,就是建立链接~ 当然不需要手动作这些链接,而是使用 systemctl 来处理即可!

Tips:另外,这些程序除非在脚本设定里面原本就有规范服务的相依性, 这样才会有顺序的启动之外,大多数的服务都是同时启动的!这就是 systemd 的多任务。


​ 当系统完成开机后,还想要让系统额外执行某些程序的话,可以将该程序指令或脚本的绝对路径名称写入到 /etc/rc.d/rc.local 这个文件去。新的 systemd 机制中,它建议直接写一个 systemd 的启动脚本配置文件到 /etc/systemd/system 底下,然后使用systemctl enable 的方式来设定启用它,而不要直接使用 rc.local 这个文件啦。但systemd也是兼容了rc.local这个文件,主要靠rc-local.service这个服务,这个服务不需要启动,它会自己判断 /etc/rc.d/rc.local 是否具有可执行的权限来判断要不要启动这个服务。

#先看一下 /etc/rc.d/rc.local 的权限,然后检查 multi-user.target 有没有这个服务
[root@localhost ~]# ll /etc/rc.d/rc.local
-rw-r--r--. 1 root root 500 Jan  6 21:47 /etc/rc.d/rc.local

[root@localhost ~]# systemctl status rc-local.service
● rc-local.service - /etc/rc.d/rc.local Compatibility
   Loaded: loaded (/usr/lib/systemd/system/rc-local.service; static; vendor preset: disabled)
   Active: inactive (dead)

#有这个服务,但是 rc.local 不具有可执行 (x) 的权限,因此这个服务不会被执行
[root@localhost ~]# systemctl list-dependencies multi-user.target | grep rc-local
[root@localhost ~]# chmod a+x /etc/rc.d/rc.local; ll /etc/rc.d/rc.local
-rwxr-xr-x. 1 root root 500 Jan  6 21:47 /etc/rc.d/rc.local

#重新加载配置文件(/usr/lib/systemd/system/下)
[root@localhost ~]# systemctl daemon-reload

#这个服务已被记录到启动的环境下
[root@localhost ~]# systemctl list-dependencies multi-user.target | grep rc-local
● ├─rc-local.service

Tips:通过这个 chmod a+x /etc/rc.d/rc.local 的步骤,许多脚本就可以放在 /etc/rc.d/rc.local 这个文件内,系统在每次开机都会去执行这文件内的命令。


10.8.2.5 Systemd 启动 graphical.target 下的服务

​ 如果你的 default.target 是 multi-user.target 的话,那么这个步骤就不会进行。反之,如果是graphical.target 的话,那么 systemd 就会开始加载用户管理服务与图形界面管理员 (window display
manager, DM) 等,启动图形界面来让用户以图形界面登入系统!

​ 到此为止,systemd 就已经完整的处理完毕,你可以使用图形界面或文字界面的方式来登入系统,系统也顺利的开机完毕, 也能够将你写入到 /etc/rc.d/rc.local 的脚本实际执行一次。

如果默认是图形界面 (graphical.target) ,但是想要关掉而进入文字界面 (multi-user.target) 呢?

答:使用 systemctl isolate multi-user.target 或者 init 3 ,但实际执行还是systemctl isolate multi-user.target


10.8.3 总结

简化记忆的开机流程

  1. 开机自检(BIOS自检)
  2. MBR/GPT引导系统启动
  3. GRUB菜单(选择内核,进入救援模式)
  4. 加载内核镜像 (加载/boot下内容到内存中)
  5. 运行第1个进程:systemd
  6. 读取运行级别: 多用户模式即可。
  7. 系统初始化:ip,主机名,fstab挂载。
  8. 启动服务(并行)
  9. 显示登陆界面(getty 运行login界面)

开机流程图

image-20230204203607769


10.9 网络管理

10.9.1 OSI与TCP知识
OSI定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层),即ISO开放互连系统参考模型。 每一层实现各自的功能和协议,并完成与相邻层的接口通信。OSI的服务定义详细说明了各层所提供的服务。某一层的服务就是该层及其下各层的一种能力,它通过接口提供给更高一层。各层所提供的服务与这些服务是怎么实现的无关。

img


TCP/IP五层协议和OSI的七层协议对应关系

img


在每一层实现的协议也各不同,即每一层的服务也不同,下图列出了每层主要的协议。

img


10.9.2 数据通信过程

发送方数据封装过程

image-20220725221935146

假设你正在通过网页浏览器访问华为官网,当你输入完网址,敲下回车后,计算机内部会发生下列事情:

  1. 浏览器(应用程序)调用HTTP(应用层协议),完成应用层数据的封装(图中DATA还应包括HTTP头部,此处省略) 。

  2. HTTP依靠传输层的TCP进行数据的可靠性传输,将封装好的数据传递到TCP模块。

  3. TCP模块给应用层传递下来的Data添加上相应的TCP头部信息(源端口、目的端口等)。此时的PDU被称作Segment(段)。

  4. 在IPv4网络中,TCP模块会将封装好的Segment传递给网络层的IPv4模块(若在IPv6环境,会交给IPv6模块进行处理)。

  5. IPv4模块在收到TCP模块传递来的Segment之后,完成IPv4头部的封装,此时的PDU被称为Packet(包)。

  6. 由于使用了Ethernet作为数据链路层协议,故在IPv4模块完成封装之后,会将Packet交由数据链路层的Ethernet模块(例如以太网卡)处理。

  7. Ethernet模块在收到IPv4模块传递来的Packet之后,添加上相应的Ethernet头部信息和FCS帧尾,此时的PDU被称为Frame(帧)。

  8. 在Ethernet模块封装完毕之后,会将数据传递到物理层。

  9. 根据物理介质的不同,物理层负责将数字信号转换成电信号,光信号,电磁波(无线)信号等。

  10. 转换完成的信号在网络中开始传递。


中间网络数据传输

image-20220725222221788

一般情况下:

网络中的二层设备(如以太网交换机)只会解封装数据的二层头部,根据二层头部的信息进行相应的“交换”操作。

网络中的三层设备(如路由器)只会解封装到三层头部,并且根据三层头部的信息进行相应的“路由”操作。


接收方数据解封装过程

image-20220725222334547

​ 经过中间网络传递之后,数据最终到达目的服务器。根据不同的协议头部的信息,数据将被一层层的解封装并做相应的处理和传递,最终交由WEB服务器上的应用程序进行处理。


10.9.3 域名解析过程

以下过程建立在每一个环节都没有的情况下进行到下一个步骤

  1. 用户访问域名www.hexun.com
  2. 主机会查询本地DNS缓存,进行查询本地Hosts文件
  3. 询问本地DNS(网卡配置上的,也许是路由器内网的IP,或者是DNS提供商的IP)
  4. 本地DNS直接询问根域名解析服务器(询问13个根域名服务器),根域名解析服务器也不知道,但它知道顶级域com的DNS服务器(返回该DNS的IP地址)
  5. 本地DNS根据返回的IP进行询问顶级域com的DNS服务器,它也不知道,但它知道hexun.com对应DNS服务器IP(返回该DNS的IP地址,通常是你域名服务提供商的DNS服务器)
  6. 询问hexun.com对应DNS服务器,这次它知道了www.hexun.com域名对应的IP,最后进行返回给本地DNS服务器
  7. 本地DNS会进行缓存,最终返回给用户使用。

Tips:每一次访问不一定都要经过以上的全过程查询,通常在本地设置的DNS当中就能查询到,除非此域名没有人经过你设置的本地DNS服务器进行查询,本地DNS中自然没有这个域名对应的解析条目缓存。那才会进行迭代查询!

小知识:Winodow可用ipconfig /displaydns命令查询缓存


递归查询与迭代查询

(1)递归查询
如果主机所询问的本地DNS服务器不知道被查询的域名对应的IP地址,那么该服务器会询问其他服务器(即替主机继续查询,而不是让主机自己进行下一步查询),并将返回的查询结果提交给客户机。

(2)迭代查询
DNS 服务器会向客户机提供其他能够解析查询请求的DNS 服务器地址,当客户机发送查询请求时,DNS 服务器并不直接回复查询结果,而是告诉客户机另一台DNS 服务器地址,客户机再向这台DNS 服务器提交请求,依次循环直到返回查询的结果为止。

递归查询:一般发生在客户端到本地DNS服务器。
迭代查询:一般发生在本地DNS服务器向根/顶级域名服务器请求。


10.9.4 用户访问网站流程

image-20230207014950944

image-20230207014825406

域名解析跟踪过程

[root@localhost ~]# dig +trace www.zhipin.com
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> +trace www.zhipin.com
;; global options: +cmd
.			158815	IN	NS	d.root-servers.net.
.			158815	IN	NS	e.root-servers.net.
.			158815	IN	NS	f.root-servers.net.
.			158815	IN	NS	g.root-servers.net.
.			158815	IN	NS	h.root-servers.net.
.			158815	IN	NS	i.root-servers.net.
.			158815	IN	NS	j.root-servers.net.
.			158815	IN	NS	k.root-servers.net.
.			158815	IN	NS	l.root-servers.net.
.			158815	IN	NS	m.root-servers.net.
.			158815	IN	NS	a.root-servers.net.
.			158815	IN	NS	b.root-servers.net.
.			158815	IN	NS	c.root-servers.net.
;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 31 ms

com.			172800	IN	NS	l.gtld-servers.net.
com.			172800	IN	NS	f.gtld-servers.net.
com.			172800	IN	NS	m.gtld-servers.net.
com.			172800	IN	NS	j.gtld-servers.net.
com.			172800	IN	NS	b.gtld-servers.net.
com.			172800	IN	NS	d.gtld-servers.net.
com.			172800	IN	NS	i.gtld-servers.net.
com.			172800	IN	NS	a.gtld-servers.net.
com.			172800	IN	NS	e.gtld-servers.net.
com.			172800	IN	NS	g.gtld-servers.net.
com.			172800	IN	NS	h.gtld-servers.net.
com.			172800	IN	NS	k.gtld-servers.net.
com.			172800	IN	NS	c.gtld-servers.net.
;; Received 1177 bytes from 199.9.14.201#53(b.root-servers.net) in 261 ms

zhipin.com.		172800	IN	NS	ns3.dnsv4.com.
zhipin.com.		172800	IN	NS	ns4.dnsv4.com.
;; Received 946 bytes from 192.35.51.30#53(f.gtld-servers.net) in 232 ms

www.zhipin.com.		600	IN	A	47.93.136.207
www.zhipin.com.		600	IN	A	47.93.219.89
www.zhipin.com.		600	IN	A	59.110.222.126
www.zhipin.com.		600	IN	A	211.159.143.184
www.zhipin.com.		600	IN	A	39.96.33.114
zhipin.com.		86400	IN	NS	ns3.dnsv4.com.
zhipin.com.		86400	IN	NS	ns4.dnsv4.com.
;; Received 177 bytes from 1.12.0.25#53(ns3.dnsv4.com) in 41 ms

10.9.5 局域网用户上网过程

image-20230207141624741


10.9.6 网络管理命令
10.9.6.1 检查端口
#方法01 
# -l 列出显示处于监听状态的套接字
# -n 不解析服务名称,以数字方式显示端口
# -t 只显示TCP
# -u 只显示TCP
# -p 显示使用套接字的进程
[root@localhost ~]# ss -lntup | grep 22
udp    UNCONN     0      0      192.168.122.1:53                    *:*                   users:(("dnsmasq",pid=1733,fd=5))
tcp    LISTEN     0      5      192.168.122.1:53                    *:*                   users:(("dnsmasq",pid=1733,fd=6))
tcp    LISTEN     0      128       *:22                    *:*                   users:(("sshd",pid=1180,fd=3))
tcp    LISTEN     0      128    [::]:22                 [::]:*                   users:(("sshd",pid=1180,fd=4))

#方法02 强制匹配只有22的
[root@localhost ~]# ss -lntup | grep -w 22
tcp    LISTEN     0      128       *:22                    *:*                   users:(("sshd",pid=1180,fd=3))
tcp    LISTEN     0      128    [::]:22                 [::]:*                   users:(("sshd",pid=1180,fd=4

#方法3 

[root@localhost ~]# lsof -i:22
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1180 root    3u  IPv4  22518      0t0  TCP *:ssh (LISTEN)
sshd    1180 root    4u  IPv6  22520      0t0  TCP *:ssh (LISTEN)
sshd    6298 root    3u  IPv4 922708      0t0  TCP localhost.localdomain:ssh->192.168.100.1:62176 (ESTABLISHED)
sshd    6304 root    3u  IPv4 922734      0t0  TCP localhost.localdomain:ssh->192.168.100.1:62177 (ESTABLISHED)

#不要把ip反向解析为主机名、域名
[root@localhost ~]# lsof -ni:22
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1180 root    3u  IPv4  22518      0t0  TCP *:ssh (LISTEN)
sshd    1180 root    4u  IPv6  22520      0t0  TCP *:ssh (LISTEN)
sshd    6298 root    3u  IPv4 922708      0t0  TCP 192.168.100.111:ssh->192.168.100.1:62176 (ESTABLISHED)
sshd    6304 root    3u  IPv4 922734      0t0  TCP 192.168.100.111:ssh->192.168.100.1:62177 (ESTABLISHED)

#不要把ip反向解析为主机名、域名,端口不解析成服务名
[root@localhost ~]# lsof -nPi:22
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1180 root    3u  IPv4  22518      0t0  TCP *:22 (LISTEN)
sshd    1180 root    4u  IPv6  22520      0t0  TCP *:22 (LISTEN)
sshd    6298 root    3u  IPv4 922708      0t0  TCP 192.168.100.111:22->192.168.100.1:62176 (ESTABLISHED)
sshd    6304 root    3u  IPv4 922734      0t0  TCP 192.168.100.111:22->192.168.100.1:62177 (ESTABLISHED)

10.9.6.2 检查是否可以访问端口
#方法01
[root@localhost ~]# telnet 192.168.100.111 22  #检查是否有connected 标记
Trying 192.168.100.111...
Connected to 192.168.100.111.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.4

#方法02
[root@localhost ~]# nc 192.168.100.111 22  #nc一般用于shell脚本中检查端口是否开启。
SSH-2.0-OpenSSH_7.4

#方法03
#nmap网络扫描工具
[root@localhost ~]# nmap -p22 192.168.100.111
PORT  STATE SERVICE
22/tcp open  ssh  #nmap结果中只要有端口 open就是开启 。

#nmap进阶使用
nmap -p1-1024 192.168.100.111
nmap  -p22 192.168.100.0/24  jd.com taobao.com

10.9.6.3 检查TCP会话连接状态
[root@localhost ~]# ss -ant
State      Recv-Q Send-Q               Local Address:Port                              Peer Address:Port
LISTEN     0      128                              *:111                                          *:*
LISTEN     0      5                    192.168.122.1:53                                           *:*
LISTEN     0      128                              *:22                                           *:*
LISTEN     0      128                      127.0.0.1:631                                          *:*
LISTEN     0      100                      127.0.0.1:25                                           *:*
LISTEN     0      128                      127.0.0.1:6011                                         *:*
ESTAB      0      0                  192.168.100.111:22                               192.168.100.1:62177
ESTAB      0      48                 192.168.100.111:22                               192.168.100.1:62176
LISTEN     0      128                           [::]:111                                       [::]:*
LISTEN     0      128                           [::]:22                                        [::]:*
LISTEN     0      128                          [::1]:631                                       [::]:*
LISTEN     0      100                          [::1]:25                                        [::]:*
LISTEN     0      128                          [::1]:6011                                      [::]:*

[root@localhost ~]# netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN
tcp        0      0 192.168.122.1:53        0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:6011          0.0.0.0:*               LISTEN
tcp        0      0 192.168.100.111:22      192.168.100.1:62177     ESTABLISHED
tcp        0     64 192.168.100.111:22      192.168.100.1:62176     ESTABLISHED
tcp6       0      0 :::111                  :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 ::1:631                 :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN
tcp6       0      0 ::1:6011                :::*                    LISTEN

#企业案例: 网站并发情况,同一时间内,用户连接数量.
#方法:统计estab状态的连接数量(一般是80/443)端口.
[root@localhost ~]# ss -ant | grep -i estab
ESTAB      0      0      192.168.100.111:22                 192.168.100.1:62177
ESTAB      0      48     192.168.100.111:22                 192.168.100.1:62176
[root@localhost ~]# ss -ant | grep -i estab | wc -l
2

10.9.6.4 监控网络流量情况
iftop
iftop -n #不要把ip反向解析为域名/主机名
iftop -N #不要把端口解析为服务名字
iftop -P #显示端口
iftop -B #以Bytes为单位显示流量(默认是bits)
iftop -i eth0 #指定网卡

#最终常用
iftop -nNP -i eth0  #显示端口号,不要把ip解析为域名,不要把端口解析为服务, 监视指定网卡eth0

#其他界面按键
# t:按三下,有三种网络情况,上行、下行、双向
# p:开关port显示
# n:开关dns解析
# N:开关port解析服务名

10.9.6.5 查看进程的流量情况

第一种:nethogs ,需另外安装软件包,可以直接看pid、哪个用户运行的、哪个程序、哪个网卡的流量、上行和下行。


第二种:利用iftop、ss、ps组合(不推荐)

#1.看看哪个进程链接流量高,得知端口号
[root@localhost ~]# iftop -nNPB -i eth0 

#2.ss找出端口对应的进程号(pid)
[root@localhost ~]# ss -lntup | grep -w 22
tcp    LISTEN     0      128       *:22                    *:*                   users:(("sshd",pid=1180,fd=3))
tcp    LISTEN     0      128    [::]:22                 [::]:*                   users:(("sshd",pid=1180,fd=4))

#3.ps根据pid过滤进程名字
[root@localhost ~]# ps aux | grep 1180
root       1180  0.0  0.1 112900  4364 ?        Ss   Feb06   0:00 /usr/sbin/sshd -D
root      63099  0.0  0.0 112816   980 pts/1    S+   22:57   0:00 grep --color=auto 1180

posted @ 2023-07-17 21:21  YinJayChen  阅读(127)  评论(0编辑  收藏  举报