L B T

记 录 过 去 的 经 验

环境信息

  • Centos 7
  • Prometheus 2.44.0
  • node_exporter-1.6.0

node_exporter 安装

安装 node_exporter 官方文档

以下步骤演示安装 node_exporter 并使用 systemd 管理服务

wget https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz

tar -xf node_exporter-1.6.0.linux-amd64.tar.gz

cp node_exporter-1.6.0.linux-amd64/node_exporter /usr/bin/

生成 systemd 服务配置文件 /usr/lib/systemd/system/node_exporter.service

/usr/lib/systemd/system/node_exporter.service
[Unit]
Description=node_exporter
After=syslog.target
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/node_exporter
Restart=always
RestartSec=10
StartLimitInterval=100

[Install]
WantedBy=multi-user.target

执行以下命令管理服务

$ systemctl daemon-reload

$ systemctl status node_exporter
● node_exporter.service - node_exporter
Loaded: loaded (/usr/lib/systemd/system/node_exporter.service; disabled; vendor preset: disabled)
Active: inactive (dead)

$ systemctl enable --now node_exporter
Created symlink from /etc/systemd/system/multi-user.target.wants/node_exporter.service to /usr/lib/systemd/system/node_exporter.service.

$ systemctl status node_exporter
● node_exporter.service - node_exporter
Loaded: loaded (/usr/lib/systemd/system/node_exporter.service; enabled; vendor preset: disabled)
Active: active (running) since Fri 2023-06-23 10:34:08 CST; 2s ago
Main PID: 28578 (node_exporter)
CGroup: /system.slice/node_exporter.service
└─28578 /usr/bin/node_exporter

node_exporter 配置信息

启动参数详解

参数 说明 示例
--web.listen-address=":9100" node_exporter 监听端口,默认 9100
--web.telemetry-path="/metrics" prometheus 获取 Metrics 访问的 url,默认 /metrics
--log.level="info" 日志级别
--log.format="logger:stderr" 日志打印格式
--collector.disable-defaults 关闭默认的采集项
--no-collector.${item} 关闭某一项默认开启的采集项 --no-collector.cpu
--collector.systemd.unit-include="(docker'|'sshd).service" 收集指定服务的指标

可以配置通过正则表达式屏蔽或者选择某些监控项 [1]

参数 说明 示例
--collector.diskstats.ignored-devices="^(ram'|'loop'|')\\d+$" 忽略某些磁盘的信息收集
--collector.filesystem.ignored-mount-points="^/(dev'|'proc'|')($'|'/)" 忽略某些文件系统挂载点的信息收集
--collector.filesystem.ignored-fs-types="^(autofs'|'proc)$" 忽略某些文件系统类型的信息收集
--collector.netclass.ignored-devices="^$" 忽略某些网络类的信息收集
--collector.netdev.ignored-devices="^$" 忽略某些网络设备的信息收集
--collector.netstat.fields="^$" 配置需要获取的网络状态信息
--collector.vmstat.fields="^(oom_kill'|'pgpg'|'pswp).*" 配置 vmstat 返回信息中需要收集的选项

功能对照表

默认开启的功能

默认开启的功能 [1]

名称 说明 系统
arp /proc/net/arp 中收集 ARP 统计信息 Linux
conntrack /proc/sys/net/netfilter/ 中收集 conntrack 统计信息 Linux
cpu 收集 cpu 统计信息 Darwin, Dragonfly, FreeBSD, Linux
diskstats /proc/diskstats 中收集磁盘 I/O 统计信息 Linux
edac 错误检测与纠正统计信息 Linux
entropy 可用内核熵信息 Linux
exec execution 统计信息 Dragonfly, FreeBSD
filefd /proc/sys/fs/file-nr 中收集文件描述符统计信息 Linux
filesystem 文件系统统计信息,例如磁盘已使用空间 Darwin, Dragonfly, FreeBSD, Linux, OpenBSD
hwmon /sys/class/hwmon/ 中收集监控器或传感器数据信息 Linux
infiniband 从 InfiniBand 配置中收集网络统计信息 Linux
loadavg 收集系统负载信息 Darwin, Dragonfly, FreeBSD, Linux, NetBSD, OpenBSD, Solaris
mdadm /proc/mdstat 中获取设备统计信息 Linux
meminfo 内存统计信息 Darwin, Dragonfly, FreeBSD, Linux
netdev 网口流量统计信息,单位 bytes Darwin, Dragonfly, FreeBSD, Linux, OpenBSD
netstat /proc/net/netstat 收集网络统计数据,等同于 netstat -s Linux
sockstat /proc/net/sockstat 中收集 socket 统计信息 Linux
stat /proc/stat 中收集各种统计信息,包含系统启动时间,forks, 中断等 Linux
textfile 通过 --collector.textfile.directory 参数指定本地文本收集路径,收集文本信息 any
time 系统当前时间 any
uname 通过 uname 系统调用, 获取系统信息 any
vmstat /proc/vmstat 中收集统计信息 Linux
wifi 收集 wifi 设备相关统计数据 Linux
xfs 收集 xfs 运行时统计信息 Linux (kernel 4.4+)
zfs 收集 zfs 性能统计信息 Linux

默认关闭的功能

默认关闭的功能 [1]

名称 说明 系统
bonding 收集系统配置以及激活的绑定网卡数量 Linux
buddyinfo /proc/buddyinfo 中收集内存碎片统计信息 Linux
devstat 收集设备统计信息 Dragonfly, FreeBSD
drbd 收集远程镜像块设备(DRBD)统计信息 Linux
interrupts 收集更具体的中断统计信息 Linux,OpenBSD
ipvs /proc/net/ip_vs 中收集 IPVS 状态信息,从 /proc/net/ip_vs_stats 获取统计信息 Linux
ksmd /sys/kernel/mm/ksm 中获取内核和系统统计信息 Linux
logind logind 中收集会话统计信息 Linux
meminfo_numa /proc/meminfo_numa 中收集内存统计信息 Linux
mountstats /proc/self/mountstat 中收集文件系统统计信息,包括 NFS 客户端统计信息 Linux
nfs /proc/net/rpc/nfs 中收集 NFS 统计信息,等同于 nfsstat -c Linux
qdisc 收集队列推定统计信息 Linux
runit 收集 runit 状态信息 any
supervisord 收集 supervisord 状态信息 any
systemd systemd 中收集设备系统状态信息 Linux
tcpstat /proc/net/tcp/proc/net/tcp6 收集 TCP 连接状态信息 Linux

配置示例

采集白名单配置

关闭默认的采集项,只开启指定的采集项(白名单)

node-exporter --collector.disable-defaults --collector.cpu --collector.meminfo
阅读全文 »

CPU

Flame Graphs

Flame Graphs(火焰图)是一种展示 CPU 性能的 Profile 方法。可以帮助我们找到 CPU 性能瓶颈并进行优化。它展示的不仅仅是 CPU 问题,还能根据 CPU 的使用路径(footprints)找到隐藏在 CPU 之后的问题,如 锁争用(lock contention) 问题可以通过在旋转路径(spin path)中查找 CPU time、 内存问题 可以通找到内存分配函数(malloc())过度使用 CPU 时间进行分析,进而找到对应的导致问题的代码路径。

Linux Perf Analysis in 60 Seconds

下表列出了在检查性能问题的最初的 60s 内可以执行的检查,这些检查都是基于 Linux 上的基础工具 [1]

# Tool Check Refer
1 uptime 检查系统负载,确定系统负载变化(增加或者减少)
2 dmesg -T
journalctl -k
检查内核日志中的错误信息,如 OOM 等
3 vmstat -SM 1 系统级别的统计数据,包括 运行队列长度(run queue length),swapping,CPU 使用率等
4 mpstat -P ALL 1 每个 CPU 的负载情况
5 pidstat 1 每个任务(Per-process)的 CPU 使用率
6 iostat -sxz 1 硬盘 IO 统计: IOPS、吞吐量(Throughput)、Average Wait Time、Percent Busy
7 free -m 内存使用情况
8 sar -n DEV 1 网络设备 IO 统计
9 sar -n TCP,ETCP 1 TCP 统计: Connection Rates、Retransimits
10 top
htop
整体检查

参考链接

Systems Performance: Enterprise and the Cloud v2

脚注


  1. 1.#1.10.1 Linux Perf Analysis in 60 Seconds

计算机启动(上电)后,需要固件(firmware)程序来 初始化硬件 以及选择 需要启动的 Operating System

曾经最流行的固件(firmware)程序是 BIOS(Basic Input Output System),最近 BIOS 正在逐渐被 UEFI(Unified Extensible Firmware Interface)取代。在同一个计算机上,他们只能使用一个(互斥)

UEFI 设计包含安全启动特性(Secure Boot Feature),他可以确保 只有所有组建都进行过有效签名的 OS 才能启动过程中被加载 。此特性也可以禁用以启动未经签名的 OS.

BIOS 或者 UEFI 的主要工作是 初始化硬件并将计算机控制权移交给 Boot Loader ,之后 Boot Loader 会寻找并启动 Operating System.

BIOS 或者 UEFI 通常可以在计算机上电启动后进行配置,一般通过特定的按键(如 F1、F2、F12 等)进入设定界面。主要包含 2 部分内容

  • Bios/UEFI 配置工具 : 可以修改 BIOS/UEFI 设定,如启用/禁止某些功能
  • Boot Order : 修改启动顺序,如从特定设备(CD、DVD、USB 等)启动

BIOS

BIOS 是位于主板(motherboard)上的一个芯片,负责初始化 CPU(Central Processing Unit)、RAM(Random Access Memory)、PCIE Card(Peripheral Component Interconnect Express Card)和 Network Devices. BIOS 通电后后会立即执行 POST(Power-on self test),确保硬件(CPU、RAM、PCIE、NIC等)配置正确并可正常运行。

  • BIOS 仅支持运行于 16 位处理器模式下 ,这限制了任一时刻固件上运行的软件命令(Software Commands)的数量。
  • BIOS 为任务运行只分配 1M 内存
  • BIOS 运行中的接口和设备(Interfaces and Devices)只能按顺序初始化 ,可能会导致开机缓慢
  • BIOS 查找 MBR(Master Boot Record)以确定 OS 的位置并运行 Boot Loader 。MBR 只有 32-bit 的空间用于描述分区(Partitions)的信息,这限制了基于 BIOS 启动的系统,最多支持 4 个主分区(3 个主分区和 1 个逻辑分区),并且分区最大不能超过 2TB.

UEFI

UEFI 最初由 Intel 提出并实现,包括 GPT(Globally Unique Identifier Partition Table),是 UEFI 的一部分。

UEFI 是一个软件(标准)或者说更像是一个微型的系统,用于连接 计算机固件(Computer’s firmware)OS(Operating System) 。UEFI 最终会替代 BIOS 但是向后兼容 BIOS。

UEFI 的功能是通过安装在主板(motherboard)上的特殊固件(firmware)实现的,和 BIOS 一样,其在(生产)出厂之时就已经安装,它是计算机开机(上电)运行的 第一个程序执行和 BIOS 同样的自检(POST)流程,但是它提供了比 BIOS 更多的灵活性 。 UEFI 解决了 BIOS 面临的一些限制,如 最大分区BIOS 执行任务的时间

大多数现代化的计算机都已经能同时支持 BIOS 和 UEFI(二选一)。

UEFI 定义了一种新的 OS 和 计算机固件(platform firmware)交流的方式,相比于 BIOS 只能提供 OS 启动过程中必须的信息,UEFI 可以提供更多的特性,如安全启动等。

UEFI 将其初始化数据存放在一个 EFI 分区中,而不是存放在固件(Firmware)中,这个 EFI 分区位于 Nonvolatile Flash Memory ,UEFI 甚至可以在启动时从一个共享网络位置加载。

UEFI 使用比 MBR 更灵活的分区方案,即著名的 GPT(Globally Unique Identifier Partition Table),GPT 使用了 64-bit 用于保留分区表信息,支持多达 128 个分区,并支持系统识别并安装于超过 2TB 的分区之上。

UEFI 能在一个 EFI 系统分区中支持多个 OS,如 Windows OS loader 或者 Debian-based OS loaders,BIOS 只允许存在一个 Boot Loader.

UEFI 是可编程的(Programmable),其相当于一个轻量的 OS.

UEFI 的安全启动(Secure Boot)支持计算机在启动时对其硬件和系统完整性进行校验,可以防止黑客在系统启动时安装 rootkits 并获得系统控制权,Secure Boot 甚至支持授权用户(网络)远程定位问题。

UEFI 包含了一个平台相关(platform-related)的 数据表(data table) ,以及 可以被 OS Loader 调用的 Boot and Runtime Service Calls 。这些信息定义了为支持 UEFI ,固件(Firmwares)或者计算机硬件(Hardwares)应该实现的接口和数据结构(Interfaces and Structures)。

阅读全文 »

boot loader 在计算机启动的时候决定如何运行(启动)安装于硬盘上的操作系统,GRand Unified Bootloader(GRUB)是 Linux 中最流行的 Bootloader 程序。目前主要有 2 个 GRUB 版本:

  • GRUB Legacy : 遗留版本 GRUB v1,在较旧的 Linux 发行版中使用
  • GRUB 2 : 当前最新版本,较新的 Linux 发行版中默认的 Bootloader. GRUB 2 的主要功能依旧是 查找并启动已安装在计算机上的操作系统 。同时 通过内嵌了一些工具和配置文件提供了更强大的功能以及灵活性

相比于 GRUB Legacy,GRUB 2 有以下优点:

  • 脚本支持 。支持脚本语言如 函数循环变量
  • 模块动态加载(Dynamic Module Loading)
  • 救援模式(Rescue Mode)
  • 自定义菜单(Custom Menus)
  • 主题(Thems)
  • 图形化的启动菜单
  • 直接从硬盘启动 LiveCD ISO
  • 全新的配置文件结构
  • Non-x86 架构支持,如 PowerPC
  • 全局 UUIDs 支持

GRUB 2 的配置文件是 /boot/grub/grub.cfg 或者 /boot/grub2/grub.cfg,关于其配置文件,要注意以下事项:

  • /boot/grub/grub.cfg 的内容是由工具 grub-mkconfig 或者 update-grub 根据 /etc/default/grub/etc/grub.d/ 中的内容自动生成,最好不要手动改动 /boot/grub/grub.cfg。要修改控制选项,可以修改 /etc/default/grub/etc/grub.d/*,然后使用 update-grub
  • /boot/grub/grub.cfg 的内容会因为 GRUB 2 的包升级(如内核升级导致新增内核或移除内核)而被覆盖,或者用户使用 update-grub 命令也会覆盖
  • 可用的启动内核列表(/boot/grub/grub.cfg 中的 menuentry)是由命令 update-grubupdate-grub2(一般是 grub 的软链接)自动生成
  • 用户可以在 OS 启动列表中自定义添加启动条目(menu entry),这个功能一般是通过修改 /etc/grub.d/40_custom 实现
  • 控制启动列表显示菜单的选项位于主配置文件 /etc/default/grub
  • 和 GRUB Legacy 不同,GRUB 2 分区(partitions)编号从 1 开始,而不是 0。但是 硬盘编号 依旧从 0 开始 。如系统上的第一个硬盘的第一个分区,GRUB Legacy 中是 hd(0, 0),GRUB 2 中是 hd(0, 1)
  • grub.cfg 中可以包含 Shell 脚本语法,如 函数,循环,变量等
  • 用于定位内核(Kernels)和 Initial RAM 位置的设备名称,最好是使用更加可靠的 标签(Labels) 或者是 UUIDs(Universally Unique Identifiers) ,而不是类似于 /dev/sda 的设备名称,这可以防止计算机系统新增硬盘后,/dev/sda 变成了 /dev/sdb 而导致系统启动时内核无法找到。
  • 配置文件更改后,只有执行了 update-grub 后才会最终生效

GRUB 2 配置流程

GRUB 2 的配置变更主要是通过修改主配置文件 /etc/default/grub 以及包含自定义脚本文件的目录 /etc/grub.d/,然后执行 update-grub 最终生效。update-grub 会从 /etc/default/grub/etc/grub.d/ 收集相关配置并将其更新到 /boot/grub/grub.cfg

启动菜单(Menu Display)的展示行为主要是通过 /etc/default/grub 进行控制

阅读全文 »

检查命令依赖的共享库

以下命令检查 crontab 命令依赖的共享库

# ldd `which crontab`
linux-vdso.so.1 (0x00007ffe2db17000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007063f4c00000)
/lib64/ld-linux-x86-64.so.2 (0x00007063f4fc3000)

PAM(Pluggable Authentication Modules) 由 Sun Microsystems 发明并最初在 Solarise OS 上实现,Linux 于 1997 年实现了 Linux-PAM.

PAM 简化了系统认证管理的过程,使用 PAM 提供了以下好处:

  • 使用中心化的方式简化了用户身份认证过程以及系统管理员的视角
  • 简化了应用在认证相关功能方面的开发,开发者无需重复写认证相关代码,只需要直接使用已有的认证模块即可
  • 认证灵活性
    • 可以根据用户身份或者是特定的时间,或者是对特定资源的使用进行允许/拒绝操作

包含 PAM 的应用中 PAM 使用流程大体如下

  • 一个主体(用户或者进程)请求访问(通过认证)一个应用
  • 此应用读取其 PAM 配置文件,其 PAM 配置文件中配置了认证策略,认证策略中一般包含要进行认证的 PAM 模块的列表,这个列表也称为 Stack
  • Stack 中配置的 PAM 模块被依次调用
  • 每个 PAM 模块会根据其配置返回 成功(Success) 或者 失败(Failure) 状态
  • 最后是否认证成功,由所有的 PAM 模块返回的结果组合得到 成功(Success) 或者 失败(Failure) ,具体组合方式取决于配置文件中的配置。

Linux 中,大多数包含 PAM 的应用的配置文件位于 /etc/pam.d/,通用的 PAM 配置文件格式使用:

context 'control flag' 'PAM module' [module options]

Linux 中,系统安全(如资源限制,用户登陆等)相关的 PAM 配置文件位于 /etc/security/*.conf

PAM Contexts

PAM 模块为不同的认证服务提供了标准的函数,这些 PAM 模块中的标准函数根据其函数类型称为 Contexts,也可以叫做 Module Interfaces 或者 Types,下列出了不同的 PAM Contexts 及其对应的 认证服务(Authentication Service)

Context Service Description
auth 提供认证管理服务(Authentication Management Services),如验证帐号密码
account 帐号验证服务(Account Validation Services),例如只允许特定时间登陆
password 管理帐号密码(Manages Account Passwords),如限制帐号密码长度

PAM Control Flags

PAM 中的 Control Flags 用于决定返回什么样的状态。下表列出了 PAM 配置中的相关的 Control Flags 及其响应

Control Flag Response Handle
required If failed, returns a failure status to the application, after the rest of the contexts have been run in the stack.
For example, a requisite control might cause a login to fail if someone types in an invalid user. But the user might not be told of the failure until after entering a password, hiding the fact that it was the bad username that caused the failure
requisite If failed, returns a failure status to the application immediately without running the rest of the stack(Be careful where you place this control in the stack.)
For example, a requisite control might require key-based authentication and fail immediately when a valid key is not provided . In that case, it could fail before even prompting for a username/password.
sufficient - If failed, the module status is ignored.
- If successful, then a success status is immediately returned to the application without running the rest of the stack.
(Be careful where you place this control in the stack.)
optional This control flag is important only for the final overall return status of success or failure . Think of it as a tiebreaker. When the other modules in the configuration file stack return statuses that are neither clear-cut failure nor success statuses, this optional module’s status is used to determine the final status or break the tie. In cases where the other modules in the stack are returning a clear-cut path of failure or success, this status is ignored.
include Get all the return statuses from this particular PAM configuration file’s stack to include in this stack’s overall return status. It’s as if the entire stack from the named configuration file is now in this configuration file
substack Similar to the include control flag, except for how certain errors and evaluations affect the main stack. This forces the included configuration file stack to act as a substack to the main stack. Thus, certain errors and evaluations affect only the substack and not the main stack.

PAM Modules

Linux 中,PAM Modules 其实是系统共享库(Shared Library Module)文件,RHEL 默认位于 /usr/lib64/security/pam*.so, Ubuntu 位于 /usr/lib/x86_64-linux-gnu/security/pam*.so

# ls /usr/lib/x86_64-linux-gnu/security/
pam_access.so pam_exec.so pam_gdm.so pam_listfile.so pam_nologin.so pam_securetty.so pam_stress.so pam_unix.so
pam_cap.so pam_extrausers.so pam_gnome_keyring.so pam_localuser.so pam_oddjob_mkhomedir.so pam_selinux.so pam_succeed_if.so pam_userdb.so
pam_dcvgraphicalsso.so pam_faildelay.so pam_group.so pam_loginuid.so pam_permit.so pam_sepermit.so pam_systemd.so pam_usertype.so
pam_debug.so pam_faillock.so pam_issue.so pam_mail.so pam_pwhistory.so pam_setquota.so pam_time.so pam_warn.so
pam_deny.so pam_filter.so pam_keyinit.so pam_mkhomedir.so pam_pwquality.so pam_shells.so pam_timestamp.so pam_wheel.so
pam_echo.so pam_fprintd.so pam_lastlog.so pam_motd.so pam_rhosts.so pam_sss_gss.so pam_tty_audit.so pam_xauth.so
pam_env.so pam_ftp.so pam_limits.so pam_namespace.so pam_rootok.so pam_sss.so pam_umask.so

要查看 PAM Module 的帮助文档,可以使用 man 手册,如 man pam_access

使用 PAM 的应用可以大概分为以下 2 类:

  • 普通程序(Application) 。默认使用 PAM 的应用的配置位于 /etc/pam.d,每个使用 PAM Module 的应用程序都应该有其自己的配置文件来定义它如何使用 PAM 模块。如果没有,这将是一个漏洞,为了防止这种情况出现,系统内置了一个 other 的配置(/etc/pam.d/other),所有使用了 PAM 但是没有指定其配置文件的应用都将使用此配置。 other 配置默认拒绝(Implicit Deny)所有的请求

    # ls /etc/pam.d/
    chfn common-auth cron gdm-autologin gdm-smartcard login polkit-1 samba sudo
    chpasswd common-password cups gdm-fingerprint gdm-smartcard-pkcs11-exclusive newusers ppp sshd sudo-i
    chsh common-session dcv gdm-launch-environment gdm-smartcard-sssd-exclusive other runuser sssd-shadowutils su-l
    common-account common-session-noninteractive dcv-graphical-sso gdm-password gdm-smartcard-sssd-or-password passwd runuser-l su vmtoolsd

  • 系统安全相关程序 。系统安全相关的 PAM 配置默认位于 /etc/security

    # ls /etc/security/
    access.conf faillock.conf limits.conf namespace.conf namespace.init pam_env.conf sepermit.conf
    capability.conf group.conf limits.d namespace.d opasswd pwquality.conf time.conf

阅读全文 »

加密解密相关常用概念

  • Plain Text : 明文,可以被人类或者激情理解的内容
  • Ciphertext : 密文,加密后的内容,一般不能直接被人类或者机器所理解,需要解密
  • Encryption : 将 Plain Text 转换为 Ciphertext 的过程,通常使用一种加密算法(Encrypt Algorithm)
  • Decryption : 解密,将 Ciphertext 转换为 Plain Text 的过程,通常使用和加密算法(Encrypt Algorithm)相对应的解密算法(Decrypt Algorithms)
  • Cipher : 加密和解密过程中算法使用的密码。
  • Block Cipher : 在对数据进行加密之前,需要首先将其分割成块(Block)
  • Stream Cipher : 加密过程中无需将其分割成块(Block)
  • Key : 通常值密钥对(公钥/私钥)

以下是一些较为经典的加密算法

Algorithm Description
AES
Advanced Encryption Standard, also called Rijndael
- Symmetric Cryptography
- Block Cipher 。encrypting data in 128-, 192-, 256-, 512- bit, blocks using a 128-, 192-, 256, or 512-bit key
Blowfish - Symmetric Cryptography
- Block Cipher 。encrypting data in 64-bit blocks using the same 32-bit to 448-bit keys for encrypting/decrypting.
CAST5 - Symmetric Cryptography
- Block Cipher 。 encrypting data in 64-bit blocks using the same up to 128-bit key for encrypting/decrypting.
DES
Data Encryption Standard
已经被认为是不安全的
- Symmetric Cryptography
- Block Cipher 。encrypting data in 64-bit blocks using the same 56-bit key for encrypting/decrypting.
3DES 增强的 DES 加密算法
- Symmetric Cryptography
Data is encrypted up to 48 times with three different 56-bit keys before the encryption process is completed.
IDEA - Symmetric Cryptography
- Block Cipher 。 encrypting data in 64-bit blocks using the same 128-bit key for encrypting/decrypting
RC5 - Symmetric Cryptography
- Block Cipher 。 encrypting data in 32-, 64-``, or 128- bit blocks ,using the same up to 2,048-bit keys for encrypting/decrypting
RC6 - Symmetric Cryptography
Same as RC5, but slightly faster
EI Gamal - Asymmetric Cryptography
Uses two keys derived from a logarithm algorithm
Elliptic Curve Cryptosystems - Asymmetric Cryptography
Uses two keys derived from an algorithm containing two randomly chosen points on an elliptic curve.
RC4
also called ArcFour or ARC4
- Stream Cipher
encrypting data in 64-bit blocks using a variable key size for encrypting/decrypting.
RSA 最流行的非对称加密算法,使用 Public/Private Key 进行加解密
- Asymmetric Cryptography
阅读全文 »

Hash 不是加密(Encryption),不像 加密(Encrypt)-解密(decrypt)对一个对象进行 Hash 操作后,不可能通过 Hash 后的值 dehash 回原来的对象

Hash 算法需要 Collision Free ,即对两个完全不同的输入,经过 Hash 算法后的值也必须 不同

在 Linux 系统中,用户名秘密验证就是使用 Hash 算法。/etc/shadow 中包含的是用户密码(加 Salt) Hash 后的值,而不是用户密码,当用户使用密码登陆系统时,会计算用户密码(加 Salt)的 Hash 值并和 /etc/shadow 中保存的内容进行对比以验证用户密码是否正确。

Hash 在 Linux 系统中,有以下用途:

  • Passwords 验证
  • 校验文件内容
  • 数字签名
  • 病毒签名

Hash 也有以下叫法:

  • Message Digest : 消息摘要,Linux 中常用的命令如 md5sumsha1sumsha224sumsha256sumsha384sumsha512sumshasum 等应用了不同的 Hash 算法
  • Checksum : 校验和
  • Fingerprint : 数字指纹
  • Signature : 签名

Hash 常见用途示例

内容完整性校验

例如网上公开的 ISO 系统镜像,发布者会同时发布镜像的 SHA-256 Hash 算法摘要值,当你下载了此镜像后,可以在本地对其镜像同样的 Hash 计算(如 sha256sum 命令),如果计算出的值和发布者公布的值一致,说明其内容和发布者发布的镜像内容一致(未被篡改)

$ sha256sum Fedora-Workstation-Live-x86_64-30-1.2.iso
a4e2c49368860887f1cc1166b0613232d4d5de6b46f29c9756bc7cfd5e13f39f
Fedora-Workstation-Live-x86_64-30-1.2.iso

Linux 审计系统提供了一种方式来跟踪系统上与安全相关的信息。根据预配置的规则,审计会生成日志条目,来尽可能多地记录系统上所发生的事件的相关信息。对于关键任务环境而言至关重要,可用来确定安全策略的违反者及其所执行的操作。审计不会为您的系统提供额外的安全,而是用于发现系统上使用的安全策略的违规。可以通过其他安全措施(如 SELinux)进一步防止这些违规。 [1]

以下列表总结了审计可以在其日志文件中记录的一些信息:

  • 事件的日期、时间、类型和结果.
  • 主题和对象的敏感度标签。
  • 事件与触发事件的用户身份的关联。
  • 对审计配置的所有修改,以及对访问审计日志文件的尝试。
  • 所有身份验证机制的使用,如 SSH 和 Kerberos 等。
  • 对任何受信任数据库的修改,如 /etc/passwd。
  • 尝试将信息导入系统或从系统导出。
  • 根据用户身份、主题和对象标签以及其他属性包含或排除事件。

使用案例

  • 监视文件访问
    审计可以跟踪文件或目录是否已被访问、修改、执行或者文件的属性是否已改变。例如,这有助于检测对重要文件的访问,并在其中一个文件损坏时提供审计跟踪。
  • 监控系统调用
    可将审计配置为在每次使用特定系统调用时生成日志条目。例如,这可用于通过监控 settimeofdayclock_adjtime 和其他与时间相关的系统调用来跟踪对系统时间的修改。
  • 记录用户运行的命令
    审计可以跟踪文件是否已被执行,因此可以定义一个规则以记录每次特定命令的执行。例如,可以对 /bin 目录中的每个可执行文件定义一个规则。然后,可以按用户 ID 搜索生成的日志条目,以生成每个用户所执行的命令的审计跟踪。
  • 记录系统路径名称的执行
    除了观察在规则调用时将路径转换为 inode 的文件访问之外,审计现在还可以观察路径的执行,即使路径在规则调用中不存在,或者在规则调用后文件被替换了。这允许规则在升级程序可执行文件后或甚至在其安装之前继续运行。
  • 记录安全事件
    pam_faillock 认证模块能够记录失败的登录尝试。也可以将审计设置为记录失败的登录尝试,并提供有关试图登录的用户的附加信息。
  • 搜索事件
    审计提供了 ausearch 工具,可用于过滤日志条目,并根据多个条件提供完整的审计跟踪。
  • 运行总结报告
    aureport 实用程序可用于生成记录事件的日常报告等。然后,系统管理员可以分析这些报告,并进一步调查可疑的活动。
  • 监控网络访问
    iptablesebtables 工具可以配置为触发审计事件,允许系统管理员监控网络访问。

    系统性能可能会受到影响,具体取决于审计所收集的信息量。

审计系统架构

审计系统由两个主要部分组成: 用户空间应用程序和工具 ,以及 内核端系统调用处理 。内核组件接收用户空间应用程序的系统调用,并通过以下过滤器对其进行过滤: usertaskfstypeexit[1]

用户空间审计守护进程 从内核收集信息,并在日志文件中创建条目。其他审计用户空间工具审计守护进程内核审计组件审计日志文件 进行交互:

  • audisp - Audit 分配程序守护进程与 Audit 守护进程交互,并将事件发送到其他应用程序,以便进一步处理。此守护进程的目的是提供插件机制,以便实时分析程序可以与审计事件交互。
  • auditctl - 审计控制实用程序与内核审计组件交互,以管理规则并控制事件生成进程的多个设置和参数。
  • 其余的审计工具会将审计日志文件的内容作为输入,并根据用户的要求生成输出。例如,aureport 工具生成所有记录的事件的报告。
阅读全文 »

Linux 系统安全加固常用方法

服务网络安全

  • 启用防火墙,并确保入口流量都是必须的,禁止无关的 IP 访问目标主机上的服务(端口)

系统软件安全检测

  • 定期扫描系统上安装的软件,确保关键系统命令未被篡改,例如使用 rpm -Va 对所有系统上的软件进行校验,检查是否有软件被篡改

    # rpm -Va
    .......T. /usr/src/kernels/3.10.0-1160.114.2.el7.x86_64/virt/lib/Kconfig
    .......T. /usr/src/kernels/3.10.0-1160.114.2.el7.x86_64/virt/lib/Makefile
    S.5....T. c /root/.bash_profile
    S.5....T. c /root/.bashrc
    .M....... /var/run/supervisor
    missing /etc/filebeat/fields.yml
    SM5....T. c /etc/filebeat/filebeat.yml
    ....L.... c /etc/pam.d/fingerprint-auth
    ....L.... c /etc/pam.d/password-auth
    ....L.... c /etc/pam.d/postlogin
    ....L.... c /etc/pam.d/smartcard-auth
    ....L.... c /etc/pam.d/system-auth

    输出的每一行对应一个文件,前 9 个字符的字符串显示了该文件的属性状态。每个字符的位置代表了特定的属性检查结果。rpm -Va 对比的是当前系统中文件的状态与 RPM 数据库中记录的文件状态。

    每个字符的含义:

    • 第 1 位 : 文件类型 (S).
      如果文件丢失了,则会显示 S(代表文件缺失,”File is missing”)。
    • 第 2 位:文件大小 (5)
      如果文件大小与 RPM 数据库中的记录不一致,则会显示 5
    • 第 3 位:文件权限(模式/权限位,M)
      如果文件的权限与 RPM 数据库记录的不一致,则会显示 M
    • 第 4 位:文件的所有者 (U)
      如果文件的所有者与 RPM 数据库记录的不一致,则会显示 U
    • 第 5 位:文件所属的组 (G)
      如果文件的所属组与 RPM 数据库记录的不一致,则会显示 G
    • 第 6 位:文件的设备类型 (D)
      如果文件的设备类型(如块设备或字符设备)与 RPM 数据库记录的不一致,则会显示 D
    • 第 7 位:文件的时间戳 (T)
      如果文件的修改时间与 RPM 数据库中的记录不一致,则会显示 T
    • 第 8 位:文件的校验和 (5)
      如果文件内容的校验和与 RPM 数据库记录的不一致,则会显示 5
    • 第 9 位:文件的符号链接 (L)
      如果文件是一个符号链接,并且符号链接目标发生变化,则会显示 L
    • 如果是配置文件,会被标记为 c

文件加固

文件系统加固

Linux 操作系统中的很多目录都有约定的用途,可能会挂载单独的文件系统,不同用途的目录,对权限的要求不同,从安全角度考量,可以针对文件系统进行一定程度的安全加固。

文件系统的挂载,主要依赖配置文件 /etc/fstab,此配置会被 mountdumpfsck 等命令使用,其权限应该设置为 644,属主和属组都应该是 root。在挂载不同用途的文件系统时,可以根据其用途配置权限限制。以下列出部分示例

可用的挂载选项可以查看 man fatabman mountman 5 ext4 等内容中的选项,不同的文件系统支持不同的挂载选项,通用的挂载选项(独立于文件系统)可以查看 man mount 中的 FILESYSTEM-INDEPENDENT MOUNT OPTIONS 部分

  • /home/ 目录下通常是用户家目录,可能会挂载到单独的文件系统,根据其特性,可以配置以下限制
    • nosuid : 禁止其中的文件/目录配置 SUID 或 SGID 权限
    • nodev : 禁止其中的设备被内核识别,放置在此目录下的设备可能都是恶意设备,应该被禁止识别并使用
    • noexec : 禁止此文件系统中的可执行文件执行。
  • /tmp/ 目录也可以设置以下限制
    • nosuid
    • nodev
    • noexec

关键文件审计及监控

auditd 审计

可以使用 `auditd` 服务对系统上的关键文件进行审计日志记录

关键文件监控

系统上的某些关键文件,如常用可执行文件(/sbin/ 下的文件)、关键配置文件等,要监控其是否被恶意修改。可以参考以下方法

  • find 命令搜索文件修改时间
    find 命令的 -mtime 可以查找文件的 内容修改时间

    find 命令的 -ctime 可以查找文件的 创建时间/属性修改时间

    如常用的系统命令不会出现内容的修改和属性的修改,如果出现这些现象,很可能属于恶意篡改,可以使用 find 命令查找或是监控这些变化

    # find /sbin -mtime -1
    /sbin
    /sbin/init
    /sbin/reboot

    在发现关键文件被篡改后可以及时发送告警。可以使用 stat 命令检查文件变更的更详细信息

    # stat /sbin/init
    File: '/sbin/init' -> '../bin/systemd'
    Size: 14 Blocks: 0 IO Block: 4096 symbolic link
    Device: fd01h/64769d Inode: 9551 Links: 1
    Access: (0777/lrwxrwxrwx)
    Uid: ( 0/ root) Gid: ( 0/ root)
    Context: system_u:object_r:bin_t:s0
    Access: 2016-02-03 03:34:57.276589176 -0500
    Modify: 2016-02-02 23:40:39.139872288 -0500
    Change: 2016-02-02 23:40:39.140872415 -0500
    Birth: -

    为了更好的监控关键文件的篡改,可以在系统运行之初就为其创建一个包含关键文件的 mtimesctimes 信息的数据库,并在系统运行过程中通过脚本检测关键文件的 mtimesctimes 并和原始数据库中的信息进行对比已检测文件是否被篡改。通常的 Intrusion Detection System 基本都实现了类似的功能。

    通常需要关注的可以被 find 检查的其他特殊类型文件和特殊权限还可能包括以下事项:

    File or Settings Scan Command Problem With File or Settings
    SUID find / -perm -4000 Allows anyone to become the file’s owner temporarily while the file is being executed in memory
    GID find / -perm -2000 Allows anyone to become a group member of the file’s group temporarily while the file is being executed in memory.
    rhost files find /home -name .rhosts Allows a system to trust another system completely. It should not be in /home directories.
    Ownerless files find / -nouser Indicates files that are not associated with any username.
    Groupless files find / -nogroup Indicates files that are not associated with any group name.

Viruses

ClamAV

ClamAV 是一个开源并免费的 Linux 杀毒(Antivirus Software)软件。

Rootkit

chkrootkit

chkrootkit 是 Linux 上常用的检测 rootkit 的工具,这个工具的结果需要更深入的分析,它可能出错

# chkrootkit | grep INFECTED
Checking 'du'... INFECTED
Checking 'find'... INFECTED
Checking 'ls'... INFECTED
Checking 'lsof'... INFECTED
Checking 'pstree'... INFECTED
Searching for Suckit rootkit... Warning: /sbin/init INFECTED

Rootkit Hunter

Rootkit Hunter 是另一个比较出名的 rootkit 检测工具

Intrusion Detection and Prevention System

入侵检测和防御系统 可以监控系统上的活动并找到潜在的恶意活动或者进程并报告相关活动。Linux 上常用的入侵检测系统有

  • aide : Advanced Intrusion Detection Environment.
  • snort
  • tripwire

进程的内存分层结构

进程的内存结构一般被分成多个 sections,包括

  • Text section - 存放程序代码(the executable code)
  • Data section - 存放全局变量(global variables)
  • Heap section - 程序运行过程中动态分配的内存
  • Stack section - 调用程序功能时的临时数据存储,如函数参数、返回地址、本地变量等。

下图展示了 C 程序(Program)在内存中的分层结构(layout of a C program in memory)

  • 其中, Data section 被分成了 2 部分,包括 (a) initialized data(b) uninitialized data

使用 GNU 工具 size 可以检查 Projram 在磁盘上的 内存布局。这些值在程序编译时确定,并不会在程序运行时变化,因此它们是固定不变的。

# size /usr/sbin/sshd
text data bss dec hex filename
817397 15460 37664 870521 d4879 /usr/sbin/sshd

输出信息中:

  • text : 代表 Text section 的大小
  • data : 初始化数据段(initialized data)的大小,包含已初始化的全局和静态变量。
  • bss : 未初始化数据段的大小,包含未初始化的全局和静态变量。
  • dec : 上述所有部分的总大小,以十进制表示。
  • hex : 上述所有部分的总大小,以十六进制表示。
阅读全文 »

环境信息

  • Centos 7 kernel 5.4.221

启动过程

systemd 管理的系统中,提供了工具 systemd-analyze 用于分析具体的启动过程,使用 systemd-analyze --help 查看使用帮助

检查系统启动时间

使用 systemd-analyze 命令会显示系统启动所用的时间,等同于 systemd-analyze time

# systemd-analyze 
Startup finished in 1.830s (kernel) + 36.827s (userspace) = 38.657s
graphical.target reached after 12.604s in userspace

systemd-analyze blame 列出系统上各个 Unit 启动的时间

# systemd-analyze blame
6.414s wazuh-agent.service
3.161s dracut-initqueue.service
2.473s network.service
1.004s watchdog.service
...
45ms sysstat.service
14ms plymouth-switch-root.service
14ms systemd-journald.service
4ms systemd-logind.service
3ms sys-kernel-config.mount
3ms initrd-udevadm-cleanup-db.service
3ms systemd-random-seed.service
2ms google-shutdown-scripts.service

列出系统各个 Unit 启动消耗的时间

# systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

graphical.target @12.604s
└─multi-user.target @12.601s
└─skylight-agent.service @36.639s
└─network.target @9.073s
└─NetworkManager.service @8.795s +275ms
└─dbus.service @8.788s
└─basic.target @8.774s
└─sockets.target @8.772s
└─snapd.socket @8.766s +5ms
└─sysinit.target @8.669s
└─cloud-init.service @6.850s +1.811s
└─systemd-networkd-wait-online.service @4.970s +1.871s
└─systemd-networkd.service @4.864s +91ms
└─network-pre.target @4.850s
└─cloud-init-local.service @3.228s +1.620s
└─systemd-remount-fs.service @1.113s +93ms
└─systemd-fsck-root.service @1.030s +69ms
└─systemd-journald.socket @853ms
└─-.mount @692ms
└─-.slice @692ms

查看内存信息

内存相关概念说明:

  • VSS ,Virtual Set Size , VIRT - 虚拟耗用内存(包含共享库占用的内存), 通常 VIRT 是系统承诺分配给应用的内存,不是实际使用的内存
  • RSS , Resident Set Size , RES - 实际使用物理内存(包含共享库占用的内存)
  • PSS , Proportional Set Size - 实际使用的物理内存(比例分配共享库占用的内存)。 top 命令中的 SHR 列展示的就是共享库按比例分配给进程的内存
  • USS , Unique Set Size - 进程独自占用的物理内存(不包含共享库占用的内存)

系统内存使用量统计

free

$ free -h
total used free shared buff/cache available
Mem: 15Gi 7.8Gi 707Mi 449Mi 7.0Gi 6.9Gi
Swap: 30Gi 1.0Gi 29Gi

ps

例如查看使用内存排名前十的进程:

ps aux | sort -k4,4nr | head -n 10

sar 命令

使用 sar 命令检查系统上的内存及 Swap 使用情况

查看某个进程使用的内存量

比如检查 docker 使用的内存量,首先通过 ps 命令查询到 docker 的 PID 信息

$ ps -elf | grep docker
4 S root 1243 1 4 80 0 - 1067527 futex_ Jan03 ? 15:14:45 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

例如此处的 docker 进程的 PID 为 1243

  • 使用 top 命令动态查看 docker 使用的内存信息

    $ top -p 1243
    top - 11:47:40 up 14 days, 2:09, 3 users, load average: 0.65, 1.42, 1.70
    Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
    %Cpu(s): 1.0 us, 0.6 sy, 0.0 ni, 98.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    KiB Mem : 32068748 total, 2494500 free, 18536188 used, 11038060 buff/cache
    KiB Swap: 0 total, 0 free, 0 used. 9586340 avail Mem

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
    1243 root 20 0 4270108 1.4g 53956 S 1.0 4.6 914:55.80 dockerd
  • 使用 ps aux 命令查看内存使用量

    $ ps aux | grep 1243
    root 1243 4.5 4.6 4270108 1486460 ? Ssl Jan03 914:57 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

    输出结果中

    • 第 3、4 列 (4.5 4.6) 分别表示 cpu 使用率内存使用率
    • 第 5、6 列 (4270108 1486460) 分别表示 虚拟内存使用量物理内存使用量,单位为 k
  • 通过进程的 status 文件查看内存使用

    $ cat /proc/1243/status
    Name: dockerd
    Umask: 0022
    State: S (sleeping)
    Pid: 1243
    PPid: 1
    VmPeak: 4270364 kB
    VmSize: 4270108 kB
    VmLck: 0 kB
    VmPin: 0 kB
    VmHWM: 1562204 kB
    VmRSS: 1492340 kB
    ...

    其中,VmRSS 为进程使用的物理内存

  • 使用 pmap 命令查看进程使用的内存信息

    pmap -x 1243
    pmap -p 1243
    阅读全文 »

传统的 PC 架构计算机使用 Master Boot Record(MBR)分区表(Partition Tables) 来存储计算机上的 磁盘分区(Disks Partitions) 信息。MBR 有以下特点:

  • MBR 的分区最大支持 2TB 的容量。

最新的 UEFI 计算机架构使用 GUID(Globally Unique Identifier) Partition Tables(GPT) 标准来替代旧的 BIOS 方法启动计算机操作系统。相比于 MBR,GPT 有以下优势及特性:

  • GPT 的分区最大能支持到 9.4ZB

传统的基于 MBR Partition Tables 的最重要的分区工具是 fdisk,但是它目前不支持 GPT Partitions ,新的工具 parted 正在顶替 fdisk 的功能。

parted 用法

要查看 parted 常见用法,可以参考 parted --help 或在交互模式中使用 help 指令

查看分区表信息

要查看系统上的分区信息,使用以下方式之一

  • parted -l
    # parted -l
    Model: Amazon Elastic Block Store (nvme)
    Disk /dev/nvme0n1: 85.9GB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Disk Flags:

    Number Start End Size File system Name Flags
    14 1049kB 5243kB 4194kB bios_grub
    15 5243kB 116MB 111MB fat32 boot, esp
    1 116MB 85.9GB 85.8GB ext4


    Model: Amazon Elastic Block Store (nvme)
    Disk /dev/nvme1n1: 107GB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    Disk Flags:

    Number Start End Size Type File system Flags
    1 1049kB 53.7GB 53.7GB primary ext4


    Model: Unknown (unknown)
    Disk /dev/zram0: 33.2GB
    Sector size (logical/physical): 4096B/4096B
    Partition Table: loop
    Disk Flags:

    Number Start End Size File system Flags
    1 0.00B 33.2GB 33.2GB linux-swap(v1)

  • parted 交互模式,在交互模式中使用指令 p
    # parted 
    GNU Parted 3.4
    Using /dev/nvme0n1
    Welcome to GNU Parted! Type 'help' to view a list of commands.

    (parted) p
    Model: Amazon Elastic Block Store (nvme)
    Disk /dev/nvme0n1: 85.9GB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Disk Flags:

    Number Start End Size File system Name Flags
    14 1049kB 5243kB 4194kB bios_grub
    15 5243kB 116MB 111MB fat32 boot, esp
    1 116MB 85.9GB 85.8GB ext4

    (parted)

创建 GPT 分区格式的硬盘

要使用 parted 对硬盘指定其分区表类型,假设硬盘为 /dev/nvme1n1 (默认表示第二个 NVM(NVMe, NonVolatile Memory Disks express, NVM 磁盘设备专用的通信接口协议) 硬盘的第一个 Namespace),参考以下步骤:

  1. parted /dev/nvme1n1 ,进入交互模式并对指定的硬盘进行分区操作, 以下步骤会导致硬盘上所有的分区及数据丢失
  2. 在交互模式中使用 mklabel gpt 命令,配置硬盘使用 GPT 类型的分区表,而不是 MBR
    (parted) mklabel gpt
    Warning: The existing disk label on /dev/nvme1n1 will be destroyed and all data
    on this disk will be lost. Do you want to continue?
    Yes/No? Yes
    (parted)
  3. 在交互模式中使用 mkpart 命令进行分区操作,分区完成后使用 p 指令检查分区
    (parted) mkpart
    Partition name? []? alldisk
    File system type? [ext2]? xfs
    Start? 1
    End? 123GB

    (parted) p
    Model: SanDisk Ultra (scsi)
    Disk /dev/nvme1n1: 123GB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Disk Flags:
    Number Start End Size File system Name Flags
    1 1049kB 123GB 123GB xfs alldisk
  4. 使用 quit 指令退出 parted 交互模式。

    fdisk 交互模式中,只有最终执行了 w 命令保存,对硬盘的操作才会最终生效,和 fdisk 不同,parted 命令对硬盘的更改立即生效

  5. 对分区进行格式化并挂载使用,如果需要持久化挂载(系统重启后依然生效),可以将挂载信息写入 /etc/fstab
    mkfs -t xfs /dev/nvme1n1p1
    mount /dev/nvme1n1p1 /mnt/

文件权限

在 Linux 系统中,普通的文件权限控制通过关联身份三元组 (user, group,other) 和权限三元组 (r, w, x) 来实现访问控制。

系统存在一个 umask 值(针对用户),umask 是一个权限掩码,它决定了新建的文件或者目录的默认权限,使用 umask 命令可以查看当前(用户) 的 umask

$ umask
0022

比如如上所示的 umask 值,决定了当前(用户)创建的文件和目录的默认权限

  • 目录 - 默认权限为 0755777-022),即 rwxr-xr-x
  • 文件 - 默认权限为 644 (666-022),即 rw-r--r--

因此要配置当前(用户)创建的文件或者目录的默认权限,只需要配置合适的 umask 值即可。配置 umask 值可以通过以下方法

  • 临时方法
    umask 027
  • 永久方法
    根据需求将 umask 027 配置添加到配置文件中,如 /etc/profile~/.bashrc~/.bash_profile

如果需要更进一步的权限控制,需要使用到 Sticky Bit 和 ACL,更细力度的控制还包括 SELinux. 相关扩展权限标志如下:

  • 文件/目录 权限最后会包含一个 . : 表示 SELinux (Security Enhanced Linux)扩展权限。可以使用命令 ls -l -Z 查看具体权限。
  • 文件/目录 权限最后会包含一个 + : 表示 文件/目录ACL(Access Control List) 扩展权限,相关操作及命令参考
  • 目录 权限最后会包含一个 t : 表示此 目录Sticky Bit 扩展权限,相关操作及命令参考
  • 可执行文件 权限中属主(Owner)的 x 位变为 s : 表示此 可执行文件 配置了 Set UID 扩展权限
  • 可执行文件/目录 权限中属组(Group)的 x 位变为 s : 表示此 目录 配置了 Set GID 扩展权限

Linux 文件权限控制中,除了 SELinux 权限,其他权限控制属于 DAC(Discretionary Access Control),SELinux 属于 MAC(Mandatory Access Control),系统执行权限控制的过程中, 如果 DAC 权限允许资源访问,会继续进行 SElinux 权限检查,如果 DAC 权限拒绝资源访问,不会再进行 SELinux 权限检查

Set UID

  • 只有 可执行的二进制程序和可执行的代码 才能设定 SUID 权限。
  • 命令执行者首先要对该程序拥有 x(执行)权限。
  • 命令执行者在执行该程序时获得该程序文件 属主(Owner) 的身份。
  • SetUID 权限只在该程序 执行过程中 有效,也就是说身份改变只在执行过程中有效。

设定 SUID 和 SGID 时,传统的 3 元组权限方式(如 rwxrwxrwx = 777) 变为 4 元组(Srwxrwxrwx),其中的 S 选项包括:

  • 4 代表 SUID,如 4777
  • 2 代表 GID,如 2777
  • 1 代表 Sticky BIT,如 1777
  • 7 代表全部设置, 如 7777

SUID 设定命令格式:

chmod 4777 可执行文件名

chmod u+s 可执行文件名

取消 SUID 设置:

chmod 777 可执行文件名

假如某个可执行文件的属主为 root,其设置了 SUID,普通用户运行此可执行文件时会暂时拥有 root 的权限,有一定的风险存在,因此要谨慎设置,为系统安全考虑,要定期查找系统上拥有 SUID 权限的可执行文件并核对其是否存在风险。

Set GID

可执行文件 来说,SGID 拥有和 SUID 同样的作用,只不过 **命令执行者在执行该程序时获得该程序文件 属组(Group) 的身份。

SGID 设定方法:

chmod 2777 可执行文件名

chmod g+s 可执行文件名

Sticky Bit

粘滞位 (Sticky Bit) 只能用于目录,并对其中的文件有特殊的权限控制。他的主要作用是确保只有文件的所有者才能够删除或者修改文件。要给某个目录配置 粘滞位 (Sticky Bit) ,使用以下命令

chmod +t directoryname

这将为目录 directoryname 配置粘滞位 (Sticky Bit),以下命令可以验证 粘滞位 (Sticky Bit)是否存在。如果目录的权限列表中有 t 标志,表示目录设置了 粘滞位 (Sticky Bit)

$ ls -l directoryname
drwxrwxrwt 2 owner group 4096 Jun 26 10:15 directoryname

设置粘滞位后,只有文件的所有者才能删除或修改该文件。其他用户即使有写权限(w),也无法删除其他用户的文件。

阅读全文 »

systemd-journald 服务简介

systemd-journald 服务是 systemd init 系统提供的收集系统日志的服务。它会根据从内核、用户进程、标准输入和系统服务错误收到的日志记录信息,维护结构化的索引日记,并以此方式来收集和储存日志记录数据。systemd-journald 服务默认处于启用状态。

默认情况下,systemd-journald/run/log/journal/ 中储存日志数据。由于 /run/ 目录具有易失本性,因此,在重引导时会丢失日志数据。要永久保存日志数据,/var/log/journal/ 目录必须存在且具有正确的所有权和权限,如此,systemd-journald 服务便可在其中储存其数据。

要在终端中查看日志信息,可以使用命令 journalctl

systemd-journald 服务常用配置

持久化日志存储

默认情况下,日志位于 /run/log/journal/,重启后日志会丢失,为了持久化日志,可按照以下 2 种方法之一配置

  • 方法 1

    1. root 身份打开 /etc/systemd/journald.conf 进行编辑
      vi /etc/systemd/journald.conf
    2. 将包含 Storage= 的行取消注释,并将它更改为 Storage=persistent
      /etc/systemd/journald.conf
      [Journal]
      Storage=persistent
      #Compress=yes
      SystemMaxUse=50M
      [...]
    3. 重启 systemd-journald
      systemctl restart systemd-journald
      之后日志会持久化存储于 /var/log/journal。这些数据最多会占用 /var/log/journal 所在文件系统空间的 10%,要更改此限制,可以修改选项 SystemMaxUse=50M
阅读全文 »

Program 是一个静态实体,只是存储在操作系统中的文件(集合)

Process 是操作系统上的活动(Active)实体,是 Program 由操作系统加载到内存并运行之后的实体。

Process 运行过程中需要操作系统为其分配各种资源,如 CPU、Memory、Files、IO 等来完成其运行。

如果一个 Program 被操作系统运行(启动)了多次,那么其产生的多个 Process 属于分割(单独)的实体。

Linux 系统中调度的进程/线程,通常被称为任务(Task)

Linux 中常见的进程状态如下表:

状态标识 状态名称 状态说明 示例
R task_running 进程处于运行或就绪状态
S task_interruptible
sleeping
可中断的睡眠状态
D task_uninterruptible 不可中断的睡眠状态
1. 它是一种睡眠状态,意味着处于此状态的进程不会消耗 CPU
2. 睡眠的原因是等待某些资源(比如锁或者磁盘 IO),这也是非常多 D 状态的进程都处在处理 IO 操作的原因
3. 是它不能被中断,这个要区别于 硬件中断 的中断,是指不希望在其获取到资源或者超时前被终止。因此他不会被信号唤醒,也就不会响应 kill -9 这类信号。这也是它跟 S(可中断睡眠)状态的区别
T task_stopped
task_traced
Traced
暂停状态或跟踪状态
Z task_dead
exit_zombie
zombie
退出状态,进程成为僵尸进程
X task_dead
exit_dead
退出状态,进程即将被销毁
I idle 空闲状态
+ 表示关联了前台操作(Foreground Operation),比如前台运行的进程

进程调度

Linux 中任务(Task)调度算法默认使用 CFS(Completely Fair Scheduler,内核版本 >= 2.6.23).

CFS 调度算法没有使用固定的进程(此处的进程可能是进程或者线程,Linux 中统称为 Task)优先级(Priority),而是根据进程的 nice value 为进程分配一定比例的(Proportional) CPU 计算时间。 [1]

nice 的取值从 -20 - +19,值越小,优先级越高,默认值为 0 。优先级高的进程会被分配到更高比例的 CPU 处理时间。

在 Linux 内核中,优先级分为两种:静态优先级和动态优先级。CFS 使用的是动态优先级,它是根据 nice 值计算出来的。

CFS Scheduler 不会直接设定 Priorities,而是为每个 Task 维护变量 vruntime(virtual runtime)(可以检查系统 /proc/<PID>/sched),这个值记录了每个 task 使用了多少 CPU 时间。

CFS 通过将进程的虚拟运行时间(vruntime)与其他进程的虚拟运行时间进行比较来决定调度优先级。权重越大,vruntime 增长越慢,意味着进程的优先级越高,能够更频繁地被调度。

假入一个任务有默认的 Priority(nice=0),那么他的 vruntime 和实际使用的 CPU 时间相同。例如一个 nice=0 的进程使用了 CPU 200ms,那么他的 vruntime=200ms低优先级(low priority,nice>0 的任务在 CPU 上运行了 200ms,那么他的 vruntime>200ms,相反的,一个 高优先级(high priority,nice<0 的任务在 CPU 上运行了 200ms,那么他的 vruntime<200ms基于此,CFS Scheduler 在选择下一个要执行的任务时,会选择 vruntime 最小的任务来运行。如果有高优先级的任务就绪(可执行),它会抢占(preemptive)正在执行的低优先级的任务。

假如 Linux 中有 2 个优先级一样的任务(nice=0),一个进程为 I/O-bound,另一个为 CPU-bound。通常情况下,在一个 CPU 周期内,I/O-bound 的任务会使用很少的 CPU 时间就会因等待 IO 而中断在 CPU 上的执行并进入 CPU 的等待调度队列(schedule queue),而 CPU-bound 的任务会用尽分配给它的整个 CPU 周期。执行一段时间之后, I/O-bound 的任务的 vruntime 的值会显著的小于 CPU-bound 的任务的 vruntime,导致 I/O-bound 的任务拥有比 CPU-bound 的任务更高的优先级,当 I/O-bound 的任务就绪(IO 返回数据)时,它会立即抢占 CPU 开始执行。

nice 只能针对单一的进程调整优先级,无法同时将优先级配置关联到相关进程,如 子进程或者同一个服务中的其他进程

修改 nice 的值

在 Linux 中,nice 值用于调整进程的优先级,数值范围从 -20最高优先级 )到 19最低优先级 )。较低的 nice 值表示进程有更高的优先级,会更频繁地获得 CPU 时间,而较高的 nice 值表示进程有较低的优先级。

你可以使用 nicerenice 命令来修改进程的 nice

普通用户(root 之外的用户)启动应用程序时默认只能配置初始 nice0-19

普通用户(root 之外的用户)修改正在运行的应用程序的 nice 值,只能改大,不能改小。比如进程启动时,其 nice10,拥有权限的普通用户只能将其 nice 值改为大于 10 的值。

nice 命令

nice 命令用于在启动进程时指定 nice 。如果不指定,默认 nice 值为 0

nice -n 10 command

renice 命令

renice 命令可以修改已经在运行的进程的 nice 值。需要提供进程 ID( PID )来指定要修改的进程。

renice <nice_value> -p <PID>

如果想要一次修改多个进程的 nice 值,可以传递多个 PID:

sudo renice 10 -p 1234 2345 3456

Linux 进程资源控制 cgroups

cgroups 可以将一个任务(task)标识(绑定)到一个特殊的 控制组(Control Group ,此任务启动的子进程可以继承父进程的 控制组(Control Group

控制组(Control Group 可以限制的资源类型如下:

Type Description
blkio Storage
限制到存储设备(如 Hard Disk、USB Drivers等)的请求
cpu CPU
限制 CPU 调度
cpuacct Process Accounting
上报 CPU 使用状态,可以用于统计客户端使用的处理量并进行收费
cpuset CPU Assignment
在多处理器的系统上,将 Task 分配到特定的处理器以及关联的内存
devices Device Access
限制 控制组(Control Group 中的 Task 对目标设备类型的使用
freezer Suspend/Resume
暂停/恢复 控制组(Control Group 中的 Task
memory Memory Usage
限制并报告 控制组(Control Group 中的 Task 使用的内存
net_cls Network Bandwidth
制并报告 控制组(Control Group 中的 Task 使用的网络流量,主要通过对网络流量打上 cgroups 相关标签实现
net_prio Network Traffic
控制 控制组(Control Group 中的网络流量的优先级
ns Namespaces
cgroups 分配到不同的 Namespaces,如此同一个 cgroups 中的进程只能看到本 Namespace 中的进程

Linux 进程管理

top 命令

使用 top 命令可以查看系统负载、CPU 和 内存使用情况。也可以查看单个进程的具体信息。

top 命令常用选项

选项 说明 示例
-H Threads Mode,线程模式。默认情况 top 展示进程的简要信息,使用此选项显示进程中的线程状态。
对应交互式命令 H
  • 显示单个进程的(线程)详细信息
    # top -H -p 1423
    top - 09:44:42 up 54 days, 23:53, 2 users, load average: 8.82, 6.84, 7.21
    Threads: 15 total, 0 running, 15 sleeping, 0 stopped, 0 zombie
    %Cpu(s): 40.9 us, 10.8 sy, 0.0 ni, 48.1 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
    KiB Mem : 15790488 total, 466056 free, 7761544 used, 7562888 buff/cache
    KiB Swap: 0 total, 0 free, 0 used. 3895716 avail Mem

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
    1423 root 20 0 1477368 778788 4260 S 39.5 4.9 11999:41 [watchdog:1:6]
    2572 root 20 0 1477368 778788 4260 S 37.9 4.9 11363:48 [watchdog:1:6]
    1436 root 20 0 1477368 778788 4260 S 34.2 4.9 11286:08 [watchdog:1:6]
    1435 root 20 0 1477368 778788 4260 S 33.9 4.9 12059:53 [watchdog:1:6]
    1434 root 20 0 1477368 778788 4260 S 33.2 4.9 10249:00 [watchdog:1:6]
    1437 root 20 0 1477368 778788 4260 S 30.6 4.9 11717:47 [watchdog:1:6]
    1431 root 20 0 1477368 778788 4260 S 28.9 4.9 11222:06 [watchdog:1:6]
    21378 root 20 0 1477368 778788 4260 S 27.6 4.9 12143:35 [watchdog:1:6]
    1433 root 20 0 1477368 778788 4260 S 17.6 4.9 8738:21 [watchdog:1:6]
    1428 root 20 0 1477368 778788 4260 S 8.0 4.9 7650:56 [watchdog:1:6]
    1429 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.04 [watchdog:1:6]
    1430 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.05 [watchdog:1:6]
    1432 root 20 0 1477368 778788 4260 S 0.0 4.9 0:00.03 [watchdog:1:6]
    1438 root 20 0 1477368 778788 4260 S 0.0 4.9 12260:30 [watchdog:1:6]
    1529 root 20 0 1477368 778788 4260 S 0.0 4.9 11068:39 [watchdog:1:6]

进程命令名和进程可执行文件名

在系统中遇到以下进程:

# ps -elf | grep 18686
5 S root 18686 1239 0 80 0 - 46620 pipe_w 15:50 ? 00:00:00 /usr/sbin/CROND -n
0 R root 18694 18686 7 80 0 - 610547 - 15:50 ? 00:00:02 /usr/local/php73/bin/php /home/www/admin/artisan PullData
0 S root 18754 18686 0 80 0 - 22453 pipe_w 15:50 ? 00:00:00 /usr/sbin/sendmail -FCronDaemon -i -odi -oem -oi -t -f root

其中 PID 为 18686 的进程名为 /usr/sbin/CROND,其启动了另外两个子进程。但是在系统中检查,并不存在路径 /usr/sbin/CROND

# ls -l /usr/sbin/CROND
ls: cannot access /usr/sbin/CROND: No such file or directory

出现此种现象,主要是因为 在启动时,进程的命令名是根据路径传递给 execve() 函数的参数决定的,而不是直接与系统中的文件进行匹配

在 Linux 系统中,ps 命令显示的进程信息是从 /proc 文件系统中获取的,而 /proc 文件系统包含有关正在运行的进程的信息,包括每个进程的命令名。因此,即使实际上系统中不存在 /usr/sbin/CROND 文件,但如果进程的命令名是 /usr/sbin/CROND,那么 ps 命令仍然会显示进程的命令名为 /usr/sbin/CROND

进程的命令名可以查看 /proc/<PID>/cmdline 文件,本示例中显示如下:

# cat /proc/18686/cmdline 
/usr/sbin/CROND-n

对应的系统上的可执行文件的名称可以查看 /proc/<PID>/stat/proc/<PID>/comm/proc/<PID>/status 等文件

# cat /proc/900/comm 
crond

# cat /proc/900/status
Name: crond
Umask: 0022
State: S (sleeping)
Tgid: 900
Ngid: 0
Pid: 900
PPid: 1239
TracerPid: 0

# cat /proc/900/stat
900 (crond) S 1239 1239 1239 0 -1 4202816 1627 0 0 0 0 0 0 0 20 0 1 0 139129633 190955520 1478 18446744073709551615 94685936058368 94685936118156 140733000396032 140733000262488 140427856103840 0 0 4096 16387 18446744071797306256 0 0 17 3 0 0 0 0 0 94685938219080 94685938221648 94685948321792 140733000400770 140733000400789 140733000400789 140733000400872 0

在本示例中,实际执行的命令为 crond

参考链接|Bibliography

Operating System Concepts v10 Online
Linux进程状态说明

脚注


  1. 1.Operating System Concepts v10 Online 5.7.1 Example: Linux Scheduling

在 Linux 中,命令提供的 man 手册是一份非常详细的命令使用说明手册,要了解命令的使用方法及其工作原理,熟练参考 man 手册是及其必要的。

man 手册中不仅包含了命令的使用方法,还包括了命令相关的 (配置)文件说明System Calls 等相关信息,下表中列出了 man 手册不同编号对应的功能

Section Number Section Name Description
1 User Commands 用户可以在 shell 中运行的指令说明
man 命令不指定 Section Number 时默认为 1
2 System Calls 应用程序中的功能函数调用的内核函数
3 C Library Functions 应用程序针对特定的函数库提供的接口
4 Devices and Special Files 程序使用的硬件或软件
5 File Formats and Conventions 涉及的文件类型(如配置文件)及约定
6 Games
7 Miscellaneous 其他杂项,如 协议文件系统字符集
8 System Administration Tools and Daemons 需要 root 权限或其他管理员权限运行的命令

要查看命令 man 的某个部分,可以使用以下命令查看 passwd 命令的 File Formats and Conventions

man 5 passwd

环境信息

  • Centos 7

为源码编译安装的软件安装 man 手册

使用源码编译安装的软件默认是没有 man 手册的,使用 man 命令会报以下错误

$ man fswatch
No manual entry for fswatch

要为源码编译安装的软件安装 man 手册,可以参考以下步骤,此处示例软件为 fswatch,软件编译安装到了 /usr/local/fswatch-1.17.1/

  1. 一般情况下,源码中会附带软件的使用文档,编译安装后,可能位于以下路径,fswatch 编译安装后的 man 手册位于 /usr/local/fswatch-1.17.1/share/man/man7/fswatch.7

    ls /usr/local/fswatch-1.17.1/doc
    ls /usr/local/fswatch-1.17.1/share/doc
    ls /usr/local/fswatch-1.17.1/share/man/

  2. man 命令使用的文档默认来源于 /usr/share/man/

    $ ls /usr/share/man/
    cs de fr hu it ko man1 man1x man2x man3p man4 man5 man6 man7 man8 man9 mann pl pt_BR ro sk tr zh_CN
    da es hr id ja man0p man1p man2 man3 man3x man4x man5x man6x man7x man8x man9x nl pt pt_PT ru sv zh zh_TW

    要为编译安装软件的安装 man 帮助文档,首先将 fswatch 的帮助文档复制到 man 页面的目录

    cp /usr/local/fswatch-1.17.1/share/man/man7/fswatch.7 /usr/share/man/man7/

  3. 更新 man 索引

    $ mandb
    1 man subdirectory contained newer manual pages.
    47 manual pages were added.

    安装成功后,可以正常使用 man fswatch 查看帮助文档。

bash 快捷键

bash 常用的快捷键总结

删除类快捷键

快捷键 功能 示例
Ctrl + D 删除光标右侧的一个字符,等于 Delete
Ctrl + H 删除光标左侧的一个字符,等于 Backspace
Ctrl + K 删除从光标位置到行尾的所有字符。
Ctrl + U 删除从光标位置到行首的所有字符。
Ctrl + W 删除光标左侧的一个单词(以空格为分隔)。
Alt + D 删除光标右侧的一个单词。(空格,下划线,点分割)
Ctrl + C 删除整行

定位类快捷键

快捷键 功能 示例
Ctrl + F 向前挪动一个字符 ,等于 右箭头 ->
Ctrl + B 向后挪动一个字符 ,等于 左箭头 <-
Alt + F 向前挪动一个 word
Alt + B 向后挪动一个 word 。
Ctrl + A 跳到行首。
Ctrl + E 跳到行尾。

Recall 类快捷键

bash 中执行过的命令都保存在了历史记录中,可以通过 history 命令查看。为了快速重新执行或者修改之前的命令并执行,bash 提供了以下快捷键

快捷键 功能 示例
Ctrl + R 搜索 history最后一个 匹配的命令
Alt + P 搜索 history最常使用 的命令
!100 重新执行 history 中的第 100 号的命令,无确认,会立即执行
!! 重新执行 history 中的 最后一个 命令,无确认,会立即执行

bash 环境变量

shell 中的环境变量大体可以分为以下几种:

  • Local Variables : 当前 Shell 中的 所有的本地变量(Local Variables ,要查看所有的 本地变量(Local Variables),可以使用以下命令:

    • set
    • declare
      $ set | more
      BASH=/bin/bash
      BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:globasciiranges:histappend:interactive_comments:progcomp:promptvars:sour
      cepath
      BASH_ALIASES=()
      BASH_ARGC=([0]="0")
      BASH_ARGV=()
      ...
  • Environment Variables : 本地变量(Local Variables)的一部分子集(subset)被稱為 环境变量(Environment Variables环境变量(Environment Variables 会被导入到任何从当前 Shell 启动的新的 Shell,要查看 环境变量(Environment Variables ,使用以下命令

    • env
    • printenv
      $ env
      SHELL=/bin/bash
      SESSION_MANAGER=local/U-3TSDMAL9IVFAQ:@/tmp/.ICE-unix/3396,unix/U-3TSDMAL9IVFAQ:/tmp/.ICE-unix/3396
      QT_ACCESSIBILITY=1
      COLORTERM=truecolor
      XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg
      SSH_AGENT_LAUNCHER=gnome-keyring
      XDG_MENU_PREFIX=gnome-
      GNOME_DESKTOP_SESSION_ID=this-is-deprecated
      GTK_IM_MODULE=fcitx
      LANGUAGE=en
      LC_ADDRESS=en_US.UTF-8
      GNOME_SHELL_SESSION_MODE=ubuntu
      LC_NAME=en_US.UTF-8
      SSH_AUTH_SOCK=/run/user/408001114/keyring/ssh
      XMODIFIERS=@im=fcitx
      DESKTOP_SESSION=ubuntu
      LC_MONETARY=en_US.UTF-8
      GTK_MODULES=gail:atk-bridge
      DBUS_STARTER_BUS_TYPE=session
      ...
      查看单个变量
      $ echo $PATH 
      /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin

bash 常用环境变量

环境变量 功能 示例
PATH 可执行文件查找路径变量。
查找顺序从左向右,找到即停止
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
PS1
PS[234]
PS1 环境变量定义了 bash 中的命令后提示符包含的内容
定义中支持的元字符可以查看 man bash 手册
PS1="[\u@\h \W]\\$

bash 命令查找优先级

bash 中命令执行优先顺序如下:

  • Aliases : 由 alias 命令配置的命令别名。
  • Shell 预留的关键字 : 主要是 Shell 编程中会用到的关键字,如 dowhilecaseelse 等。
  • Built-in Command : shell 内嵌的命令,如 cdecho
  • Filesystem Command : 环境变量 PATH 中的命令。

要查找命令所在位置,可以使用 typewhich 命令

$ type bash
bash is /usr/bin/bash

$ which bash
/usr/bin/bash

$ type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls
ls is /bin/ls

如果要查找命令所在的所有位置,可以使用 type -a ls,如上所示,这会显示 ls 命令所在的所有位置

bash 环境变量配置优先级

Linux 系统中的多个配置文件中可以配置环境变量,其中有些会针对所有的用户和 shell 生效,有些只会针对特定的用户生效。

以下表格中列出了常用的环境变量的配置文件:

File Description
/etc/profile 此配置中的环境变量对所有用户生效,在用户登陆时为其配置环境变量 ,它一般会加载(包含)/etc/profile.d 中的配置
/etc/bashrc 此配置中的环境变量针对所有的 shell 生效,每次打开一个 bash 时会执行 ,一般会设置包括 登陆提示alias
~/.bash_profile 此配置中的环境变量对 当前登陆 用户生效,仅在用户登陆时为其配置环境变量 ,一般会加载 ~/.bashrc 文件
~/.bashrc 此配置中的环境变量针对 当前登陆 的用户 bash 生效,并在用户打开每个新的 bash 时执行
~/.bash_logout 此配置中的环境变量对 当前登陆 用户生效,仅在 当前登陆用户登出(logout) 时执行

Operating System Concepts v10(操作系统导论第10版)中涉及的相关专业词汇。

memory

Main Memory

Main Memory 通常是 CPU 可以直接定位和访问的唯一的大存储设备。如果 CPU 要处理磁盘上的数据,数据必须首先被传输到 Main Memory,指令要能被 CPU 执行,也必须首先载入内存中。

Program 要能被运行,首先必须载入到内存中,并提供内存绝对地址给 CPU 以供加载指令和数据。

Logical Memory Address and Virtual Memory Address

通常情况下,CPU 生成的内存地址被称为 Logical Memory Address,也称为 Virtual Memory Address

Memory-address 注册器(memory-address register)加载的地址通常称为 Physical Memory Address

程序运行过程中,CPU 操作的是 Virtual Memory Address,需要由硬件设备 MMU(Memory Management Unit)负责将 Virtual Memory Address space 映射到对应的 Physical Memory Address space。程序或者是 CPU 运行过程中,不会直接操作(访问/access)物理内存地址空间。

DMA

Direct Memory Access (DMA) 在 CPU 需要从存储读写大量数据到内存时,如果数据通过 CPU 中转,成本太高,为了解决这个问题,DMA 被采用,在传输大块数据时,首先在 CPU 中为数据设置好必要的 buffer、指针、计数器等资源,设备控制器(DMA Controller)直接(在磁盘和内存中)传输数据块而无须 CPU 参与实际的数据传输,只需要在数据块传输完成时,向 CPU 产生中断以指示设备控制器(DMA Controller)数据传输已完成。在 DMA 过程中,CPU 依旧可以做其他工作。 [1]

Dynamic Linking and Shared Libraries

DLLs(Dynamic Linked Libraries) 是程序运行期间需要链接的系统库文件(system libraries)。[6]

部分操作系统不支持 DLLs 机制,只能使用 静态链接static linking),在这种情况下,应用程序运行过程中需要使用的系统库文件必须和应用程序一起编译进应用程序镜像(program image)中。假如多个应用程序使用了同样的库文件,那么这些库文件会同时存在于这些应用程序的程序镜像文件中,这些应用程序运行过程中也会在内存中加载多份同样的库文件。这可能会产生以下缺点:

  • 应用程序镜像较大,占用更多磁盘空间
  • 应用程序运行时,因为要加载多个同样的库文件,会占用更多的内存
  • 库文件升级不灵活,要升级某个库文件,要重新编译所有使用此库文件的应用程序。

DLLs(Dynamic Linked Libraries) 是在运行过程中,动态加载库文件。这个特性在系统库文件(如 standard C language library)中很常用。程序编译过程中及运行过程中动态加载系统库文件,无需将系统库文件打包进应用程序镜像中,应用程序运行过程中动态加载系统库文件,如果要加载的目标系统库文件已经存在于内存中,则无需重复加载,直接共享使用即可。DLLs 有以下优势:

  • 应用程序镜像无需包含常用的库文件,减少了磁盘使用量
  • 应用程序运行时,可以在多个进程中共享库文件,无需重复加载(只存在一个库实例即可),减少了内存使用率并提升了内存效率
  • 共享库文件升级后,所有加载此库文件的应用程序都可以直接使用更新后的新版本。应用程序和库文件中都包含了相应的版本信息,会防止应用程序使用错误的库版本
  • 内存中可以加载多个版本的共享库文件,应用程序会使用自己的库文件版本信息加载正确的库文件

Memory Allocation

Fragmentation

假设在一个全新的未运行任何应用程序的操作系统中,初始情况下内存中存在一整块连续的可用地址范围(one large block of available memory),或者叫一个 Hole

假设如下图所示情况,系统中运行了 processes 5, 8, and 2 并且占用了所有的内存地址范围。之后 process 8 退出,其所使用的内存释放,形成了一个 Hole,随后 process 9 开始运行并申请了一段内存,随后 process 5 退出并释放内存,导致内存中出现了 2 个地址非连续(noncontigous)的 Hole随着系统中进程的运行和退出,内存中可能会存在很多大小不一,地址范围不连续的 Hole,这些 Hole 既是 外部内存碎片(External Memory Fragmentation

外部内存碎片(External Memory Fragmentation 存在时,可能出现系统有足够多的空闲内存(非连续的地址空间,内存碎片)但是这些内存都是内存碎片。

在现代的内存管理中,内存的分配一般是以 block 为单位进行分配,block 是一个固定大小的内存。在这种情况下,假如 block 大小为 512 bytes,应用程序申请了 600 bytes 内存,那么需要分配 2 个 block 给应用程序,实际分配了 1024 bytes 。申请的内存(600 bytes)和实际分配的内存(2 blocks = 1024 bytes)之间的差值被称为 内部内存碎片(Internal Memory Fragmentation)

Paging

在当前的操作系统中,解决 外部内存碎片(External Memory Fragmentation 的问题,通用解决方法是采用 内存页(Memory Paging) 技术: 应用程序申请的 Logical 内存/Physical 内存地址非连续(横跨多个 Hole)

Paging 解决了 外部内存碎片(External Memory Fragmentation 的问题,没有解决 内部内存碎片(Internal Memory Fragmentation)

Virtual Memory

Virtual Memory 提供了 允许程序运行过程中,无需将整个程序内容全部加载到内存中的技术 [7]

主要有以下优势:

  • 程序大小可以大于物理内存空间。开发者不必再关注物理内存是否足够。
  • Virtual Memory 将 main memory 抽象成一个统一的大存储阵列,基于此,程序开发者可以不用关注物理内存的差异和限制。
  • 允许进程共享文件和库,并实现了共享内存(shared memory)。

Page Fault

Virtual Memory 提供了 允许程序运行过程中,无需将整个程序内容全部加载到内存中的技术,实现此技术主要使用了 Demand Paging 技术,使用 demand-paged virtual memory,可以实现程序运行过程中,仅仅在 运行过程中必须的 pages 才会被加载到内存中,那些没有用到的 pages 永远不会加载到物理内存中Demand Pageing 也是 Virtual Memory 的一个主要优势。

Demand Paging 技术的实现依赖于硬件的支持和 Page Fault 技术。

根据 Demand Paging 方案的原则,程序运行过程中用不到的 Pages 不应该被加载到内存中。因此,当一个程序刚刚启动时,它之后运行过程中所需的 Pages 理论上都不在内存中,而是存在于次级存储(secondary storage,如磁盘或者 swap)中,如果 程序运行过程中需要内存中不存在的 Pages,这时就要有机制确保实现将程序运行所需的 Pages 加载到内存中来,并且只是加载程序运行所需的 Pages,而不会加载用不到的 Pages,实现此机制的技术叫 Page Fault

Page Fault 需要硬件支持,主要是内存组件中的硬件设备(Paging Hardware,负责 page table 内存地址转换),当程序运行过程中需要不存在于内存中的 Pages 时,会向 OS 产生一个 Page Fault 的 trap,此 trap 是一个 OS Failure(指示所需 Pages 不在内存中),硬件会注意到此 OS Failure 并进行相应处理。

操作系统处理 Page Fault 的简要工作流程如下:

  1. 检查并确保此内存请求合法后,如果所需的 pages 不在内存中,开始将其加载入内存(page in)
  2. 在物理内存中找到空闲的 frame(free frame)
  3. 向次级存储(secondary storage,如磁盘或者 swap)发送读取所需 Pages 到新分配的 frame 的请求
  4. 当存储(Pages)读取到内存完毕后,修改程序所属的 internal table 和 page table 以指示所需的 Pages 已经在内存中
  5. 重新启动因为缺少所需 Pages 而被中断(interrupted)的指令(instruction)

Major Page Fault

Major Page Fault 发生于所需要的 Page 不在内存中,这是系统需要在物理内存中找到可用的 Frames,然后将数据从 次级存储(secondary storage,如磁盘或者 swap) 读取到内存中并更新对应的 internal tablepage table 以指示所需的 Pages 已经在内存中

Minor Page Fault

Minor Page Fault 发生在以下 2 中情况:

  1. 应用程序需要引用共享库,此共享库已经在内存中,但是应用程序的 page table 中没有到此共享库所在内存页的 mapping。此种情况下,只需要更新应用程序的 page table,向其中添加到共享内存库所在内存页的引用。
  2. Virtual Memory 中的 Page 被应用程序释放(reclaimed),对应物理内存 Frame 被标记为 free-frame,但是上面的数据未被 zeroed out,此时 Page 被分配给其他应用程序。

Linux 系统中,使用 ps 命令的 -eo min_flt,maj_flt,cmd 参数可以查看进程相关的 major 和 minor page fault。

Page Relpacement

现代的操作系统内存,一般都允许 超分配(over-allocating),即允许操作系统分配比实际的物理内存更多的内存给应用程序,当一个应用程序运行过程中,因为 Page Fault 要 Page In 时,可能会出现物理内存不足(no free frames on the free-frame list)的情况,此时操作系统会尽最大可能的满足应用程序对内存的申请。以前的操作系统大都采用 Swap 来实现,即将当前未在 CPU 上运行的应用程序使用的内存 swap out 到 Swap 中,并将空余出来的内存分配给要运行的程序使用。Swap 技术已被当前大多数操作系统摈弃,因为其在内存和 Swap 中拷贝数据成本太高,取而代之的技术是 Page Repalcement

使用 Page Relpacement 技术,在物理内存不足时,使用 page-replacement 算法找到物理内存中的 Frames(victim frames),将其上的内容写入(如果其上内容未改变,不用执行写入操作,如果内容改变,执行写操作)到次级存储(secondary storage),如果之后的运行过程中,应用程序需要这些数据,它会产生 Page Fault,这些数据会被重新加载回内存中。

Memory Compression

Memory Compression 是在物理内存不够时,使用的一种可替代 Page Repacement 的技术。在系统内存不足时,系统不执行 Page Replacement,而是先对选择出的 victim frames 执行内存压缩,将多个 frames 压缩成一个 frame 进而降低内存使用率,而无需进行 Page Swapping out 操作。

移动设备操作系统,包括 Android 和 IOS 都不支持 SwapPage Repalcement,都采用了 Memory Compression 技术作为 Memory Management strategy 的一部分

在性能方面,Memory Compression 拥有比 Page Repalcement 更快的速度。

Kernel Memory

内核(kernel)使用的内存和用户模式(user mode space)中的应用程序使用的内存分配机制不同。主要基于以下原因: [8]

  • Kernel 中的数据结构大小差异很大,很多都比 Page Size 要小,内存使用不当会导致非常多的 internal fragmentation,导致内存严重浪费。而且很多操作系统并未将内核代码放置到 Paging Memory 中。
  • user-mode 中的应用程序分配的内存在物理内存地址上没必要是连续地址空间,然而内核中包含的很多硬件设备都需要直接通过物理内存进行交互,无法使用 Virtual Memory Interface,因此需要内存中连续的地址空间(contiguous pages)分配

CPU

SMP

Symmetric Multiprocessing (SMP),对称处理系统,在系统中存在多个处理器,每个处理器中包含一个或多个 CPU,每个 CPU 有自己的 L1 Cache (CPU 独享)和 Register,每个处理器有 L2 Cache(处理器中的多个 CPU 共享 L2 cache),同一个处理器中的 CPU 使用处理器内部通信系统通信,跨处理器的 CPU 之间通过系统总线(Bus)通信。 [2]

NUMA

系统中的处理器不宜太多,多处理器可以提高系统的任务处理能力,但是当 CPU 过高时,对系统总线的争抢会成为系统瓶颈。

为了避免太多 Processors 争抢系统总线造成的性能下降,一个可选的 方法是为每个 CPU(或 CPU 集)提供专用的本地内存,CPU 通过一个更小更快的本地 bus 连接专用的本地内存。所有的 CPU 通过一个 内部通信系统 进行连接,所有 CPU 共享同一个物理地址空间,这种架构被称为 Non-uniform Memory Access (NUMA)

Program and Process

Program 是一个静态实体,只是存储在操作系统中的文件(集合)

Process 是操作系统上的活动(Active)实体,是 Program 由操作系统加载运行之后的实体。

Process 运行过程中需要操作系统为其分配各种资源,如 CPU、Memory、Files、IO 等来完成其运行。

如果一个 Program 被操作系统运行(启动)了多次,那么其产生的多个 Process 属于分割(单独)的实体。

Process Control Block

PCB (Process Control Block) 代表了 OS 中进程(Process)的各种信息,包括

  • Process State : 进程当前的状态
  • Program counter : 程序计数器指针。指向了当前进程中下一个要执行的指令的地址。
  • CPU registers : 根据计算机架构的不同,可能包括计数器、栈指针(stack pointers)、通用指针(general-purpose registers)等。
  • CPU-scheduling information : 包括进程优先级(process priority)信息、调度队列指针(pointers to scheduling queues)以及其他调度参数等。
  • Memory-management information : 进程使用的内存信息
  • Accounting information : CPU 数量和 CPU 使用时间,CPU 使用限制,进程数量等信息
  • I/O status information : 分配给进程的 IO 设备,打开的文件列表等。

Scheduling Queues

  • ready queue : 进程开始后,会被放入 ready queue,等待 CPU 被分配给它。ready queue 是一个 链接队列,其首部包含一个指向队列中第一个 PCB 的指针,每个 PCB 都包含一个指针,指向 ready queue 中的下一个 PCB。
  • wait queue : 当 ready queue 中的进程被分配了 CPU 后,其执行一段时间后会中止或者是等待特殊事件,如 IO,在起等待的过程中会被放入 wait queue

操作系统负载(system load) 衡量的就是在 Scheduling Queues 中的进程(线程)的数量。即有多少任务等待 CPU 空闲以运行。

Context Switch

CPU 会频繁的调度(因为 CPU Schedule 或 Interrupts)不同的进程来执行,当调度发生,OS 需要保存当前进程的上下文信息(Context)以备当前进程再次开始执行时恢复 Context,Context 信息保存在 PCB

切换 CPU core 要保存当前进程的 Context (到 PCB)并恢复另一个进程的 Context(从 PCB),这个过程被称为 Context Switch

在现代化的操作系统上,OS 调度的更多的是 kernel-level threads,而不是 processes (进程)

Processor Affinity

Processes 在指定的 CPU 上运行的过程中,一般会加载数据到 CPU 的 cache 中,下一次调度到同一个 CPU 运行时,仍然可以使用 Cache 中的数据(称为 warm cache)。 [5]

假如后续 CPU 调度时,此进程被调度到了另一个 CPU,那么原来 CPU Cache 中的数据就要失效,新的 CPU 必须从新加载数据到 Cache 中。因为让 CPU Cache 中的数据失效和加载 Memroy 中的数据到 Cache 中是一个成本较高的操作,现代的 SMP 操作系统都会避免这类缓存迁移操作,会尽量将进程调度到同一个 CPU 以使用 warm cache 数据,这就是 Processor Affinity,一个进程对其正在运行的 CPU 拥有亲和性。

常见的 CPU 亲和性(Processor Affinity)有两类:

  • soft affinity : 尽量保证一个进程被调度到同一个 CPU,但是不保证一定,尽最大可能
  • hard affinity : 允许配置进程只运行在选定的 CPU 集(subset of processors)

大多数系统同时实现了以上两种类型。

Disk

可以将 NVS (Nonvolatile Storage (NVS))根据硬盘组成划分成 2 大类

  • 机械硬盘(Mechanical): HDDs,Optical Disks,Holographic storage,Magnetic Tape。
  • Electrical(NVM): Flash Memory,FRAM,NRAM,SSD

HDD


HDD (Hard Disk Driver)的主要组成如上图。主要包括以下主要组件: [9]

  • Platter
    Platter 的两面由磁性材料(magnetic material)覆盖组成。

  • Read-Write Head
    Platter 的两面分别有个 Read-Write Head (读写磁头) 负责在磁碟(Platter)上写入/读取数据。磁头和 Platters 之间一般由一层非常薄的气体作为保护层,如氦气(helium),磁头和 Platter 表面接触会造成 Platter 表面的磁性材料损坏,这被称为 Head Crash,一般无法修复,磁盘上面数据会丢失。

  • Disk Arm
    Disk Arm 连接了 Read-Write Head (读写磁头) 和 Arm AssemblyRead-Write Head (读写磁头) 通过 Disk Arm 的移动来寻址到不同的存储单元。

  • Tracks
    Platter 的面被(逻辑/Logically)分割成圆弧形(两个不同半径的圆分割组成的部分)

  • Sectors
    Tracks 被逻辑(Logically) 分割成 Sectors (扇形),Sectors 是 HDD 磁盘上最小的传输单元,一般有固定大小的存储空间(2010 年前一般是 512 bytes,之后大多升级到了 4KB)。每个 Track 上面包含多个 Sectors。

  • Cylinder
    每个 Platter 上面,固定位置的 Disk Arm / Read-Write Head 垂直组成的存储单元组成一个 Cylinder 。每个磁盘上面会包含很多个同心的(Concentric) Cylinder

HDD 磁盘中包含一个高速旋转的 马达(disk driver motor),HDD 磁盘的传输速度(Transfer Rate)和马达的旋转速度相关,通常使用 RPM(Rotations Per Minute) 来衡量 HDD 磁盘的转速,通常在 5400/7200/15000 RPM。有些 HDD 磁盘在电量不足或者使用频率低时会降低 RPM 来节能和提高磁盘使用寿命。

Transfer Rate 是衡量数据在 HDD 磁盘和操作系统之间传输速度的指标。这个性能指标主要受到 寻址时间(Positioning Time) 或者叫 Random-Access Time 的影响,这个时间主要由 2 部分组成,一般在 几毫秒(several milliseconds)

  1. Seek Time : Disk Arm 移动到目标 Cylinder 的时间
  2. Rotational Latency : 目标 Sector 移动到 Disk Read Wirte Head 的延迟。

NVM

Nonvolatile Memory Devices (NVM) 使用电特性(Electrical)存储,而不是机械(mechanical)特性,相比 HDD,其拥有更高的可靠性和性能(没有 Seek Time 和 Rotational Latency),更加的省电,劣势是他们价格相对 HDD 更贵并且存储空间相对较小,但是随着时间推移,这些劣势也会逐渐消弭。

NVM 存储的 写入性能 通常和其存储可用大小相关,因为 NVM 设备内部通常会保留部分空间用于 Garbage CollectionOver-Provisioning(通常为 20%),如果可用空间小,会导致 写性能 下降。

NVM 设备的寿命和其 Erase 的次数正相关

Error Detection and Correction

Error Detection 是计算机系统中最基础的功能之一,普遍用于 Memory、Network、Storage 系统中。Error Detection 的常见功能包括:

  • 检测存储中存储的数据是否发生了(错误/非自发/无意的)改变,比如某个数据位由 0 变为了 1
  • 网络数据在传输过程中发生了改变
  • 存储设备上的数据读写不一致。
    通过检测这些错误,可以防止在使用这些错误数据之前对其进行修正或者是发送通知给使用者。

Parity Bit

Memory 长使用 Parity Bit (奇偶校验位) 算法进行 Error Detection,Memory 系统中的每个 Byte 都有一个对应的 Parity Bit,此 Parity Bit 记录了对应的 byte 中 1 出现的次数是 偶数(even,Parity Bit = 0 还是 奇数(odd, Parity Bit = 1)

根据 Parity Bit 算法的计算结果,会出现以下情况:

  • Memory 中的一个 byte 中的一个 bit 位发生了改变,那么此 byte 计算出的 Parity Bit 值和保存的 Parity Bit 值不一样,说明数据不可靠
  • Memory 中的一个 byte 中的任何 bit 都正常,但是保存的 Parity Bit 值发生了变化,那么此 byte 计算出的 Parity Bit 值和保存的 Parity Bit 值不一样,说明数据不可靠
  • Memory 中的一个 byte 计算出的 Parity Bit 值和保存的 Parity Bit 值一致,说明数据可靠

Parity Bit 无法检测 2 个 bit 位的错误,因为 2 个 bit 位的数据错误,其正确计算出来 Parity Bit 的值不变。

Parity Bit 容易实现并且计算起来非常的快,但是因为 Parity Bit 的存在,会为每个 byte 增加一个 bit 的大小

CRCs

CRCs (Cyclic Redundancy Check) 是网络传输中常用的 Error Detection 算法。可以检测到多个 bit 位的错误。

ECC

ECC (Error Correction Code) 算法不仅可以检测到数据错误,并且可以尝试恢复数据。

EEPROM

EEPROM(Electrically Erasable Programmable Read-Only Memory) 是主板上的一个 NVM Flash Memory Firmware。

服务器上电运行后启动的第一个程序是 bootstrap loader program (操作系统启动引导程序,如 Linux 中的 grub2,其启动之后会加载操作系统)。RAM 是易失性存储,不能将 bootstrap program 放置到 RAM 中,当下主机会使用 EEPROM 放置 bootstrap programbootstrap program 可以被修改,但是不能频繁修改,它属于慢速存储,其中包含了不经常会使用的静态程序和数据。比如 iPhone 使用了 EEPROM 存储了设备 serial numbershardware information

RAID

RAID (Redundant Arrays of Independent Disks)

RAID 0: Striping Volume

RAID 0,Striping Volume,条带卷,在多个存储设备上面,以 Block 为基本单位组成条带(Strip),数据分散写入到每个存储设备的对应的条带上,读取时从多个设备上的对应条带中读取。

  • 不提供任何冗余(Redundancy),任意存储设备损坏,会导致整个存储系统上的数据损坏
  • 有极高的读写速度,在多个设备上并发的读写
  • 存储设备利用率 100%

RAID 1: Mirrored Volume

由 2 或多块物理存储设备(physical storage device)组成一个逻辑存储设备(logical disk),每次写入数据时,同时写入到 2 个或多个物理存储设备。

  • 提供冗余(Redundancy),数据同时写入 2 个或多个物理存储设备上,只有在所有数据盘都损坏的情况下数据才会损坏
  • 有极高的读取速度,可以从每个镜像盘读取数据
  • 数据写入速度降低,因为要将数据写入多个数据盘,可能会导致写入速度下降
  • 存储设备利用率 50%

RAID 4: Block-Interleaved Parity

RAID 4 使用 RAID 0 的 Strip(条带)作为基础,至少需要 3 块数据盘。数据存储以 Block 为单位。

假设由 3 块数据盘组成 RAID 4,数据写入过程如下:

  1. 写入数据的第一个 block 写入到第 1 块数据盘中,第二个 block 写入到第 2 块数据盘中,对写入第一块盘和第二块盘上的这 2 个 block 做 Error Correcting Code 计算,计算结果存储在第 3 块数据盘中。
  2. 第三个 block 继续写入到第 1 块数据盘中,第四个 block 写入到第 2 块数据盘中,对此 2 个 block 做 Error Correcting Code 计算,计算结果存储在第 3 块数据盘中
  3. 依次类推,直到数据写入完成。
  • 其中一块盘存储了 Error Correction Code
  • 假如其中一个数据盘或其上的一个 Block 损坏,那么这块数据可以根据其他盘上的数据和 Error Correction Code 做计算进行恢复
  • 有极高的读写速度,在多个设备上并发的读写。
  • 存储设备利用率 (N-1)/N

RAID 5: Block-Interleaved Distributed Parity

和 RAID 4 唯一的不同是: RAID 4 使用一个单独的盘存储了 Error Correction Code(Parity Bit),RAID 5 将 Error Correction Code(Parity Bit)分布存储在所有数据盘上,通过将 Parity 分布到所有的数据盘上,避免了专用的 Parity Block 的盘压力太大。

RAID 6: P + Q redundancy scheme

RAID 6 为每 4 个 Block 保留了 2 个冗余(Redundant)的 Block,使用了更复杂的算法来进行 Error Detect 和 Error Correcting,可以支持 2 块数据盘损坏。

RAID 10


RAID 10 的结构:

  • 首先将硬盘分成多个镜像组(RAID 1),每个镜像组包含两个或多个硬盘。
  • 然后将这些镜像组组合成一个条带组(RAID 0)。

优缺点:

  • 高数据冗余:每个数据块都有一个镜像副本,因此可以抵抗单个硬盘故障。

  • 高读写性能:通过条带化技术,可以提高读写速度。

  • 成本较高:需要至少四个硬盘,而且有效存储容量只有硬盘总数的一半。

RAID 01

RAID 01 的结构:

  • 首先将硬盘分成多个条带组(RAID 0),每个条带组包含两个或多个硬盘。
  • 然后将这些条带组组合成一个镜像组(RAID 1)。

优缺点:

  • 高读写性能:通过条带化技术,可以提高读写速度。

  • 数据冗余:整个条带组被镜像,因此可以抵抗硬盘故障。

  • 成本较高:需要至少四个硬盘,而且有效存储容量只有硬盘总数的一半。

  • 数据恢复复杂:如果一个硬盘发生故障,整个条带组都需要被重建,恢复时间较长。

RAID 10 和 RAID 01 在单一硬盘故障时的恢复方式基本一致,都是从对应的镜像组恢复数据到故障硬盘。 在涉及到多个硬盘的故障的情况下,RAID 10 相比 RAID 01 拥有更多的优势:

  • RAID 10 提供了更高的冗余性和恢复灵活性,因为它允许多个独立的镜像组。
  • RAID 10 可以承受每个镜像组中的一个硬盘故障而不影响整体系统。
  • RAID 01 在任一条带组中失效的硬盘超过一个时,会导致整个 RAID 组不可用。

File System

File Systems 为访问(storedlocatedretrieve)存储系统(Storage)上存储的文件提供了高效和便利的途径(方式)。文件系统的设计主要涉及到以下问题: [10]

  • File System 对用户(User)应该如何呈现。包括如何定义文件以及文件属性,允许哪些操作,目录结构是怎样的(如何组织)
  • 使用怎样的算法来创建文件或者目录结构,以及如何将逻辑上的文件(logical files system)和物理存储(硬件)上的内容进行对应

File System 通常由多个功能分层(Levels or layers)构成,其中 下层为上层提供服务,上层利用下层提供的服务来构建文件系统的功能(特性)

在如上图所示的分层的文件系统架构中,主要包括以下层:

  • I/O control : 主要由存储设备驱动器(Device Drivers)和中断控制器(interrupt handlers)组成。主要功能是在存储设备和主内存之间传输数据。它接受更高层的指令(如 retrieve block 123),并将此指令转换为能被存储设备驱动器识别的针对存储硬件设备的指令。
  • basic file system : 在 Linux 系统中被称为 “block I/O subsystem。这一层的主要功能是将上层的通用的读写 block 的指令发布给正确的存储设备驱动器(device driver)来读写存储设备上的 block。它发送给存储设备驱动器(device driver)的是 逻辑块地址(Logical block address),它还负责 IO request scheduling 以及 buffers 和 caches。
  • file-organization module : 主要存储了文件和他们对应的 logical blocks 的信息。还包括 free-space manager,用来跟踪未分配的 logical blocks,当 file-organization module 需要空闲块时提供空闲的块地址信息。
  • logical file system : 负责管理 metadata 信息。Metadata 信息存储了所有的文件系统结构信息(包括 目录结构文件名),只是不包括具体的数据。关键信息包括 FCB (file-controle blocks,即 inode),存储了文件的具体信息如 owershippermissionslocations of file contents(location of logical blocks)

system-wide open-file table And per-process open-file table

大多数操作系统再打开并使用文件之前,都需要(implicitly or explicitly)系统调用 open(),操作系统维护了一个 open-file table,维护着所有的打开文件的信息。当一个文件操作(如读,写,执行等)被请求前,系统调用 open(),文件会通过一个 index 被加入到 open-file table,当文件不在使用时,open-file table 中关于此文件的条目(index) 被移除。

系统中维护了 2 中类别的 open-file table:

  • per-process open-file table : 跟踪进程打开的文件列表,此表中的列表实际是指向 system-wide open-file table 中相关条目(entry)的指针(pointer)。
  • system-wide open-file table : 维护了系统上所有的打开的文件信息,保存了如 文件路径文件大小文件时间属性(access time 等)open count 等信息,当一个进程打开一个文件后,system-wide open-file table 中就会添加一个此文件相关的条目,当另一个进程打开同样的文件后,进程的 per-process open-file table 中只是会添加一条到 system-wide open-file table 中对应文件的引用(entry)。system-wide open-file table 中的每个条目还维护了一个 open count,记录了有多少进程打开了此文件,当某个进程关闭此文件后,其 open count 会减少,值为 0 时,表示没有任何进程打开了此文件,此条目可以从 system-wide open-file table 中移除。

system-wide open-file table 里面关于文件的信息,保存的主要是 FCB 的拷贝(Copy)

per-process open-file table 里面存储的主要是到 system-wide open-file table 里面的对应文件的指针(pointers)

Linux 系统中要查看 open-file table 相关信息,可以使用 lsoffuser/proc/<pid>/fd/ 等方法。

Security

Encryption

Symmetric Encryption

对称加密算法(Symmetric Encryption) 中,加密和解密使用同样的密钥(Key)

Glossary

GNU: GNU’s Not Unix,Richard Stallman 于 1984 年开始开发的自由(free)的类 Unix 操作系统。包括编译器、编辑器、库文件、游戏等应用,没有内核。

GNU/Linux: 1991 年,Linus Torvalds 发布了最初版类 Unix 操作系统内核,并使用了 GNU 提供的编译器和工具。

FSF: Free Software Foundation,自由软件基金会,由 Richard Stallman 于 1985 年成立,旨在鼓励和推动自由软件的使用和开发。自由不等于免费

GPL: GNU General Public License。

ELF: Executable and Linkable Format.

ABI : Application Binary Interface. ABI 定义了在不同架构以及不同的操作系统中,一个二进制代码(Binary Code)提供的接口的差异性。ABI 定义了二进制代码的底层细节,如地址宽度、向系统调用(system calls)提供参数的方法、运行时的堆栈(stack)的组织方式、系统库的二进制格式、数据类型等信息。ABI 是架构级别(architecture-level)的定义,如果一个二进制文件是根据特点的架构(如 ARMv8 processor)编译(链接)而成,那将他迁移到支持此 ABI 的另外的系统上,理论上它也可以正常运行。[3]

RTE : Run Time Environment.

LKMs : Loadable Kernel Modules.

Darwin : iOS/MacOS 底层的类 Unix 操作系统,主要基于 BSD UNIX 的 microkernel

IPC : Inter-Process Communication.

RPCs : Remote Procedure Calls.

JNI : Java Native Interface.

HAL : Hardware Abstraction Layer.

UEFI : Unified Extensible Firmware Interface. 最新的硬件初始化程序,用于取代 BIOS

initramfs : 在系统启动过程中(Bootstrap Program 运行过程,比如 GRUB),因为根文件系统(root file system)还未挂载,为了挂载根文件系统,必须加载必要的驱动程序和内核模块,boot loader 会创建一个临时 RAM 文件系统,即 initramfs。一旦内核开始运行,必要的驱动已经安装,内核会将根文件系统从 initramfs 切换到已经挂载的根文件系统。然后启动 systemd 进程。

CMT : Chip MultiThreading. 一个物理 CPU 核上实现了双线程或多线程的支持。在一个 CPU 线程因等待内存加载数据而空闲(Memory Stall)时,另一个 CPU 线程开始执行。每个 CPU 线程拥有自己独立的状态数据(architectural state)、指令指针(instruction pointer)、注册器(regester set)等,可以将其当作一个单独的逻辑 CPU 来运行单独的线程(进程/Job)。如 Intel 的超线程(hyper-threading)或者叫 SMT(Simultaneous Multi-Threading)

CFS : Completely Fail Scheduler。Linux kernel 2.6.23 版本开始默认的 CPU 调度算法。

MMU : Memory Management Unit.

HDD : Hard Disk Driver.

SSD : Solid State Disk.

ATA : Advanced Technology Attachment. 存储设备接口协议

SATA : Serial ATA. 存储设备接口协议

SAS : Serial Attached SCSI. 存储设备接口协议

USB : Universal Serial Bus. 存储设备接口协议

FC : Fibre Channel. 存储设备接口协议

NVMe : NVM express. NVM 存储设备专用的通信接口协议。NVM 设备通过 NVMe 接口协议直接连接在系统 PCI 总线上。 相比其他存储接口协议(如 SATA 、SAS 等)增加了吞吐量及减少了延迟。

HBA : Host Bus Adapter.

HAS : Host Attached Storage.

NAS : Network Attached Storage. 存储设备接口协议,使用基于 TCP/IP 的 RPC 实现,如 NFS

FC : Fibre Channel,光纤通道,存储设备接口协议

SANs : Storage Area Networks. 使用基于 TCP/IP 的 RPC 实现

RAIDs : Redundant Arrays of Independent Disks.

DES : Data Encryption Standard.

AES : Advanced Encryption Standard

IKE : Internet Key Exchange.

TLS : Transport Layer Security. SSL 的升级版

SSL : Secure Sockets Layer.

MAC : Mandatory Access Control. Linux 系统中,是 SELinux 的一部分。

DAC : Discretionary Access Control. UNIX-based 系统上使用的权限控制策略(chmodchownchgrp

PAM : Pluggable Authentication Modules. UNIX-based 系统上使用的用户鉴权模块

BSD : Berkeley Software Distribution. 第一个 Unix 发行版,由 California Berkeley 大学发行

FSF : Free Software Foundation, 自由软件基金会,由 理查德斯托曼 于 1984 年发起的开源运动,GNU 是其主要的一部分

参考链接|Bibliography

Operating System Concepts v10 Online

脚注


  1. 1.Operating System Concepts v10 Online 1.2.3 I/O Structure
  2. 2.Operating System Concepts v10 Online 1.3.2 Multiprocessor Systems
  3. 3.Operating System Concepts v10 Online 2.6 Why Applications Are Operating-System Specific
  4. 4.Operating System Concepts v10 Online CHAPTER 5 CPU Scheduling
  5. 5.Operating System Concepts v10 Online 5.5.4 Processor Affinity
  6. 6.Operating System Concepts v10 Online 9.1.5 Dynamic Linking and Shared Libraries
  7. 7.Operating System Concepts v10 Online CHAPTER 10 Virtual Memory
  8. 8.Operating System Concepts v10 Online 10.8 Allocating Kernel Memory
  9. 9.Operating System Concepts v10 Online 11.1.1 Hard Disk Drives
  10. 10.Operating System Concepts v10 Online 14.1 File-System Structure