1.精简Linux系统概念模型
1.1 Linux的体系结构
冯·诺依曼体系结构中,计算机硬件由运算器、存储器、控制器、输入设备和输出设备5大基本类型部件组成。
1.1.1 内存管理
Linux地址空间可以分为两部分,分别为用户空间和内核空间,以32位操作系统为例,Linux 默认情况下会将高地址的 1GB 空间分配给内核空间(地址为0xffffffff-0xc0000000),将剩下的3GB空间分配给用户空间。
虚拟地址:为了充分利用和管理系统内存资源,Linux采用虚拟内存管理技术,利用虚拟内存技术让每个进程都有一定容量互不干涉的虚拟地址空间。进程初始化分配和操作的都是基于这个「虚拟地址」,只有当进程需要实际访问内存资源的时候才会建立虚拟地址和物理地址的映射,调入物理内存页。
物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。在前端总线上传输的内存地址都是物理内存地址,编号从0开始一直到可用物理内存的最高端。
1.1.2 进程管理
进程状态:主要分为可运行状态、可中断的等待状态、不可中断的等待状态、暂停状态、跟踪状态、僵死状态和僵死撤销状态。
- 可运行状态:进程要么在CPU上执行,要么准备执行。
- 可中断的等待状态:进程被挂起(睡眠),直到某个条件变为真,产生一个硬件中断,释放进程正等待的系统资源,或传递一个信号都是可以唤醒进程的条件(把进程的状态放回到TASK_RUNNING)
- 不可中断的等待状态:与可中断的等待状态类似,但有一个例外,把信号传递到睡眠进程不能改变它的状态,这种状态很少用到, 但是在一些特定条件下,这种状态还是很有用的。
- 暂停状态:进程的执行被暂停。
- 跟踪状态:进程的执行由debugger程序暂停。
- 僵死状态:进程的执行被终止。
- 僵死撤销状态:父进程刚发出wait4()或waitpid()系统调用,因而进程由系统删除。
1.1.3 文件系统
VFS 是底层文件系统的主要接口。这个组件导出一组接口,然后将它们抽象到各个文件系统,各个文件系统的行为可能差异很大。有两个针对文件系统对象的缓存(inode 和 dentry)。它们缓存最近使用过的文件系统对象。在这里缓冲区缓存和设备驱动的交互、以及VFS提供的系统接口暂不讨论,主要看看实现这个VFS子系统的主要结构。
1.1.4 设备驱动程序
设备驱动程序包含与设备进行通信时所需的所有特定于设备的代码。此代码包括一组用于系统其余部分的标准接口。就像系统调用接口可使应用程序不受平台特定信息影响一样,此接口可保护内核不受设备特定信息的影响。应用程序和内核其余部分需要非常少的特定于设备的代码(如果有)对此设备进行寻址。这样,设备驱动程序使得系统的可移植性更强,并更易于维护。
设备驱动程序按照处理 I/O 的方式可以分为以下三大类别:
- 块设备驱动程序-适用于可将 I/O 数据作为异步块进行处理的情况。通常,块驱动程序用于管理可物理寻址的存储介质的设备,如磁盘。
- 字符设备驱动程序-适用于针对连续的字节流执行 I/O 操作的设备。
- STREAMS 设备驱动程序-字符驱动程序的子集,将 streamio(7I) 例程集用于内核中的字符 I/O。
1.2 具体例子
文件写流程:
- 应用程序发起写请求,触发系统调用write()函数,用户态切换为内核态。
- 文件系统通过目录项→inode→address_space→页缓存树,查询Page Cache是否存在,如果不存在则需要创建。
- Page Cache存在后,CPU将数据从用户缓冲区拷贝到内核缓冲区,Page Cache变为脏页(Dirty Page),写流程返回。
- 用户主动触发刷盘或者达到特定条件内核触发刷盘,唤醒pdflush线程将内核缓冲区的数据刷入磁盘。
2. 影响程序性能表现的原因
分析工具:
- 使用监控分析系统性能工具--sysstat 来查看系统资源的使用情况
- 使用系统压力测试工具--stress来模拟cpu使用繁忙情况
经分析,发现影响程序性能表现主要有以下原因:
2.1 动态链接库过多过大
- 系统加载一个动态链接库需要一个固定的时间消耗,所以库的数量越大,占用的这部分时间就越多;
- 系统的IO以页为单位,库的大小越大,从库总载入有效代码的准确性就越低,导致IO操作的几率就越高,占用的时间也越多;
- 启动过程的动态链接库个数越少越好,大小越小越好。
2.2 网络带宽
- Linux 下的各种应用,一般都是基于网络的,因此网络带宽也是影响性能的一个重要因素。
- 低速的、不稳定的网络将导致网络应用程序的访问阻塞;
- 而稳定、高速的带宽,可以保证应用程序在网络上畅通无阻地运行。
2.3 磁盘IO性能
- 用追加写代替随机写,减少寻址开销,加快 I/O 写的速度;
- 在需要同步写的场景中,尽量将写请求合并,而不是让每个请求都同步写入磁盘;
- 借助缓存 I/O ,充分利用系统缓存,降低实际 I/O 的次数。