linux大神Brendan Gregg 性能之巅 第二版(systems performance)阅读心得(第三章 操作系统)

3.1 术语

        介绍了本章用到的一些概念,比如操作系统、内核、进程等。

3.2 背景

        本章描述了通用的操作系统和内核概念,有助于读者对各类操作系统的实现原理有个基本的理解。

3.2.1 内核

        操作系统,其实就是在硬件设备和应用软件之间的传令官和翻译官,它将对磁盘、CPU、内存等硬件设备的操作指令封装成用户可以直接调用的系统接口,而内核就是操作系统基于硬件的第一层软件扩展。

                        ​​​​​​​        ​​​​​​​        ​​​​​​​        

        内核之上的系统调用和系统库为用户提供了简单的调用接口,比如linux中的 lib,lib64路径下的库文件。在实际生产运维过程中经常会遇到运维工程师误删这两个路径下的库文件导致的故障,甚至会导致系统命令无法执行,系统无法启动。还有强制安装rpm包,导致安装的库文件与系统其他库文件版本不兼容的异常。

        内核的执行

        执行频繁的IO操作,比如磁盘读写、网络交互,主要在内核中进行,主要与硬件设备打交道;而计算密集型的负载通常在用户态运行。但内核很多情况下也会影响,最明显的是CPU调度场景。

3.2.2 内核态和用户态

        内核态和用户态是通过CPU的特权环来控制的,所谓运行态的切换也是CPU安全级别的切换。特权环可以理解为CPU不同的权限级别,分为0,1,2,3 四个级别,实际只用到两个或三个,权限级别从0到3依次降低。等级越高内操控越底层的设备,用户程序运行在用户态,它想往磁盘里写一条数据,需要CPU切换到内核态再执行,这就涉及到CPU的上下文切换。需要先保存用户态的现场,再切换到内核态,在内核态执行完需要的操作后再切换回用户态,并恢复之前保存的现场。

        因为频繁的上下文切换会增加CPU开销,所以对于IO频繁的业务系统不能只关注磁盘性能,往往CPU也会出现瓶颈。

        相对应的,在内存中也区分了用户空间和内核空间,CPU只有在内核态时才有权限对内核空间的内存进行操作。

3.2.3 系统调用

        用户程序执行一些内核态的特权指令是通过系统调用来传递的,可用的系统调用有几百个,常用的有read、write、open、fork等,这些调用尽可能简单,更为复杂的接口作为系统库构建在用户空间中。操作系统通常包含C语言的标准库,其为许多常见的系统调用提供更容易使用的接口(libc、glibc库)。

        下面介绍了几个常用但比较复杂的系统调用:

        ioctl(2):用于设备输入输出操作的系统调用,执行的功能取决于传入的请求码,可以操作的设备包括网络套接字、文件、接口、ARP、路由、流,在linux中,所有的要素都被视为文件,并且分配了唯一的标识fd。

        mmap(2):将可执行文件和库文件以及内存映射文件映射到进程的地址空间。

        futex(2):处理用户空间的锁。

3.2.4 中断

        中断是向处理器发出的信号,即当发生了一些高优先级需要马上处理的事件时,要中断处理器当前的执行来实施处理。要处理中断,处理器需要进去内核态。保存当前执行的线程,运行一个中断服务例程(ISR)来处理该事件。

        有外部硬件产生的异步中断和软件指令产生的同步中断。

        异步中断(硬件设备主动发出中断信号):

        磁盘设备发出磁盘I/O完成的信号

        硬件显示有故障情况

        网络接口发出有数据包到达的信号

        外接设备输入:键盘、鼠标

        同步中断(软件指令主动中断):

        自陷:主动调用内核,例如通过int(中断)指令

        异常:执行错误指令,比如除0

        故障:内存缺页故障(内存中没有需要的数据,要从磁盘加载)

        中断线程ISR

        用于快速处理中断.

        中断屏蔽:内核可以通过设置CPU的中断屏蔽寄存器来暂时屏蔽中断。(时间尽可能要短),一些高优先级的事件可以被实现为不可屏蔽中断(NMI)。

3.2.5 时钟和空闲

        计时器中断:每秒执行次数。功能:更新系统时间,线程调度时间片,维护CPU统计数据,以及执行内核调度例程。

        空闲线程:CPU没有工作可做时,内核会安排一个占位线程。

3.2.6 进程

        进程保存了用户程序执行的环境信息,包含内存地址空间、文件描述符、线程栈和寄存器。PID唯一标识一个进程。一个进程包含一个或多个线程,同一个进程的线程共享进程的地址空间及文件描述符。

        线程包括栈、寄存器以及指令指针(程序计数器),多线程让单一进程可以在多个CPU上并发执行。

        内核启动的第一个进程是 init,在/sbin/init,PID为1,用于启动用户空间。其他的进程都是fork该进程。

        进程的创建

        进程的创建通常使用fork(2)和clone(2)创建一个进程的副本,然后再调用exec(2)来开始执行一个不同的程序。

        fork和clone可以用写时拷贝(copy on write COW)策略提高性能。原理是fork一个新进程时,会添加对原有地址空间的引用而非把所有内容都复制一遍,如果进程要修改被引用的内存空间才会建立一个单独的副本。推迟甚至取消了内存拷贝的需要。

        进程的生命周期

        进程环境

        进程环境分为用户地址空间和内核上下文,内核上下文保存了进程切换时需要保存或换入的进程信息,而用户地址空间是内存中的用户数据和用户栈。

        

3.2.7 栈

        栈是存储临时数据的内存区域,函数被调用时,返回地址保存到栈中,函数需要的一些寄存器的值也可以被保存在栈里面。函数执行完后,恢复所有需要的寄存器,并从栈中获取返回地址。通过检查线程栈中的所有栈帧中保存的返回地址,可以看到当前函数的调用路径(栈遍历)。

        通过向下阅读栈,可以看到函数完整的调用链,自下而上,可以跟踪函数的执行路径。一般tomcat java程序的报错信息都会列出程序执行的栈,从而定位到具体的代码。

3.2.8 虚拟内存

        虚拟内存是主存的抽象,每个进程都有一个完整主存大小的私有地址空间,进程可以随意往自己的虚拟内存空间存取数据,而不用担心与其他进程冲突,因为这并不是真实的内存,操作系统会将虚拟内存映射到真实内存。

        内存管理

        内核会尽力将最活跃的数据放在主存中:换页(更高效)和进程交换。

3.2.9 调度器

        现在常见的UNIX衍生操作系统都是分时系统,划分了一个个时间周期,其实每个cpu同一时刻还是只执行一个线程,但在一个时间段内,多个线程依次执行,看起来也是并行。而多个线程如何依次执行,则是由CPU调度器控制的。

        调度器维护了一套优先级机制和多个优先级队列,调度器可以动态地修改进程的优先级以提升特定工作负载的性能。工作负载分类:CPU密集型、IO密集型。

3.2.10 文件系统

        文件系统是操作系统中文件和目录的组织方式,以根目录为起点(“/”),自上而下,通过挂载可以添加文件系统的树,把自己的树挂在一个挂载点上(目录)。linux常用的文件系统有xfs、ext4。

                

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值