代码改变世界

《性能之巅:洞悉系统、企业与云计算》笔记——操作系统与观测工具

2025-08-15 20:36  第二个卿老师  阅读(11)  评论(0)    收藏  举报

《性能之巅:洞悉系统、企业与云计算》笔记——操作系统与观测工具

作者: Brendan Gregg 第一版

本书包含了Linux与Solaris两个系统,我把重点放在了Linux上


第三章 · 操作系统(Operating Systems)

  • 常用术语:

    • 操作系统: 包含内核、管理工具、以及系统库
    • 内核: 内核是管理系统的程序,包括设备(硬件)、内存和CPU调度
    • 进程: 一个OS的抽象概念,用来执行程序的环境
    • 线程: 可被调度的运行在CPU上的可执行上下文
    • 任务: 一个Linux的可运行实体,可指线程或进程
    • 内核空间: 内核的内存地址空间
    • 用户空间: 进程的内存地址空间
    • 上下文切换: 内核程序切换CPU让其在不同的地址空间上做操作
    • 系统调用: 一套定义明确的协议,为用户程序请求内核执行特权操作
    • 自陷: 信号发送到内核,请求执行一段系统程序
    • 中断: 由物理设备发送给内核的信号
  • 内核:

    • 内核执行是按需的,I/O密集型的负载,会经常执行在内核上下文中,而计算密集型的负载会尽量减少内核执行
    • Linux中clock例程主要是更新系统时钟和jiffies计数器
    • 内核是唯一运行在内核态的程序(该状态下,设备的一切访问及特权指令的执行都是被允许的),而用户程序运行在用户态,通过系统调用来运行特权指令,这时会发生上下文切换
    • 软件执行上下文包括栈和寄存器
  • 栈:

    • 栈用函数和寄存器的方式记录了线程的执行历史,可使用栈检查来进行调试和性能分析
    • 进行系统调用时,线程可有用户栈和内核栈
  • 中断:

    • Linux内核响应设备中断包括上下两部分,上部分快速响应处理中断,下半部的调度工作在之后处理
    • 中断存在优先级处理,其中错误、交叉调用、串行I/O的中断优先级很高
  • 进程:

    • 进程是用以执行用户级别程序的环境,包括内存地址空间、文件描述符、线程栈、寄存器,用进程ID做唯一识别(PID)

    • 进程通过系统调用fork()来创建的,然后再通过exec()执行程序

    • 进程生命周期(Idle —> Ready to Run —> On-Proc —> Zombie)
      WebSocket

    • 进程环境:包括用户地址空间(各种内存段:可执行文件、库、堆)、内核元数据(进程属性与统计信息等状态、文件描述符)

  • 系统调用: 常见调用有read()(读取字节),write()(写入字节),open()(打开文件),close()(关闭文件),fork()(创建新进程),exec()(执行新程序),connect()(连接到网络主机),accept()(接受网络连接),stat()(获取文件统计信息),ioctl()(设置I/O属性或其他),mmap()(把文件映射到内存地址空间),brk()(扩展堆指针)

  • 虚拟内存: 主存的抽象,支持映射到磁盘上,有近乎无穷的存储空间

  • 内存管理: 现代Linux通过换页替换了交换,也称为“swapping”

  • 调度器: 维护一套优先级的机制,将CPU时间划分给活跃的进程和线程

  • 文件系统:

    • 作为文件和目录的数据组织,以根目录(“/”)为起点,自上而下的拓扑结构
    • 虚拟文件系统(VFS)是一个对文件系统类型做抽象的内核界面
    • I/O栈:应用程序—>系统调用(也可直接到块设备接口)—>VFS—>文件系统—>卷管理器—>块设备接口—>目标I/O驱动—>主机总线适配器驱动—>磁盘设备
  • 其他: 包括缓存、网络、设备驱动、多处理器、抢占、资源管理、观测性后续篇幅介绍

  • 内核历史: UNIX(1969),BSD(1978),Solaris(1982),Linux(1991),mac OS(2001)


第四章 · 可观测性工具(Observability Tools)

  • 工具分类:
    • Counters(计数器): 零开销,本质是对事件计数并递增,系统级别(vmstat、mpstat、iostat、netstat、sar),进程级别(ps、top、pmap),后者通常来源于/proc文件
    • Tracing(事件跟踪): 部分CPU与存储开销,本质是跟踪每个事件的数据,系统级别(snoop、blktrace、iosnoop、execsnoop、dtruss、DTrace、SystemTap、perf),进程级别(strace、truss、gdb、mdb)
    • Profiling(采样剖析): 对目标收集采样或快照,oprofile,perf,DTrace,SystemTap等
    • Monitoring(常驻监控): 对目标进行监控,sar
  • 系统数据来源:
    • Linux :
      • 计数器来源于:/proc/sys
      • 设备驱动和调试信息: /sys
      • 进程级跟踪:ptrace、uprobes
      • 性能计数器:perf_event
      • 网络跟踪:libpcap
      • 进程级延时指标:延时核算
      • 系统级跟踪:tracepoints、kprobes、ftrace
  • 延时核算: Linux中可采用taskstats接口读取每个任务的时间,包括调度器延时、块I/O、交换、内存回收
  • 动态追踪技术演示:
    • DTrace/SystemTap/perf 等,通过内核探针插装、脚本大量自动化完成诊断任务

📌 总结感悟

这两章主要是对操作系统整个架构进行梳理,并阐述了相关观测工具的数据来源与使用,自己看了后又扩展了一些知识,总结如下

操作系统的重要性

  • 操作系统是软件和硬件之间的桥梁,是一个庞大且复杂的软件系统
  • 作为应用程序运行的基石,对性能分析来说了解操作系统是必要的

Linux内核

  • 内核管理着CPU调度、内存、文件系统、网络协议、以及系统设备(磁盘、网络接口等)
  • 当你启动Linux系统时,内核首先被加载到内存,然后它负责初始化系统并启动第一个用户空间进程(通常是init或systemd)
  • Linux 是一个宏内核,完全支持并管理多个并发执行的用户进程和线程
  • 内核内部通过内核线程、中断处理、软中断/任务队列以及SMP支持,实现了自身执行路径的高度并发

内核线程、用户进程、用户线程的区分

  • 从 Linux 内核的角度来看,并没有把线程和进程区别对待,无论线程还是进程,都是用task_struct结构表示的,唯一的区别就是共享的数据区域不同,参考来源——Linux 进程、线程、文件描述符的底层原理
  • 内核线程: 内核本身会创建和管理一些内核线程,这些线程运行在内核空间,执行后台任务
  • 用户线程: 线程的某些数据区域和其父进程是共享的
  • 用户进程: 主要运行在用户空间,可能会共享一些内核空间的资源

1,那么内核线程为什么不叫内核进程呢?
因为内核线程共享内核地址空间,即共享同一份内核页表,所以叫内核线程
2,子进程和子线程又是指什么?
由于用task_struct结构表示进程,子进程拷贝了父进程的数据区域(比如内存空间与文件描述符),是单独的,而子线程是共享父进程的数据区域
3,内核线程、用户进程、用户线程的进程环境是什么?
内核线程拥有:进程描述符、PID、进程正文段、核心堆栈
用户进程拥有:进程描述符、PID、进程正文段、核心堆栈 、用户空间的数据段和堆栈
用户线程拥有:进程描述符、PID、进程正文段、核心堆栈,同父进程共享用户空间的数据段和堆栈

进程切换、线程切换、协程是什么

  • 进程切换: 陷入内核态,进行页表切换、刷新TLB、内核栈切换、寄存器保存/恢复
  • 线程切换: 陷入内核态,无页表切换,仅保存寄存器、栈指针
  • 线程模型: Linux和Window系列的操作系统都采用了一对一的实现模型,即用户线程(也叫LWP)陷入内核态时依旧还是这个线程,只是从特权级别Ring 3 切换到了Ring 0
  • 协程: 采用多对一(python、JS)或多对多(Go、Java)的线程实现模型,多个协程共享一个或多个用户线程,在用户态实现调度,无需陷入内核

栈、文件描述符是什么

  • 线程的用户栈和内核栈:
    • 用户栈:保存函数调用、局部变量、返回地址(Java的jstack工具就打印用户栈)
    • 内核栈:保存陷入内核态时的寄存器、局部变量,函数调用链,可用ftrace、perf工具
  • 文件描述符:
    • 本质: 是task_struct结构中文件指针数组的索引(struct files_struct *files;),程序的文件描述符默认情况下 0 是输入,1 是输出,2 是错误
    • 作用:文件、管道、网络套接字、设备文件等都通过文件描述符来操作,比如高并发时服务器的连接数就是文件描述符数(一般是1024)
    • 与进程、线程关系: 属于进程级资源,但线程共享它

应用程序是如何工作的

  • 程序编译或解释: 应用程序的源代码会经过编译(或解释)生成机器码可执行文件,或生成需要运行在虚拟机/解释器上的字节码文件
  • 程序初始化: 通过命令等方式,操作系统会创建进程,将可执行文件(或虚拟机)加载到该进程的虚拟内存中,初始化所需的运行环境,并在进程内创建至少一个线程
  • 程序运行: 调度器会把这些线程分配到 CPU 核心上执行,最终由 CPU 依次取指、解码、执行、写回完成程序的运行