「Linux性能优化大师」
我其实是买了这本书好多年了,都是拿起来翻了两页就看不动了,最近下决心还是把它看完吧,毕竟这书真的有点老了。该书是基于LInux 2.6内核和RHEL6的版本为例进行的Linux性能解析,即便在15年成书的时候,都已经算老了。这本书的内容的确有很大问题,个人感觉更像红帽EX442考试的参考教程,很多语句就像英文硬翻的,只能说有一定的科普的作用。
说起来,该书作者赵永刚还是我素未谋面的同事,他是我在纷享工作岗位的前前任,我曾经蹲的工位也曾是他的工位。
性能调优是一项艰巨的任务,需要深入了解硬件、操作系统和应用程序的工作原理。
2024.07 摄于北京朝阳区·众秀大厦
深入理解Linux操作系统
Linux进程管理
进程
进程管理在任何操作系统中都是最重要的任务之一。进程是在处理器上执行的一个实例,进程可以使用任意资源以便内核可以处理完成任务。在Linux操作系统上运行的进程多是通过task_struct结构来管理的,也被称为进程描述符。一个进程描述符包含了单个进程在运行期间所有必要的信息,比如进程表示、属性、构建进程的资源等。
每个进程都有自己的生命周期,比如创建、执行、终止、删除等。只要系统启动和运行,这些阶段就会不断重复。
- 当一个进程创建一个新进程时,父进程就会发出一个fork()系统调用,然后父进程得到一个子进程的进程描述符,并设置一个新的ID。
- exec()系统调用将新的程序复制到子进程的地址空间,内核给子进程分配新的物理页,子进程执行自己的程序,而不是父进程相同的操作
- 当程序执行完成,通过exit()系统调用终止子进程,exit()释放进程数据结构并发送一个终止信号通知父进程
- 子进程不会完全移除,知道父进程通过wait()调用得知子进程已终止,父进程就会释放进程描述符
线程
线程时进程中产生的一个执行单元,在同一个进程中与其他线程并行运行,共享相同的资源,访问同一组应用程序数据。线程也被称为轻量级进程。因为资源共享,所以互斥、锁、序列化是用户应用程序要实现的机制。
具体的实现有:
- LinuxThreads
- Native POSIX Thread Library
- Next Generation POSIX Thread
优先级和nice等级
进程优先级是一个数字,用来确定CPU处理进程的顺序,并可以确定实时优先级和非实时优先级。最高实时优先级(99)对应于系统优先级0,最低非实时优先级(0)对应于系统优先级99。
一个进程可以间接通过使用nice级别来修改实时优先级,高实时优先级的进程可以更多的占用CPU时间。Linux的nice级别可以从最低的19到-20的最高优先级,默认为0。
上下文处理
在处理器执行期间,运行进程的信息被存储在处理器的寄存器和高速缓存中,执行的进程被加载到寄存器的数据集被称为上下文,切换过程被称为上下文切换。
中断处理
中断处理时优先级最高的任务之一,通常由I/O设备产生,是由内核通知事件。当中断信号到达内核时,内核必须要从当前执行的进程切换到一个新的进程。
[root@share ~]# cat /proc/interrupts |
进程状态
- TASK_RUNNING
- TASK_STOPPED
- TASK_INTERRUPTIBLE
- TASK_UNINTERRUPTIBLE
- TASK_ZOMBIE
当一个进程接收到一个终止信号,在它结束之前需要一些时间结束所有任务,在此期间它就是僵尸进程。使用kill命令无法杀死僵尸进程,除非杀死父进程。
进程的内存段
- 文本段:存储可执行代码
- 数据段
- 数据,初始化数据,比如静态变量
- BSS,零初始化数据,数据被初始化为零
- 堆,根据需求动态分配内存,向高地址增长
- 堆栈段,局部变量、函数参数、返回的存储函数存放区域
CPU调度程序
内核使用进程调度程序来确定那个程序在那个给定时间点运行。
- 0(1)调度程序
- CFS完全公平调度程序
内存体系结构
物理内存和虚拟内存
- 页帧分配
- 一个分页是物理内存或者虚拟内存中一组连续线性地址,内核以内存页为单位处理内存,通常为4KB大小
- 进程不能直接对物理内存寻址,每个进程有一个虚拟地址空间,页帧的物理地址被映射到进程的虚拟地址
- 虚拟内存寻址布局
- 32位架构的最大地址访问空间是4GB,其中1GB为内核空间,3GB为用户空间
- 64位架构没有限制。
虚拟内存管理
管理虚拟内存的默认规则:分配所有有效空闲内存空间作为磁盘缓存。
伙伴算法:把所有空闲的内存,以2的幂次方的形式,分成11个块链表,分别对应为1、2、4、8、16、32、64、128、256、512、1024个页块。
[root@share ~]# cat /proc/buddyinfo
Node 0, zone DMA 0 0 0 0 0 1 1 1 0 1 3
Node 0, zone DMA32 235 43 27 3 4 7 4 3 3 5 55分页回收
当进程所需要分页不足时,内核将尝试释放一定数量的分页,然后进行重新分配。内核线程kswapd和内核函数try_to_free_page()负责分页回收。其原则基于Least Recently Used最近最少原则,最近最少使用哦个的分页被释放,活跃列表和非活跃列表用于维护候选分页。
kswapd同时遵循宁可缩小分页缓存也不改变分页移出(page out 或者 swap out)进程拥有的分页的原则。分页缓存时分页被映射到磁盘上的一个文件,被称为匿名内存。可以通过/proc/sys/vm/swapiness来控制,1表示尽量使用分页缓存,10表示尽量不使用。
[root@share ~]# cat /proc/sys/vm/swappiness
10SWAP
当发生分页回收时,在非活跃列表中属于进程空间的候选分页可以被移出。如果虚拟内存管理器发现内存分页已经被分配,但大量时间还没有使用完,就会把这个内存分页移动到swap空间。
文件系统
虚拟文件系统
VFS时驻留在用户进程与各类型的Linux文件系统之间的抽象接口层。VFS提供了访问文件系统对象的通用对象模型和方法,对用户进程隐藏了文件系统实现的方法和差异。
文件系统日志
为了保证数据的完整性,文件系统在执行写入数据到实际文件系统之前,先将改变数据写入日志区域。被写入日志区域的数据称为日志记录。它包含了改变的文件系统元数据和实际的文件数据。
EXT2
EXT3的前身,没有日志功能,是个快速、简单的文件系统。以引导扇区开始,然后是块组将整个文件系统分成若干区域,将用户数据的索引节点表和数据块更紧密的保存在盘片上,以此减少寻道时间。
一个块组包括
- 超级块,存储文件系统信息,放置在每个块组的顶部
- 块组描述符:存储块组信息
- 数据块位图:用于空闲数据块管理
- 索引节点位图:用于空闲索引节点管理
- 索引节点表:保存文件的元数据
- 数据块:实际用户数据存储
EXT3
增加了日志功能的ext2,提高了可用性和数据完整性。其日志模式有以下三种
- 全日志,元数据和实际数据先被写入日志区,然后再写入主文件系统
- 顺序,实际数据直接写入主文件系统,元数据在实际数据写完后再被写入日志区,是默认的模式
- 回写,元数据先写入日志区,然后再将实际数据直接写入文件系统
EXT4
EXT3的升级,提供了文件系统的伸缩性,突破了文件系统的限制,支持最大单体16TB文件,存储容量最大1EB。此外还采用了一系列提高性能和安全性的措施:
- 文件级预分配
- 延迟块分配
- 多个块分配
- 执行文件系统日志校验和
- 在线磁盘碎片整理
XFS
Btrfs
磁盘I/O系统
体系结构
当磁盘执行写入操作时发生的基本操作
- 一个进程通过write()系统调用请求写一个文件
- 内核更新已映射文件的分页缓存
- 内核线程将分页缓存刷新到磁盘
- 文件系统层同时放置块缓存,并向块设备提交写请求
- 块设备从上层得到请求,并执行IO操作
- 设备驱动器将执行写操作
- 磁盘设备固件执行硬件操作
Cache
- 存储层次结构
- 访问局部性
- 刷新脏页
块层
IO电梯调度
- CFQ 完全公平队列,使用并发读写系统,例如多媒体应用和桌面系统
- Deadline算法,近似实时算法,适用于数据库服务器等大I/O操作
- NOOP算法,无操作,执行先入先出队列,使用SSD和SAN
设备驱动程序
- SCSI
RAID
网络子系统
网络化的实现
网络传输基本操作
- 当应用程序发送数据到对等主机时,应用程序创建数据
- 应用程序打开socket,并通过socket接口写入数据
- socket缓冲区引用数据,向下穿过各层
- TCP/IP各层添加报头、校验和、路由操作、分片等等
- 网络接口卡向线缆发送数据,并增加一个中断
- 以太帧到达对等主机网络接口卡
- 如果mac地址匹配接口卡的mac地址,将帧移动到网络接口卡的缓冲区
- CPU之后处理数据包,并使其向上穿过各层,直到应用程序的TCP端口
socket buffer内核缓冲区
NAPI(Network API)
Netfilter
- 数据包过滤filter
- 地址转换nat
- 改变数据包mangle
连续跟踪
TCP/IP
- 建立连接
- 流量控制
- 传输窗口
- 重传
Offload
Bonding
性能度量标准
CPU
- CPU使用率
- 用户进程消耗时间
- 内核操作消耗时间
- 等待
- CPU空闲时间
- Nice消耗CPU时间
- 平均负载
- 不是一个百分比
- 队列等待进程数和等待不可中断任务被完成进程数之和
- 可运行进程
- 阻塞的进程
- 上下文切换
- 中断
内存
- 空闲内存
- 使用的swap
- 缓存和缓冲
- slab
- 活跃和非活跃内存
块设备
- IO等待
- 平均队列长度
- 平均等待时间
- 每秒传输
- 每秒读取/写入块的数量
- 每秒读取/写入的字节
网络接口
- 接收和发送的数据包
- 接收和发送的字节
- 每秒钟的冲突数量
- 丢弃的数据包
- 溢出
- 错误
分析性能瓶颈
识别系统瓶颈
处理步骤
- 了解你的系统
- 备份系统
- 监控和分析系统的性能
- 缩小瓶颈
- 通过尝试以此一个更改,找到发生瓶颈的原因
收集信息
- 你能给我一个问题服务器的完整描述吗?
- 型号
- 生产日期
- 配置
- 外围设备
- 操作系统版本和更新级别
- 你能告诉我到底时什么问题吗?
- 有什么症状?
- 描述任意错误信息
- 谁遇到的这个问题?
- 问题可以复现么?
- 复现的步骤是什么?
- 这是一个间歇性的问题么?
- 它发生在一天的某个时段,或是几天,或是周几?
- 这是不寻常的么?
- 问题是什么时候开始的?他是平缓的,还是很快的发生?
- 对服务器做出任何改变或者对客户端使用服务器的方法做出任何改变?
- 是否涉及任何其他服务器或硬件组件?
- 是否有任何可用的日志?
- 问题的优先级是什么?什么时候能解决?
分析服务器性能
- 了解影响服务器性能的因素
- 测量当前性能,创建一个性能基线,与未来的测量相比较
- 使用监控工具来识别性能瓶颈
- 组件工作导致瓶颈,那么升级组件就是一个号的方法
- 测量新的性能
CPU瓶颈
高CPU使用率并不总是意味着CPU忙于工作,它可能在等待另一个子系统。当执行适当的分析时,要整体来查看系统和所有子系统。
- 使用top或者htop,查看CPU的使用者
- 使用sar和gnuplot进行长期监控,并输出为图表
- vmstat
如果确认是CPU的问题,那么可以采取以下措施来提高性能:
- 使用ps -ef命令来确认后台是否有不必要的程序
- 使用top识别非关键性CPU密集程序,并使用renice修改它们的优先级
- 尝试使用taskset来绑定进程到指定CPU,确保进程不会在处理器之间跳跃,导致cache刷新
- 根据应用程序特性来选择CPU,例如单线程程序需要更快的CPU,而不是更多的CPU
- 确保使用最新的驱动程序和固件
内存瓶颈
如果认为存在内存瓶颈,可以执行如下操作:
- 调整swap空间,使用大页、hugetlb共享内存
- 增加或者减少分页的大小
- 改进活跃和非活跃内存的处理
- 调整分页移出率
- 限制服务器上每个用户的资源使用
- 停止不必要的服务
- 增加内存
磁盘瓶颈
磁盘子系统是最常见的瓶颈。常见的瓶颈有磁盘空间太小和同一个阵列上有太多的逻辑磁盘。
检查磁盘瓶颈的分析方法有两种:
- 实时监控
- 收集性能数据
- 使用iostat或者vmstat来获取相关指标
磁盘性能瓶颈的调优的方法:
- 增加更快的磁盘控制器
- 在raid中增加更多的磁盘驱动器
- 考虑使用条带化的Linux逻辑卷
- 将进程卸载到网络中的另一个系统
- 添加更多的内存,提高系统内的磁盘cache
网络瓶颈
- 确保网卡配置与路由器和交换机配置相匹配
- 调整网络配置和拓扑
- 使用更快的网卡
- 调整适当的TCP/IP内核参数
- 更新网卡驱动并重新检查性能
- 添加网卡,并组件bond或者team,形成一个适配器群组
调整操作系统
调整原则
- 分析和评估当前系统配置
- 确保系统按照硬件制造商所述运行,所有设备在最佳模式下运行
- 系统被设计为最佳性能,最小化运行不必要任务和子系统
- 调整通常是让系统适应一个特定的工作负载
变更管理
- 在调整任何Linux系统之前,实施适当的变更管理过程
- 绝不在生产服务器上开始调整设置
- 绝不在调整过程期间改变一个以上的变量
- 重新启动可能提高性能的参数,
- 记录成功的参数并分析它们,无论你人为它们是多么微不足道。
安装事项
- 需要什么特点和版本的Linux
- 选择正确的内核
- 选择什么样的分区布局
- 使用什么样的文件系统
- 软件的选择
- Netfilter配置
- SElinux
- 运行级别的选择
当前配置
硬件信息
CPU
- 模式、架构、主板芯片
- 多少个插槽、每CPU多少个核心、多少个线程、socket如何连接
- CPU每层cache有多大、cache是私有还是共享、cache如何组织和访问
- 处理的特性和功能
内存
- 多少内存,硬件允许最大内存数量是多少?
- 系统使用内存技术是什么?带宽和延迟
- 内存如何被连接到CPU
- NUMA节点使用什么技术?
存储
- 存储设备是什么类型,是机械硬盘还是固态硬盘
- SSD驱动器使用的是MLC还是SLC,RAID级别和条带的大小
- 直连式存储使用什么连接,带宽是多少
- SAN设备是使用fc还是iscsi,带宽和延迟是多少?
网络
- 网络接口卡是什么,线缆规格是什么
- 有什么特殊用途的网络,带宽是多少?
- 需要特别能力么?比如网卡直通、IO虚拟化等
系统内容
查看内核信息
[root@testnode ~]# dmesg
[ 0.000000] Linux version 5.14.0-427.33.1.el9_4.x86_64 (mockbuild@iad1-prod-build001.bld.equ.rockylinux.org) (gcc (GCC) 11.4.1 20231218 (Red Hat 11.4.1-3), GNU ld version 2.35.2-43.el9) #1 SMP PREEMPT_DYNAMIC Wed Aug 28 17:34:59 UTC 2024
[ 0.000000] The list of certified hardware and cloud instances for Enterprise Linux 9 can be viewed at the Red Hat Ecosystem Catalog, https://catalog.redhat.com.
[ 0.000000] Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-427.33.1.el9_4.x86_64 root=/dev/mapper/rl-root ro resume=/dev/mapper/rl-swap rd.lvm.lv=rl/root rd.lvm.lv=rl/swap rhgb quiet crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M
[ 0.000000] Disabled fast string operations
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[ 0.000000] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
[ 0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'compacted' format.
[ 0.000000] signal: max sigframe size: 1776
[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] NX (Execute Disable) protection: active
[ 0.000000] SMBIOS 2.7 present.
[ 0.000000] DMI: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
[ 0.000000] vmware: hypercall mode: 0x02
[ 0.000000] Hypervisor detected: VMware
[ 0.000000] vmware: TSC freq read from hypervisor : 2112.004 MHz
[ 0.000000] vmware: Host bus clock speed read from hypervisor : 66000000 Hz
[ 0.000000] vmware: using clock offset of 16204854701 ns
[ 0.000017] tsc: Detected 2112.004 MHz processor
[ 0.001892] e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
[ 0.001897] e820: remove [mem 0x000a0000-0x000fffff] usable
[ 0.001903] last_pfn = 0x80000 max_arch_pfn = 0x400000000
[ 0.001992] total RAM covered: 3072M
[ 0.002467] Found optimal setting for mtrr clean up
[ 0.002468] gran_size: 64K chunk_size: 64K num_reg: 2 lose cover RAM: 0G
[ 0.002472] MTRR map: 7 entries (6 fixed + 1 variable; max 22), built from 8 variable MTRRs
[ 0.002478] x86/PAT: Configuration [0-7]: WB WC UC- UC WB WP UC- WT
[ 0.012113] found SMP MP-table at [mem 0x000f6a70-0x000f6a7f]
[ 0.012161] Using GB pages for direct mapping
[ 0.012312] RAMDISK: [mem 0x33c10000-0x35dfffff]查看CPU信息
查看CPU信息
[root@testnode ~]# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 45 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 1
On-line CPU(s) list: 0
Vendor ID: GenuineIntel
BIOS Vendor ID: GenuineIntel
Model name: Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz
BIOS Model name: Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz
CPU family: 6
Model: 142
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 1
Stepping: 12
BogoMIPS: 4224.00
查看CPU各级缓存信息
[root@testnode ~]# lscpu -p
The following is the parsable format, which can be fed to other
programs. Each different item in every column has an unique ID
starting usually from zero.
CPU,Core,Socket,Node,,L1d,L1i,L2,L3
0,0,0,0,,0,0,0,0查看BIOS信息
[root@testnode ~]# dmidecode
dmidecode 3.5
Getting SMBIOS data from sysfs.
SMBIOS 2.7 present.
620 structures occupying 29188 bytes.
Table at 0x000E0010.
Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
Vendor: Phoenix Technologies LTD
Version: 6.00
Release Date: 11/12/2020
Address: 0xEA480
Runtime Size: 88960 bytes
ROM Size: 64 kB
Characteristics:
ISA is supported
PCI is supported
PC Card (PCMCIA) is supported
PNP is supported
APM is supported
BIOS is upgradeable
BIOS shadowing is allowed
ESCD support is available
Boot from CD is supported
Selectable boot is supported
EDD is supported
Print screen service is supported (int 5h)
8042 keyboard services are supported (int 9h)
Serial services are supported (int 14h)
Printer services are supported (int 17h)
CGA/mono video services are supported (int 10h)
ACPI is supported
Smart battery is supported
BIOS boot specification is supported
Function key-initiated network boot is supported
Targeted content distribution is supported
BIOS Revision: 4.6
Firmware Revision: 0.0
最小化资源使用
以最高性能水平设计的系统必须最小化任何资源的浪费。
- 清理守护进程,只运行必要服务
- 更改运行级别
- SElinux的设置
- 重新编译内核
内核参数
proc文件系统
proc文件系统提供了一个用于访问正在运行的内核的接口,可以用它来进行监控和在联机状态下更改内核设置。proc文件系统不是一个真正的文件系统,它不存储数据知识提供了一个访问正在运行的内核的接口。
[root@testnode ~]# ls /proc |
- 数字目录:表示运行的进程和它们各自的进程ID
- ACPI:桌面和笔记本系统支持的高级配置和电源接口
- bus:总线子系统,比如PCI总线和USB接口
- irq: 系统中断信息
- net:网络接口的原始统计
- scsi:关于各自系统的scsi子系统信息
- sys:可以调整的内核参数
- tty:系统的虚拟终端和它连接的物理设备的信息
调整处理器子系统
调整进程优先级
查看进程的调度策略 |
调整CPU亲和力
CPU亲和力就是为了把一个或者多个进程绑定到一个或者多个核心上。CPU亲和力表示为十六进制的位掩码,最低位代表第一个逻辑CPU,最高位对应最后一个逻辑CPU
查看rsyslogd进程的PID |
虚拟机的亲和力
可以将虚机里面的vcpu绑定到指定CPU
平衡中断
NUMA
查看当前主机的NUMA硬件情况,可见只有一个NUMA节点,上面有4个CPU逻辑核 |
调整内存子系统
内存回收
查看内存信息 |
处理内存不足(OOM)
OOM killer,内核为进程保持一个运行的不良分数,分数越高越有可能被杀掉
[root@testnode ~]# cat /proc/1220/oom_score
667
调整SWAP
- swappiness的调整
- 优化swap空间
- 使用高速硬盘作为swap空间
- 创建空闲分区作为swap空间,避免使用swap文件
- 使用多个swap分区,分散swap读写压力
- 合理估算swap空间
HugeTLBfs
HugeTLBfs特性可以是应用程序使用比普通分页更大的分页。可以通过proc/sys/vm/nr_hugepages修改大页大小,但大页大小和数量超过可用物理内存会引起内核panic。
内存同页合并
使用Kernel Samepage Merging功能将KVM虚机中完全相同的分页到同一个内存分页中。ksm进程实际地扫描内存和合并分页,ksmtuned控制ksm是否扫描内存和如何积极扫描内存。
调整磁盘子系统
磁盘子系统的性能最终取决于一个给定设备能够处理的输入输出请求的数量。一般情况下,增加驱动器数量或者更换更快速的硬盘是提高服务器性能最有效的手段。
- 通过创建合适的硬盘分区来提高文件系统属性安全和数据完整性
- 选择正确的I/O算法
- 选择合适的Cache模式
调整网络子系统
- 使用网卡绑定
- 巨帧
- 速度与双工模式
- 增加网络缓冲区
- 增加数据包队列
- 配置offload
- TCP/IP调整
限制资源使用
ulimit
系统默认状态
[root@testnode ~]# ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 14349
max locked memory (kbytes, -l) 8192
max memory size (kbytes, -m) unlimited
open files (-n) 64000
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 14349
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimitedcgroup