性能之巅
- 性能优化方法:包括响应时间和吞吐量优化,以及基准测试、容量规划、垂直和水平扩展等方面的优化方法。
- 系统架构设计:包括分层架构、微服务架构、事件驱动架构、云原生架构等,以及它们的优缺点和适用场景。
- 操作系统和计算机体系结构:包括CPU、内存、缓存、磁盘、网络等硬件和操作系统相关的知识,以及如何优化它们的性能。
- 数据库和存储系统:包括关系型数据库、NoSQL数据库、内存数据库、文件系统等,以及它们的优缺点和适用场景。
- 分布式系统:包括分布式存储、分布式计算、分布式事务等,以及如何处理分布式系统中的并发和一致性问题。
- 云计算和容器技术:包括公有云、私有云、混合云等云计算部署模型,以及Docker、Kubernetes等容器技术的基本概念和使用方法。
- 网络和协议:包括TCP/IP协议、HTTP协议、WebSocket协议等,以及如何诊断和优化网络问题。
- 性能工具和监控:包括负载测试工具、性能监控工具、日志分析工具等,以及如何使用这些工具来诊断和解决性能问题。
- 安全和可靠性:包括如何保证系统的可用性、可靠性和安全性,以及如何应对各种安全和可靠性威胁。
- DevOps和敏捷开发:包括DevOps和敏捷开发的基本概念、实践和工具,以及如何将它们与性能优化和系统设计相结合。
目录结构
第一部分:性能指标与性能分析
- 第1章:性能指标和性能评估
- 第2章:性能分析的基础
- 第3章:性能基准测试
第一部分的重点是关于性能测量的基本原理和工具,涵盖以下几个方面:
- 性能测量的基本原理:Brendan Gregg在本书中介绍了性能测量的四个基本原则,即测量、分析、比较和验证。
- 性能测量的基本工具:本书介绍了多种性能观测工具,包括计数器、跟踪器和剖析器等。其中,计数器是内核维护的统计数据,可以用于对事件计数。
- 火焰图:本书介绍了火焰图作为一种常用的性能分析工具,可以用于可视化代码的执行过程,并识别瓶颈。
- 其他工具和技术:本书还介绍了其他性能观测工具和技术,如dtrace、perf等,并提供了相应的实例和使用方法。
第二部分:系统性能
- 第4章:操作系统的性能
- 第5章:存储系统的性能
- 第6章:网络性能
第三部分:企业应用性能
- 第7章:企业应用性能基础
- 第8章:Java虚拟机性能
- 第9章:数据库性能
- 第10章:Web应用程序性能
第四部分:云计算性能
- 第11章:云计算的性能挑战
- 第12章:云服务的性能分析
- 第13章:云应用程序性能
第五部分:性能优化
- 第14章:系统和应用程序性能优化
- 第15章:云环境中的性能优化
频次最高的10个分析工具或命令
- top:用于查看系统中运行的进程和资源占用情况的命令行工具。
- sar:系统活动报告工具,用于收集和报告系统资源使用情况的命令行工具。
- strace:用于跟踪进程系统调用和信号的命令行工具。
- tcpdump:用于捕获和分析网络数据包的命令行工具。
- Wireshark:网络协议分析工具,用于分析和调试网络通信的图形化工具。
- perf:Linux性能事件分析工具,用于分析CPU、内存和I/O等性能事件的命令行工具。
- lsof:列出打开文件的工具,用于显示系统中打开的文件和进程的命令行工具。
- ps:查看系统进程的命令行工具。
- iostat:输入/输出统计工具,用于监控系统磁盘和存储性能的命令行工具。
- vmstat:虚拟内存统计工具,用于监控系统内存和CPU使用情况的命令行工具。
第1章 综述
1.1 系统性能
(图 1.1 系统性能-通用软件栈)
系统性能:指计算机系统在特定工作负载下的表现,包括响应时间、吞吐量、资源利用率等指标。
- 整个系统的研究:所有的硬件组件和整个软件栈。
- 所有数据路径、软硬件上所有的事情都会影响性能。
- 当讨论到系统性能,全栈表示所有事情,包括系统库及内核。
全栈(entire stack):在性能分析语境下,指从硬件到应用层的完整软件栈,包括:
- 硬件层:CPU、内存、磁盘、网络
- 操作系统层:内核、系统调用、文件系统
- 运行时层:虚拟机、库函数
- 应用层:应用程序代码
注意:有时”全栈”仅指应用程序环境,包括数据库、应用程序,以及网站服务器。
1.2 人员与职能
- 一般人员配置都是兼职对性能问题的解决,这样出现问题需要很多职能的人协作解决。
- 有的公司会请性能工程师(Performance Engineer),其主要任务就是维护系统性能。
- 他们与多个团队协同工作
- 对环境做全局性的研究
- 执行一些对解决复杂性能问题至关重要的操作
- 会开发更好的工具
- 对整个环境做系统级分析(system-wide analysis)
- 为容量规划(capacity planning)定义指标
性能工程师:专门负责系统性能优化和分析的专业人员,需要具备:
- 系统级性能分析能力
- 跨团队协作能力
- 工具开发能力
- 性能建模和容量规划能力
- 性能工程师也有精细到应用程序(MySQL性能工程师、Java性能工程师等)的工种,通常他们在开始使用特定的应用程序工具之前,会做一些系统性能检查,但是有限。
1.3 性能领域的事情
(图 1.3 事情)
- 设置性能目标和建立性能模型
- 基于软件或硬件原型进行性能特征归纳
- 对开发代码进行性能分析(软件整合之前)
- 执行软件非回归性测试(软件发布前或发布后)
- 针对软件发布版本的基准测试
- 目标环境中的概念验证(Proof-of-concept)测试
- 生产环境部署的配置优化
- 监控生产环境中运行的软件
- 特定问题的性能分析
- 1~5 是常见的软件开发过程,这个阶段经常缺失性能设计,从而导致6~9节点在客户环境中出现”未知”的性能问题。
- 当没有性能设计参与的架构,后期出现的性能问题修复难度会越来越大。
- 因为缺乏设计,所以没有目标,没有目标,监控就容易丢失重心。
- 在设计阶段对开发软件的资源占用情况进行研究,得以进一步确认最初性能设计与性能目标的偏差程度。在部署后,监控资源的使用情况,可以在问题出现之前就被发现。
容量规划(Capacity Planning):指一系列事前行动,包括:
- 预测未来资源需求
- 评估当前系统容量
- 规划系统扩展方案
- 定义性能指标和阈值
- 建立性能基线
1.4 视角
图 视角
负载分析(Workload Analysis):从上而下的分析方法,关注系统输入和应用程序响应。
- 分析对象:请求、事务、用户操作
- 关注指标:吞吐量、响应时间、错误率
- 适用场景:应用性能问题诊断
- 典型使用者:系统管理员、运维人员
资源分析(Resource Analysis):从下而上的分析方法,关注系统资源的使用情况。
- 分析对象:CPU、内存、磁盘、网络等资源
- 关注指标:使用率、饱和度、错误
- 适用场景:容量规划、资源瓶颈识别
- 典型使用者:开发人员、性能工程师
1.5 性能是充满挑战的
1.5.1 性能是主观的
- 已经存在的客观事实,在没有明确的期望性能目标时,很难断定其“好”或“坏”。
- 需要方法将性能客观化。
1.5.2 性能是复杂的
- 系统的复杂性,组件的关联。
- 常常缺少一个明确的分析起点。
- 瓶颈往往是复杂的,看似解决了瓶颈,可能只是将瓶颈推向了系统的其他地方,从而导致整体系统性能没有提升。
- 环境很难复现,或只能间歇式重现。
1.5.3 可能多个问题并存
- 成熟的软件,即便是那些被认为拥有高性能的软件,也会有不少已知的但未被修复的性能问题。
- 真正的任务不是寻找问题,而是辨别问题或者说是辨别哪些问题是最重要的。
- 识别“最重要的”,意味着性能分析要对问题的重要程度进行“量化”(quantify)。
- 理想情况:1. 量化问题 2. 估计每个问题修复后带来的增速。
- 延时(latency)这个指标非常适合量化性能。
1.6 延时 Latency
延时(Latency):操作执行之前所花费的等待时间,或操作完成所需的总时间。
- 延时 = 等待时间
- 广义:所有操作完成的等待时间
- 延时可以估计最大增速(maximum speedup)
延时的组成:
- 服务时间:实际处理时间
- 等待时间:排队等待时间
- 传输时间:数据传输时间
最大增速(Maximum Speedup):通过消除延时所能获得的最大性能提升。如果某个操作有50%的时间在等待,理论上最多可以获得2倍的性能提升。
1.7 动态跟踪 dynamic tracing
动态跟踪(Dynamic Tracing):一种运行时性能分析技术,可以在不修改代码的情况下,在任意程序点插入探针(probe)来收集性能数据。
- 动态跟踪可以从任意感兴趣的点测量延时(latency),并且提供数据以显示延时完整的分布情况。
- dynamic tracing 可以把所有软件变得可以监控。
- 可以在真实的生产环境中使用。
- 比”内核分析”更方便的对延时建立测量监控。
Dtrace:由Sun Microsystems开发的动态跟踪框架,对用户态和内核态的软件都提供了静态跟踪和动态跟踪能力。
- 静态跟踪:在编译时插入的探针
- 动态跟踪:在运行时插入的探针
- 支持多种语言:C、C++、Java、Python等
其他动态跟踪工具:
- SystemTap:Linux平台的动态跟踪工具
- eBPF:Linux内核的扩展Berkeley包过滤器,用于动态跟踪
- perf:Linux性能分析工具,支持动态跟踪
1.8 云计算
云计算:通过网络提供计算资源(计算、存储、网络等)的服务模式。
云计算对性能的影响:
- 虚拟化:通过虚拟化技术实现资源抽象,但会带来性能开销
- 快速扩展:弹性扩展成为可能,可以快速响应负载变化
- 容量规划:降低了容量规划的精度要求,可以按需扩展
- 性能分析:性能分析需求要求更高,需要跨虚拟机、跨区域分析
- 性能隔离(Performance Isolation):多租户环境下,租户间的性能隔离带来的性能影响
性能隔离:在多租户环境中,确保一个租户的性能不会受到其他租户的影响。包括:
- CPU隔离:CPU时间片分配
- 内存隔离:内存使用限制
- I/O隔离:磁盘和网络带宽限制
- 噪声邻居问题:其他租户的负载影响
1.9 案例
(待补充具体案例内容)
第2章 方法
2.1 术语
IOPS(Input/Output Operations Per Second):每秒的输入输出次数。对于硬盘,指每秒的读写次数。是数据传输的度量方式,常用于评估存储性能。随机I/O和顺序I/O的IOPS差异很大。
吞吐量(Throughput):
- 数据传输速度(字节/秒或比特/秒)
- 工作执行速率
- 数据库下,指操作的速度(每秒操作数或每秒事务数)
- 与延迟相关:高吞吐量可能意味着高延迟
响应时间(Response Time):一次操作从开始到完成的总时间。包括服务时间和等待时间。
延时(Latency):
- 操作里用来等待服务的时间
- 操作执行之前所花费的时间
- 在某些情况,等同于响应时间
- 是量化性能的重要指标
使用率(Utilization):
- 对于服务所请求的资源,在给定时间区间内资源的繁忙程度
- 基于时间:资源忙碌时间的百分比(U = B/T)
- 基于容量:资源使用量占容量的百分比
- 对于存储资源来说,使用率指的就是所消耗的存储容量(内存使用率)
饱和度(Saturation):
- 某一资源无法满足服务的排队工作量
- 资源过载的程度
- 高饱和度会导致排队和延迟增加
- 是USE方法的关键指标之一
瓶颈(Bottleneck):
- 在系统性能里,瓶颈指的是限制系统性能的那个资源
- 分辨和移除系统瓶颈是系统性能的一项重要工作
- 瓶颈可能是CPU、内存、磁盘I/O、网络等
- 解决一个瓶颈可能暴露另一个瓶颈
工作负载(Workload):
- 系统的输入或者是对系统所施加的负载
- 对于数据库来说,工作负载就是客户端发出的数据库请求和命令
- 工作负载特征包括:请求类型、频率、数据量、访问模式等
- 工作负载分析是性能分析的重要方法
缓存(Cache):
- 用于复制或者缓冲一定量数据的高速存储区域
- 目的是为了避免对较慢的存储层级的直接访问,从而提高性能
- 出于经济考虑,缓存区的容量要比更慢一级的存储容量要小
- 多层缓存:CPU缓存(L1/L2/L3)、内存缓存、磁盘缓存
2.2 模型
这些模型阐述了一些性能基本原则:
2.2.1 受测系统 SUT - System Under Test
受测系统(SUT, System Under Test):在性能测试中,被测试的系统或组件。
图
扰动(Noise):影响测试结果的非目标因素。
扰动会影响结果:
- 扰动来源:
- 定时执行的系统活动(cron任务、系统维护)
- 系统的其他用户
- 其他的工作负载
- 后台进程和服务
- 云环境中的扰动:从单个客户的SUT的视角无法观察到物理宿主系统的其他活动(由其他租户引起的)
- 减少扰动的方法:
- 在专用测试环境中测试
- 多次运行取平均值
- 使用统计方法过滤异常值
2.2.2 排队系统
排队系统(Queuing System):用于建模系统在负载下的行为,特别是当资源达到饱和时的性能表现。
图
排队系统的基本组成:
- 到达过程:请求到达的规律(泊松分布、固定间隔等)
- 服务过程:服务时间的分布(指数分布、固定时间等)
- 服务台数量:并行处理能力
- 队列容量:等待队列的大小
排队系统用于:
- 预测系统在负载下的响应时间
- 分析系统容量和瓶颈
- 优化资源配置
详见 2.6.5 排队论
2.3 重要概念(概括)
概括描述,详细会在其他章节的分析部分。
2.3.1 延时
- 操作执行之前所花费的时间。例如:这个操作用来数据传输,而这个操作执行之前必须先建立连接,这个建立连接的过程就是延时。
- 性能问题可以用延时来进行量化和评级,因为延时都用的是相同的单位来表达。IOPS就不行。
- 通过考量所能减少或移除的延时,预计的加速也可以计算出来。
- 如果是100个网络I/O和50个磁盘I/O做选择,是一个非常复杂的选择,如果是100ms网络I/O,50ms的磁盘I/O就很简单。尝试将其他指标都转为延时或时间,这样更容易比较。
2.3.2 时间量级
用数字来作为时间的比较方法,同时可以用时间的长短经验来判断延时的源头。
| 事件 | 延时 | 相对时间比例 |
|---|---|---|
| 1个CPU周期 | 0.3ns | 1s |
| L1缓存访问 | 0.9ns | 3s |
| L2 | 2.8ns | 9s |
| L3 | 12.9ns | 43S |
| 主存访问(从CPU访问DRAM) | 120ns | 6分 |
| 固态硬盘I/O(闪存) | 50-150μs | 2-6天 |
| 旋转磁盘I/O | 1-10ms | 1-12月 |
| 互联网:从旧金山到纽约 | 40ms | 4年 |
| 互联网:从旧金山到英国 | 81ms | 8年 |
| 互联网:从旧金山到澳大利亚 | 183ms | 19年 |
| TCP包重传 | 1-3s | 105-317年 |
| OS 虚拟化系统重启 | 4s | 423年 |
| SCSI命令超时 | 30s | 3千年 |
| 硬件虚拟化系统重启 | 40s | 4千年 |
| 物理系统重启 | 5m | 32千年 |
CPU循环和延时 参考 第6章,第9章 互联网延时 参考第10章
2.3.3 权衡三角
权衡三角(Trade-off Triangle):性能优化中常见的三个维度之间的权衡关系。
图
常见的权衡关系:
- CPU与内存:
- 内存缓存数据结果,降低CPU的使用
- 在CPU充足的情况下,CPU可以压缩数据来降低内存的使用
- 延迟与吞吐量:
- 批量处理可以提高吞吐量,但会增加延迟
- 实时处理可以降低延迟,但吞吐量可能下降
- 成本与性能:
- 更好的硬件提供更好的性能,但成本更高
- 软件优化可以提升性能,但开发成本增加
文件系统记录尺寸(或块的的大小):小的记录尺寸,接近应用程序I/O大小,随机I/O工作负载会有更好的性能,程序运行的时候能更充分地利用文件系统的缓存。选择大的记录尺寸能提高流的工作负载性能,包括文件系统的备份。
网络缓存尺寸:小的网络缓存尺寸会减小每一个连接的内存开销,有利于系统扩展,大的尺寸能提高网络的吞吐量。
2.3.4 调整的影响
- 性能调整发生在越靠近工作执行的地方效果最显著。
- 应用程序层级的调整,可能通过消去或减少数据查询获得很大的性能提升(例如,20倍)。
- 存储设备层级的调整,可以精简或提高存储I/O,但是性能提升的大头在更高层级的系统栈代码-,所以调整得到的性能提升有限,时百分比量级(例如,20%)
调整事例
| 层级 | 调优对象 |
|---|---|
| 应用程序 | 执行的数据库请求 |
| 数据库 | 数据库表布局、索引、缓冲 |
| 系统调用 | 内存映射、读写、同步或异步I/O 标志 |
| 文件系统 | 记录尺寸、缓存尺寸、文件系统可调参数 |
| 存储 | RAID级别、磁盘类型和数目、存储可调参数 |
- 在应用程序层级的调整效果最显著,但不是观测效果最显著的层级。
- 数据查询慢要从其花费的CPU时间、文件系统和所执行的磁盘I/O方面来考察最好。
- 操作系统的性能分析能辨别出来的不仅是操作系统层级的问题,还有应用程序层级的问题,在某些情况下,甚至要比应用程序视角还简单。
2.3.5 合适的层级
不同的公司和环境对性能有着不同的需求,这取决于性能技术投入的投资回报率(ROI)。 例如:有的公司(纽约交易所与伦敦交易所)会投入3亿美金建立横跨大西洋的光缆,是为了减少6ms的的传输延时。
2.3.6 性能建议的时间点
性能配置不是所有时间点都有效。无法一劳永逸。
2.3.7 负载 vs.架构
图 性能差可能是来自软件配置和硬件,也有可能是架构问题,此外还有可能是太多的负载,而导致了排队和长延时。
2.3.8 扩展性
扩展性(Scalability):系统在负载增加时保持或提升性能的能力。
图 吞吐量 vs.负载
扩展性的三个阶段:
- 理想阶段(线性扩展):
- 扩展性是线性变化的(吞吐量随着负载的增加而增加)
- 资源充足,没有竞争
- 性能随资源扩展成比例增长
- 拐点阶段(非线性扩展):
- 拐点(Knee):性能由于资源限制停止线性增长的点
- 当到达拐点的时候,资源的争夺开始影响性能
- 此时扩展性将无法再保持线性发展,内聚性导致完成的工作变少而且吞吐量也减少了
- 性能增长放缓,但仍能增长
- 饱和点(Saturation Point):
- 当组件使用率达到100%或接近100%时,排队频繁且比较明显
- 性能不再增长,甚至可能下降
- 系统达到容量上限 例如,当程序是一个大量计算的应用程序(负载由线程承担),当cpu接近100%使用率时,延时增大,性能开始下降。当把x轴换成”CPU“,和上图的曲线会一致。
图 性能下降
性能的非线形变化,用平均响应时间或延时来表示。
- 性能”快速”下降可能是由于内存的负载:当系统开始换页(或者使用swap)来补充内存的时候。
- 性能”慢速”下降可能是由于CPU的负载。
- 性能”快速“下降可能是由于磁盘I/O:随着负载(和磁盘使用率)的增加,I/O可能会排队。空闲的旋转的磁盘可能I/O服务响应时间约1ms,但是当负载增加,响应时间会变成10ms。可以查看2.6.5的模型,在M/D/1和60使用率情况下的表现。
如果资源不可用,应用程序开始返回错误,响应时间是线性变化的。例如:web服务器的503,而不是添加请求到排队队列中,这样的服务能用始终如一的响应时间来执行。
2.3.9 已知的未知
- 已知的已知:有些东西你知道。例如:你知道你要检查性能指标,如CPU使用率,并且你也知道当前的均值是10%。
- 已知的未知:有些东西你知道你不知道。例如:你知道你能用profiling检查是什么致使CPU忙碌,但你还没有去做这件事。
- 未知的未知:有些东西你不知道你不知道。举个例子,你可能不知道设备终端可以消耗大量CPU资源,因此你对此并不做检查。
图
性能领域是”你知道的越多,你不知道的也就越多“。和学习系统是一样的原理:你了解的越多,就意识到”未知的未知“就越多,然后这些”未知的未知“就变成了”已知的未知“。
2.3.10 指标
IOPS 度量的是吞吐量,但只针对I/O操作(读取和写入)。
上下文很关键,上下文不同,定义可能会不同。
开销(Overhead):性能指标不是免费的,在某些时间后会消耗一些CPU周期来收集和保存指标信息。对目标的性能会有负面影响,这种影响被称为观察者效应(observer effect)。
观察者效应(Observer Effect):测量行为本身对被测量系统的影响。
- 性能工具会消耗系统资源(CPU、内存、I/O)
- 可能改变系统的执行路径(如添加日志、探针)
- 需要权衡测量精度和系统影响
注意:这与海森堡测不准原理不同,后者描述的是对于互为共轭的物理量所能测量出的精度是有限的(如位置和动量)。(这通常与海森堡测不准原理混淆,后者描述的是对于互为共轭的物理量所能测量出的精度是有限的,诸如位置和动量。)”
问题:我们总是倾向于软件商提供的指标是经过仔细挑选,没有bug,并且具有很好的可见性。但事实上,这些指标可能是混淆的、复杂的、不可靠的、不精确的、甚至是错的(bug导致)。更多参见第4章。
2.3.11 使用率
使用率经常用于系统描述设备的使用情况。 使用率是基于时间或者容量的。 使用率告诉我们组件的忙碌程度。
基于时间
基于时间的使用率是使用排队理论做正式定义的。
例如 Gunther 97 : 服务器或资源繁忙时间的均值,相应的比例公式是 U = B/T U:使用率 T:观测周期 B:T时间内系统的繁忙时间
iostat(1)调用的指标%b,即忙碌百分比,能很好表现 “U=B/T”的本质。
组件A 100%使用率,并且该组件关联的系统性能严重下降,检查该系统的其他组件指标,确认该组件是不是成了整体的性能瓶颈。
有些组件在使用率100%的情况下,性能不会下降的很厉害。比如:能够并行地为操作提供服务的组件。
电梯在载人过程中(100%使用率),依然可以继续接收更多乘客。
100%忙碌的磁盘也能够接受并处理更多的工作,例如,通过把写入的数据放入磁盘内部的缓存中,稍后再完成写入,就能做到这点。通常存储序列运行在100%的使用率是因为其中的某些磁盘在100%忙碌时,序列中依然有足够的空闲磁盘来接受更多的工作。
基于容量
系统或组件(例如硬盘)都能够提供一定数量的吞吐。无论性能处于何种级别,系统或组件都工作在其容量的某一比例上。这个比例就称为使用率。
如果是容量的使用率,硬盘的100%意味不能接受更多工作。 如果是时间的使用率,硬盘的100%意味着时间上的忙碌,但可能接受更多任务。
100%忙碌(时间)不意味着100%的容量使用。
一般来说描述的使用率都是基于时间的。
非空闲时间
如何定义使用率,用上述定义可能会混淆,可尝试使用新词“非空闲时间”,这样描述更精准,但是没有普及。
2.3.12 饱和度
饱和度:随着工作量增加而对资源的请求处理超过资源所能处理的程度。 发生在100%使用率(基于容量)时,无法处理时,将进行排队。
图
当达到100%使用率时,随着负载增加,饱和度线性增加。 出现饱和度,意味着排队等待(延时),即是性能问题。
如果是基于时间的使用率达到100%不意味着会发生饱和度,这取决于资源处理任务的并行能力。
2.3.13 剖析 Profiling
剖析(Profiling):对目标对象的研究和理解。在计算机性能领域,指按照特定的时间间隔对目标(系统状态)进行采样,然后对采样进行研究。
Profiling的类型:
- CPU Profiling:
- 采样CPU执行状态
- 识别热点函数和代码路径
- 工具:perf、gprof、VisualVM
- 内存 Profiling:
- 分析内存分配和释放
- 检测内存泄漏
- 工具:valgrind、MAT、jmap
- I/O Profiling:
- 分析I/O操作
- 识别I/O瓶颈
- 工具:strace、ltrace、blktrace
- 时间 Profiling:
- 测量函数执行时间
- 分析调用栈
- 工具:dtrace、SystemTap
Profiling方法:
- 采样(Sampling):定期采样,开销小但可能遗漏短时间事件
- 插桩(Instrumentation):在代码中插入探针,准确但开销大
- 事件跟踪(Event Tracing):记录所有相关事件,详细但数据量大
2.3.14 缓存
缓存被频繁用来性能提升。 把磁盘的块缓存在主内存(RAM)。 一般使用多层缓存。 CPU 主缓存(L3 < L2 < L1)。L2 和 L3 逐渐增加了容量及延时,这是一种经济上的权衡。
缓存性能重要指标,命中率:
命中率 = 命中次数(hits) / ( hits + 未命中次数(misses))。
图
98%和99%之间的性能差异要比10%和11%之间的性能差异大很多。这取决于缓存的存储层次的速度差异,存储层级速度差异越大,曲线倾斜越陡峭。
缓存另一个指标,失效率:每分钟缓存失效的次数。 缓存失效和性能是线性。
例A: 工作负载A的命中率90%,失效率200/s。 工作负载B的命中率80%,失效率20/s。 哪个性能更好?
工作负载总的运行时间:
运行时间= (命中率 * 命中延时)+(失效率 * 失效延时)
这里用的是平均命中延时和平均未命中延时,并且假定工作是串行发生的。
缓存替换算法
- MRU(Most Recently Used,最近最常使用):保留最新使用的数据,适合访问模式具有时间局部性的场景。
- LRU(Least Recently Used,最近最少使用):淘汰最近最少使用的数据,是最常用的缓存算法,适合大多数场景。
- MFU(Most Frequently Used,最常使用):保留使用频率最高的数据,适合访问模式具有频率特征的场景。
- LFU(Least Frequently Used,最不常使用):淘汰使用频率最低的数据,适合长期热点数据场景。
- NFU(Not Frequently Used,不常使用):LRU的一个简化版本,使用计数器记录访问频率,花费不高但吞吐量稍小。
- FIFO(First In First Out,先进先出):按进入顺序淘汰,实现简单但效果一般。
- Random(随机):随机淘汰,实现最简单但效果最差。
缓存的热、冷和温
缓存的状态:
冷:命中率为0(或接近0,当它开始变暖的时候)。是空的,或填充的是无用数据。 热:命中率超过99%。填充的是常用数据,或有着很高的命中率。 温:填充了有用的数据,但命中率没有达到预想的高度。 热度:缓存的热度或冷度。提高热度的目的就是提高缓存的命中率。
如果缓存较大或下一级的存储较慢(或者两者皆有),会需要一段较长的时间来填充缓存使其变暖。
例如:
- 128GB(DRAM),600GB(闪存)二级缓存,物理磁盘做存储。
- 在随机读的负载下,磁盘 IOPS:2000次读。一次I/O(读):8KB。
- 缓存变暖的速度仅有 16MB/s(2000 * 8KB)。
- 两级缓存从冷开始,需要2小时来让DRAM变温,需要最少10小时让闪存变暖。
- 2.28小时(128 * 1024 / 16 * 60 * 60 )达到 100%
2.4 视角
工作负载:在上而下 资源分析:在下而上
2.4.1 资源分析
- 性能问题研究:看是否某特定类型资源的责任。
- 容量规划:为设计新系统提供信息,或者对系统资源何时会耗尽做预测。
着重使用率的分析,判断资源是否已经处于极限或者接近极限。
适合的资源分析的指标如下:
- IOPS
- 吞吐量
- 使用率
- 饱和度
上述指标在给定负载的情况下,显示了使用程度及饱和程度(上述指标度量了在给定负载下资源所做的事情,显示资源的使用程度乃至饱和的程度)。
其他类型的指标,包括延时,也会被使用,来度量资源于给定工作负载的响应情况。
统计工具:vmstat、iostat、mpstat。
2.4.2 工作负载分析
检查应用程序的性能:所施加的工作负载和应用程序是如何响应的。
图
分析的对象如下:
- 请求:所施加的工作负载
- 延时:应用程序的影响时间
- 完成度:查找错误
适合分析的指标:
- 吞吐量
- 延时
这些指标分别度量了请求量的大小和在其之下系统表现出的性能。
2.5 方法
讹方法(anti-methodologies)
系统性能分析和性能调整方法:
| 类型 | 方法 |
|---|---|
| 观测分析 | 街灯讹 |
| 观测分析 | 科学法 |
| 观测分析 | 工具法 |
| 观测分析 | USE方法 |
| 观测分析 | 向下挖掘分析 |
| 观测分析 | 延时分析 |
| 观测分析 | R方法 |
| 观测分析 | 事件跟踪 |
| 观测分析 | 基础线统计 |
| 实验分析 | 随机变动讹方法 |
| 实验分析 | 微基准测试 |
| 假设分析 | 责怪他人讹方法 |
| 观测与实验分析 | Ad Hoc 核对清单法 |
| 信息收集 | 问题陈述法 |
| 生命周期分析 | 诊断循环 |
| 观测分析,容量规划 | 工作负载特征归纳 |
| 观测分析,容量规划 | 性能监控 |
| 观测分析,容量规划 | 静态性能调整 |
| 统计分析,容量规划 | 排队论 |
| 观测分析,调优 | 缓存调优 |
| 容量规划,调优 | 容量规划 |
2.5.1 街灯讹方法
这个方法用一类观测偏差来命名,这类偏差叫做街灯效应。
一天晚上,一个警察看到一个醉汉在路灯下的地面上找东西,问他在找什么。醉汉回答说他钥匙丢了。警察看了看也找不到,就问他:“你确定你钥匙是在这儿丢的,就在路灯下?”醉汉说:“不,但是这儿的光是最亮的”。
这相当于查看top,不是因为这么做有道理,而是不知道什么使用其他工具。
2.5.2 随机变动讹方法
实验性质的讹方法。
操作:
- 任意选择一个项目做改动(例如,一项可变参数)。
- 朝某个方向做修改。
- 测量性能。
- 朝另一个方向修改。
- 测量性能。
- 步骤3或步骤5的结果是不是要好于基准值?如果是,保留修改并返回步骤1。
此方法非常耗时,而且不一定能长期有效,过程还可能产生更严重的问题。
2.5.3 责怪他人讹方法
步骤:
- 找到一个不是你负责的系统或环境的组件。
- 假定问题是与那个组件相关的。
- 把问题扔给负责那个组件的团队
- 如果证明错了,返回步骤1.
也许是网络问题。你能和网络团队确认一下是不是发生了丢包或其他事情么?
这个讹方法只是因缺乏数据而造成的无端臆想。
2.5.4 Ad Hoc 核对清单法
基于对该系统类型的经验和之前所遇到的问题。
例如:核对清单的一项:“运行iostat -x 1 检查await 列。如果该列在负载下持续超过10(ms),那么说明磁盘太慢或是磁盘过载。”
这类清单能在最短的时间内提供最大的价值,是即时建议而且需要频繁更新以保证反应当前状态。
清单需要写的清楚且规范,说明如何辨别每个问题和如何修复。
2.5.5 问题陈述法
询问客户以下问题来完成:
- 是什么让你认为存在性能问题?
- 系统之前运行得好吗?
- 最近有什么改动?软件?硬件?负载?
- 问题能用延时或者运行时间来表述吗?
- 问题影响其他的人和应用程序吗(或者仅仅影响的是你)?
- 环境是怎么样的?用了哪些软件和硬件?什么版本?什么样的配置?
询问上述问题过程中通常会立即指向一个根源和解决方案。 当遇到一个新的问题,首先应该使用这个方法。
2.5.6 科学法
假设和实验来研究未知问题
步骤:
- 问题
- 假设
- 预测
- 试验
- 分析
2.5.7 诊断循环
与科学法相似: 假设 -> 仪器检验 -> 数据 -> 假设
2.5.8 工具法
工具法是一种系统性的性能分析方法,通过使用各种性能分析工具来收集数据。
步骤:
- 列出可用的性能工具
- 对每个工具运行并收集数据
- 分析工具输出
- 识别性能问题
优点:
- 系统全面
- 可以发现多种问题
缺点:
- 可能收集过多数据
- 需要熟悉多种工具
2.5.9 USE方法
USE方法(Utilization, Saturation, Errors):一种系统性的性能分析方法,针对所有资源检查三个关键指标。
对于所有的资源,查看它的使用率、饱和度和错误。
USE方法的三个维度:
- Utilization(使用率):
- 资源忙碌时间的百分比
- 例如:CPU使用率80%,磁盘使用率60%
- 高使用率可能表示瓶颈
- Saturation(饱和度):
- 资源无法满足服务请求的程度
- 例如:CPU队列长度、磁盘I/O等待队列
- 高饱和度表示资源过载
- Errors(错误):
- 资源发生的错误数量
- 例如:网络丢包、磁盘I/O错误
- 错误可能导致性能下降
USE方法的优势:
- 系统全面:覆盖所有资源
- 快速定位:优先检查USE指标异常的资源
- 易于实施:大多数系统工具都提供这些指标
与工具法相反的是,USE方法列举的是系统资源而不是工具。
2.5.10 工作负载特征归纳
谁?:谁产生,用户ID? 远程IP地址?进程ID? 为什么?:会调用?代码路径、堆栈跟踪? 怎么?:怎么变化的?有规律? 什么?:特征是什么?IOPS?变动(标准方差)?
最好的性能来自消灭不必要的工作。
如果被识别的问题无法解决,那么可以用系统资源控制来限制它。
除了识别问题,工作负载特征归纳可以用于输入仿真基准设计。
通过此方法辨别负载问题,有利于将负载问题和架构问题区分。2.3有介绍。
此方法使用的工具视目标而定。比如:用户活动信息作为统计分析的来源。
2.5.11 向下挖掘分析
从高级指标开始,逐步深入分析,直到找到根本原因。
步骤:
- 从系统级指标开始(如CPU使用率)
- 识别异常的资源
- 深入分析该资源(如CPU -> 进程 -> 线程 -> 函数)
- 找到性能瓶颈
工具链:
- 系统级:vmstat、iostat、mpstat
- 进程级:top、pidstat
- 函数级:perf、dtrace、strace
2.5.12 延时分析
专注于分析操作的延时,识别延时来源。
方法:
- 测量总延时
- 分解延时来源
- 量化各部分延时
- 优化最大延时来源
工具:
- 应用级:APM工具
- 系统级:perf、dtrace
- 网络级:tcpdump、Wireshark
2.5.13 R方法
R方法(R Method):针对Oracle数据库的性能分析方法,由Cary Millsap开发。
R方法的核心思想:
- R代表响应时间(Response Time)
- 关注端到端的响应时间分解
- 识别响应时间的主要组成部分
R方法的步骤:
- 测量总响应时间
- 分解响应时间(CPU时间、等待时间等)
- 识别最大的时间组成部分
- 优化最大的时间组成部分
R方法强调:
- 响应时间比吞吐量更重要
- 需要量化每个组成部分
- 优化应该针对最大的时间组成部分
类似方法可以应用于其他数据库和系统。
2.5.14 事件跟踪
例如:tcpdump
tcpdump -ni eth0 -ttt
-ttt 输出所包含的DELTA时间,测量了包和包之间的时间。
2.5.15 基础线统计
建立性能基准线,用于对比和检测性能回归。
步骤:
- 在正常负载下测量性能指标
- 记录多个时间点的数据
- 建立统计模型(均值、标准差)
- 设置告警阈值
用途:
- 性能回归检测
- 容量规划
- 性能趋势分析
2.5.16 静态性能调整
在系统设计阶段进行性能优化,而不是运行时调整。
方法:
- 选择合适的硬件
- 优化系统配置
- 选择合适的数据结构
- 优化算法
优点:
- 避免运行时开销
- 从根本上解决问题
2.5.17 缓存调优
优化缓存策略以提高命中率和性能。
方法:
- 分析缓存命中率
- 识别热点数据
- 调整缓存大小
- 优化缓存算法(LRU、LFU等)
- 多级缓存策略
指标:
- 命中率
- 失效率
- 缓存大小
- 缓存替换频率
2.5.18 微基准测试
测量的是施加了简单的人造工作负载的性能。
可以用于支持科学方法,将假设和预测放到测试中验证,或者作为容量规划的一部分来执行。
可以用微基准测试工具来测试工作负载并度量性能。
可以用负载生成器来产生负载,用标准的系统工具来测量性能。
最稳妥:微基准测试工具第一轮测试,标准系统工具第二轮测试(确认性能数据)
微基准测试例子:
- 系统调用:针对fork()、exec()、open()、read()、close()。
- 文件系统读取:从缓存过的文件读取,读取数据大小从1B变化到1MB。
- 网络吞吐量:针对不同的socket缓冲区的尺寸测试TCP端对端数据传输。
测量完成大量上述这类操作所要的时间,然后计算均值(平均时间 = 运行时间/操作次数)。
更多详见12章。
2.6 建模 (系统的分析模型)
可扩展性分析:建模可以用以研究当负载或资源扩展时性能会如何变化。可扩展性分析揭示拐点。
拐点:性能由于资源限制停止线性增长的点。
性能评估方法(三大类):
- 生产环境的观测:“测量”。
- 实验性测试:”仿真“。
- 分析建模。
以上三者至少择其二可让性能研究最为透彻。
- 对现有系统:从测量开始,归纳负载特征和测量性能。
- 系统没有生产环境负载/要测试的工作负载在生产环境不可见:工作负载仿真做测试。
详见“工作负载特征归纳”、“微基准测试”。
2.6.1 企业 vs.云
利用云计算技术,任意规模的环境都可以短期租用用于基准测试仿真。
2.6.2 可视化识别
数据可视化可以从其看到规律。
图 X是扩展的维度,Y轴是相应的性能(吞吐量、每秒事务数,等等)。
曲线类型如下:
- 线性扩展:性能随资源扩展成比例增长。这种情况并非永久持续,但这可能是其他扩展情况的早期阶段。
- 竞争:架构的某些组件是共享的,而且只能串行使用,共享资源的竞争会减少资源扩展的收益。
- 一致性:要维持数据的一致性,传播数据变化的代价会超过扩展带来的好处。
- 拐角:某个因素碰到了扩展的制约点,从而改变了扩展的曲线。
- 扩展上限:到达了硬性的极限。极限可能是设备瓶颈。诸如总线或互联器件到了吞吐量的最大值,或者是一个软件设置的限制(系统资源控制)。
2.6.3 Amdahl 扩展定律
该定律主要考虑串行构成的工作负载(不能并行执行)。 该定律可以用于CPU、线程、工作负载等更多事务的扩展性研究。
公式:
C(N) = N / (1 + a(N - 1))
其中:
- C(N):容量
- N:扩展维度,CPU数量或用户负载
- a:串行程度,即偏离线性扩展的程度,0 <= a <= 1
应用步骤:
- 测量或估计串行程度 a
- 计算不同 N 值下的容量 C(N)
- 识别拐点,即性能停止线性增长的点
当 a = 0 时,扩展是线性的;当 a > 0 时,串行部分限制了扩展性。
2.6.4 通用扩展定律
通用扩展定律(Universal Scalability Law, USL)是对Amdahl定律的扩展,考虑了竞争和一致性开销。
公式:
C(N) = N / (1 + σ(N - 1) + λN(N - 1))
其中:
- σ:竞争系数(contention coefficient)
- λ:一致性系数(coherency coefficient)
2.6.5 排队论
排队论(Queuing Theory):数学理论,用于建模系统在负载下的行为,特别是当资源达到饱和时。
排队论模型表示法:A/S/c
- A:到达过程的分布(M=Markovian/泊松分布,D=Deterministic/固定,G=General/一般)
- S:服务时间的分布(同上)
- c:服务器数量
常见模型:
M/M/1 模型:
- 到达过程:泊松分布(Markovian),到达率λ
- 服务时间:指数分布(Markovian),服务率μ
- 服务器数量:1
- 适用场景:单服务器系统,随机到达和随机服务时间
M/D/1 模型:
- 到达过程:泊松分布
- 服务时间:固定(Deterministic)
- 服务器数量:1
- 适用场景:固定服务时间,如固定大小的数据包传输
M/M/c 模型:
- 到达过程:泊松分布
- 服务时间:指数分布
- 服务器数量:c(多个服务器)
- 适用场景:多服务器系统,如负载均衡器后的多个服务器
排队论可以帮助预测:
- 平均等待时间:请求在队列中的平均等待时间
- 队列长度:队列中的平均请求数
- 系统利用率对响应时间的影响:利用率越高,响应时间增长越快
- 系统容量:在给定响应时间要求下的最大负载
重要公式(M/M/1):
- 系统利用率:ρ = λ/μ(必须 < 1)
- 平均队列长度:L = ρ/(1-ρ)
- 平均等待时间:W = L/λ = ρ/(μ(1-ρ))
第3章 性能基准测试
3.1 基准测试概述
基准测试是性能评估的重要方法,用于:
- 比较不同系统或配置的性能
- 验证性能改进
- 容量规划
- 回归测试
3.2 基准测试类型
3.2.1 微基准测试
测量单个操作或小段代码的性能。
特点:
- 简单、快速
- 可能无法反映真实工作负载
- 容易受到编译器优化影响
3.2.2 宏基准测试
测量完整应用程序或系统的性能。
特点:
- 更接近真实场景
- 复杂度高
- 需要更多资源
3.2.3 合成基准测试
使用人工生成的工作负载。
3.2.4 回放基准测试
使用从生产环境捕获的真实工作负载。
3.3 基准测试方法
3.3.1 测试设计
- 明确目标:要测量什么?要比较什么?
- 选择工作负载:代表性、可重复性
- 控制变量:确保公平比较
- 多次运行:减少随机误差
3.3.2 测试执行
- 预热阶段:让系统达到稳定状态
- 测量阶段:收集性能数据
- 冷却阶段:让系统恢复
3.3.3 结果分析
- 统计方法:均值、中位数、百分位数
- 可视化:图表、直方图
- 比较分析:与基准线对比
3.4 基准测试陷阱
- 测试环境不匹配:硬件、软件、配置差异
- 工作负载不真实:无法代表实际使用
- 测量误差:工具开销、系统扰动
- 过早优化:基于不准确的基准测试优化
- 基准测试游戏:针对特定测试优化,实际性能未提升
3.5 基准测试工具
- sysbench:数据库和系统性能测试
- fio:存储I/O性能测试
- iperf:网络性能测试
- SPEC:标准化基准测试套件
- TPC:事务处理性能委员会基准测试
第二部分 系统性能
第4章 操作系统的性能
4.1 CPU性能
4.1.1 CPU架构
-
时钟频率(Clock Frequency):CPU执行指令的速率,单位Hz。频率越高,单核性能越强,但功耗也越高。
- 指令级并行(Instruction-Level Parallelism, ILP):
- 流水线(Pipeline):将指令执行分为多个阶段,不同指令在不同阶段并行执行
- 超标量(Superscalar):每个时钟周期可以执行多条指令
- 乱序执行(Out-of-Order Execution):不按程序顺序执行指令,提高指令级并行度
- 缓存层次(Cache Hierarchy):
- L1缓存:最快,容量最小(通常32KB-64KB),每个核心独享
- L2缓存:较快,容量中等(通常256KB-512KB),每个核心独享
- L3缓存:较慢,容量较大(通常几MB到几十MB),多个核心共享
- 多核架构:
- SMP(Symmetric Multi-Processing):对称多处理,所有CPU核心平等访问内存
- NUMA(Non-Uniform Memory Access):非统一内存访问,不同CPU核心访问不同内存区域的速度不同
4.1.2 CPU性能指标
-
使用率(Utilization):CPU忙碌时间的百分比。100%表示CPU完全忙碌,但可能仍有处理能力(多核、超线程)。
-
饱和度(Saturation):等待CPU的线程数。高饱和度表示CPU过载,线程需要等待。
- 中断(Interrupt):
- 硬件中断:由硬件设备触发(如网卡收到数据包)
- 软件中断:由软件触发(如系统调用)
- 中断处理会消耗CPU时间
- 上下文切换(Context Switch):进程/线程切换时的开销,包括:
- 保存当前进程状态
- 加载新进程状态
- 切换内存地址空间
- 频繁的上下文切换会降低性能
4.1.3 CPU性能分析工具
- top/htop:实时查看CPU使用情况
- vmstat:系统整体统计
- mpstat:多CPU统计
- perf:性能事件分析
- strace:系统调用跟踪
4.1.4 CPU性能优化
- 减少不必要的计算
- 优化算法和数据结构
- 利用CPU缓存
- 减少上下文切换
- 使用CPU亲和性
4.2 内存性能
4.2.1 内存架构
- 虚拟内存(Virtual Memory):
- 为每个进程提供独立的地址空间
- 地址空间大小通常远大于物理内存
- 通过分页机制映射到物理内存
- 物理内存(Physical Memory):
- RAM(Random Access Memory):随机访问内存,速度快但易失
- 交换空间(Swap Space):磁盘上的虚拟内存,速度慢但可持久化
- 内存管理单元(MMU, Memory Management Unit):
- 负责虚拟地址到物理地址的转换
- 管理内存访问权限
- 实现内存保护
- 页面管理:
- 分页(Paging):将虚拟内存划分为固定大小的页面(通常4KB)
- 分段(Segmentation):将内存划分为不同用途的段(代码段、数据段等)
- 现代操作系统主要使用分页机制
4.2.2 内存性能指标
-
使用率(Utilization):已用内存/总内存。高使用率可能导致换页。
- 换页(Paging/Swapping):
- 换出(Swap Out):将内存页面写入交换空间
- 换入(Swap In):从交换空间读取页面到内存
- 换页会显著降低性能(磁盘I/O比内存慢1000倍以上)
- 缺页(Page Fault):
- 软缺页(Minor Page Fault):页面在内存中但未映射,只需更新页表
- 硬缺页(Major Page Fault):页面不在内存中,需要从磁盘读取
- 硬缺页会导致性能下降
- 内存泄漏(Memory Leak):程序分配内存后未释放,导致内存持续增长,最终可能耗尽系统内存。
4.2.3 内存性能分析工具
- free:查看内存使用情况
- vmstat:虚拟内存统计
- sar:系统活动报告
- valgrind:内存分析工具
- pmap:进程内存映射
4.2.4 内存性能优化
- 减少内存分配
- 使用对象池
- 优化数据结构大小
- 减少内存碎片
- 调整交换空间
4.3 文件系统性能
4.3.1 文件系统类型
- ext4(Fourth Extended Filesystem):
- Linux默认文件系统
- 稳定可靠,适合大多数场景
- 最大文件系统大小1EB,最大文件大小16TB
- XFS(X File System):
- 高性能文件系统,适合大文件和高并发
- 支持大文件系统(最大8EB)和大文件(最大8EB)
- 适合数据库、日志等场景
- ZFS(Zettabyte File System):
- 高级文件系统,集成了卷管理功能
- 支持快照、克隆、数据完整性校验
- 适合需要高级功能的场景
- Btrfs(B-Tree File System):
- 现代文件系统,支持写时复制(Copy-on-Write)
- 支持快照、压缩、子卷
- 仍在积极开发中
4.3.2 文件系统性能指标
- IOPS:每秒I/O操作数
- 吞吐量:数据传输速率
- 延迟:I/O响应时间
- 缓存命中率:页面缓存效果
4.3.3 文件系统性能分析工具
- iostat:I/O统计
- iotop:I/O top工具
- lsof:列出打开的文件
- strace:系统调用跟踪
- blktrace:块设备跟踪
4.3.4 文件系统性能优化
- 选择合适的文件系统
- 调整挂载选项
- 优化I/O调度器
- 使用SSD
- 调整页面缓存大小
4.4 进程和线程
4.4.1 进程模型
- 进程:独立的执行单元
- 线程:轻量级进程
- 进程间通信(IPC):管道、信号、共享内存等
4.4.2 调度
- 调度器:决定哪个进程运行
- 优先级:进程优先级
- 时间片:CPU时间分配
- 负载均衡:多核负载分配
4.4.3 性能分析
- ps:查看进程
- top:实时进程监控
- pidstat:进程统计
- strace:系统调用跟踪
第5章 存储系统的性能
5.1 存储架构
5.1.1 存储层次
- CPU缓存:最快,容量最小
- 主内存(RAM):快速,易失性
- 固态硬盘(SSD):快速,非易失性
- 机械硬盘(HDD):较慢,非易失性
- 网络存储:远程访问
5.1.2 存储类型
- DAS(Direct Attached Storage,直连存储):
- 存储设备直接连接到服务器
- 访问速度快,但扩展性差
- 适合单服务器场景
- NAS(Network Attached Storage,网络附加存储):
- 通过网络(通常是以太网)提供文件级存储
- 使用NFS、CIFS等协议
- 易于管理和扩展
- 适合文件共享场景
- SAN(Storage Area Network,存储区域网络):
- 通过网络(通常是光纤通道)提供块级存储
- 高性能、低延迟
- 适合数据库、虚拟化等高性能场景
- 对象存储(Object Storage):
- 以对象为单位存储数据,通过RESTful API访问
- 高可扩展性、高可用性
- 适合云存储、大数据、归档等场景
- 典型产品:AWS S3、Azure Blob Storage
5.2 磁盘I/O性能
5.2.1 磁盘性能指标
- IOPS:每秒I/O操作数
- 吞吐量:数据传输速率(MB/s)
- 延迟:I/O响应时间
- 队列深度:待处理I/O数量
5.2.2 磁盘类型
- HDD:机械硬盘,随机I/O较慢
- SSD:固态硬盘,随机I/O快
- NVMe:高速SSD接口
5.2.3 RAID
RAID(Redundant Array of Independent Disks):独立磁盘冗余阵列,通过多个磁盘组合提供更高的性能或可靠性。
RAID级别:
- RAID 0(条带化):
- 数据分散存储在多个磁盘
- 性能最高(并行读写),无冗余
- 任一磁盘故障会导致数据丢失
- 适合对性能要求高、数据可重建的场景
- RAID 1(镜像):
- 数据完全复制到多个磁盘
- 冗余高,任一磁盘故障不影响数据
- 性能中等,写入需要同步到所有磁盘
- 适合对可靠性要求高的场景
- RAID 5(分布式奇偶校验):
- 数据和奇偶校验信息分布在所有磁盘
- 可容忍一个磁盘故障
- 读写性能较好,但写入需要计算奇偶校验
- 适合平衡性能和可靠性的场景
- RAID 10(RAID 1+0):
- 先做镜像(RAID 1),再做条带化(RAID 0)
- 性能好,冗余高
- 可容忍多个磁盘故障(只要不是同一镜像对)
- 适合对性能和可靠性都要求高的场景
- 其他RAID级别:
- RAID 6:类似RAID 5,但可容忍两个磁盘故障
- RAID 50/60:RAID 5/6的条带化组合
5.3 存储性能分析
5.3.1 工具
- iostat:I/O统计
- iotop:I/O top
- blktrace:块设备跟踪
- fio:I/O基准测试
5.3.2 分析方法
- USE方法:使用率、饱和度、错误
- 工作负载特征:随机/顺序、读/写比例
- 延迟分析:I/O延迟分布
5.4 存储性能优化
5.4.1 硬件优化
- 使用SSD替代HDD
- 增加磁盘数量(RAID)
- 使用高速接口(NVMe)
5.4.2 软件优化
- 调整I/O调度器
- 使用异步I/O
- 批量I/O操作
- 预读和预写
- 数据压缩
5.4.3 应用优化
- 减少I/O操作
- 批量处理
- 缓存常用数据
- 优化数据结构
第6章 网络性能
6.1 网络架构
6.1.1 网络层次
- 物理层:物理连接
- 数据链路层:帧传输
- 网络层:IP路由
- 传输层:TCP/UDP
- 应用层:应用程序协议
6.1.2 网络设备
- 网卡(NIC):网络接口
- 交换机:数据包转发
- 路由器:路由选择
- 负载均衡器:流量分发
6.2 网络性能指标
6.2.1 带宽
- 带宽:最大数据传输速率
- 吞吐量:实际数据传输速率
- 利用率:带宽使用百分比
6.2.2 延迟
- RTT(Round-Trip Time,往返时间):
- 数据包从发送到接收确认的总时间
- 包括:发送时间 + 传播时间 + 处理时间 + 返回时间
- 常用工具:ping命令测量RTT
- 单向延迟(One-Way Latency):
- 数据包单程传输时间
- 需要时钟同步才能准确测量
- 比RTT更精确,但测量更复杂
- 抖动(Jitter):
- 延迟的变化程度
- 计算方式:连续数据包延迟的方差或标准差
- 高抖动会影响实时应用(如视频、语音)
6.2.3 其他指标
- 丢包率:丢失数据包比例
- 错误率:错误数据包比例
- 连接数:并发连接数
6.3 网络性能分析
6.3.1 工具
- ping:测试连通性和延迟
- traceroute:路由跟踪
- tcpdump:数据包捕获
- Wireshark:协议分析
- iperf:带宽测试
- netstat/ss:网络连接统计
- iftop:网络流量监控
6.3.2 分析方法
- 延迟分析:测量RTT和单向延迟
- 吞吐量分析:测量实际带宽
- 协议分析:分析TCP/UDP行为
- 流量分析:分析数据流特征
6.4 TCP性能
6.4.1 TCP特性
- 可靠传输(Reliable Delivery):
- 通过确认机制保证数据到达
- 丢失的数据包会重传
- 保证数据顺序
- 流量控制(Flow Control):
- 使用滑动窗口机制
- 接收方通过窗口大小控制发送方速率
- 防止接收方缓冲区溢出
- 拥塞控制(Congestion Control):
- 慢启动(Slow Start):连接开始时指数增长窗口
- 拥塞避免(Congestion Avoidance):检测到拥塞后线性增长窗口
- 快速重传(Fast Retransmit):收到3个重复ACK立即重传
- 快速恢复(Fast Recovery):快速重传后的恢复机制
- 连接管理:
- 三次握手(Three-Way Handshake):建立连接(SYN、SYN-ACK、ACK)
- 四次挥手(Four-Way Handshake):关闭连接(FIN、ACK、FIN、ACK)
6.4.2 TCP性能优化
- 调整缓冲区大小:TCP窗口大小
- 启用TCP优化选项:TCP_NODELAY、TCP_CORK
- 使用连接池:复用连接
- 批量传输:减少小包传输
6.5 网络性能优化
6.5.1 硬件优化
- 使用高速网卡(10GbE、25GbE)
- 网络设备升级
- 减少网络跳数
6.5.2 软件优化
- 调整内核参数
- 使用高效协议(HTTP/2、QUIC)
- 数据压缩
- CDN加速
6.5.3 应用优化
- 减少网络往返
- 批量请求
- 使用缓存
- 异步I/O
第三部分 企业应用性能
第7章 企业应用性能基础
7.1 应用性能概述
企业应用性能涉及多个层面:
- 应用程序代码
- 运行时环境(JVM、.NET等)
- 数据库
- Web服务器
- 操作系统
7.2 性能分析方法
7.2.1 应用性能监控(APM)
- 代码级分析:函数调用、执行时间
- 事务跟踪:端到端请求跟踪
- 依赖分析:外部服务依赖
7.2.2 性能分析工具
- Profiler:代码性能分析
- APM工具:应用性能监控
- 日志分析:分析应用日志
- 指标收集:性能指标收集
7.3 常见性能问题
7.3.1 CPU问题
- 算法效率低
- 不必要的计算
- 锁竞争
7.3.2 内存问题
- 内存泄漏
- 内存溢出
- 频繁GC
7.3.3 I/O问题
- 同步I/O阻塞
- 数据库查询慢
- 文件I/O慢
7.3.4 网络问题
- 网络延迟高
- 网络带宽不足
- 连接数过多
7.4 性能优化策略
7.4.1 代码优化
- 算法优化
- 数据结构优化
- 减少对象创建
- 避免不必要的计算
7.4.2 架构优化
- 缓存策略
- 异步处理
- 负载均衡
- 数据库优化
7.4.3 配置优化
- JVM参数调优
- 数据库配置
- Web服务器配置
- 操作系统配置
第8章 Java虚拟机性能
8.1 JVM架构
8.1.1 内存模型
- 堆(Heap):对象存储
- 新生代(Young Generation)
- 老年代(Old Generation)
- 方法区(Metaspace):类元数据
- 栈(Stack):线程栈
- 程序计数器:指令位置
8.1.2 垃圾回收
垃圾回收(Garbage Collection, GC):自动管理内存的机制,自动回收不再使用的对象。
垃圾回收算法:
- 标记-清除(Mark-Sweep):
- 标记所有可达对象
- 清除未标记的对象
- 会产生内存碎片
- 标记-复制(Mark-Copy):
- 将存活对象复制到新空间
- 适合新生代,回收效率高
- 需要额外的内存空间
- 标记-整理(Mark-Compact):
- 标记存活对象后,移动对象消除碎片
- 适合老年代
- 回收效率较低但无碎片
- 分代回收(Generational Collection):
- 基于对象生命周期假设:大多数对象很快死亡
- 新生代(Young Generation):新创建的对象,使用标记-复制
- 老年代(Old Generation):长期存活的对象,使用标记-整理
- 不同代使用不同的回收策略和频率
8.2 垃圾回收器
8.2.1 串行回收器
- Serial GC:单线程,适合小应用
- Serial Old GC:老年代串行回收
8.2.2 并行回收器
- Parallel GC:多线程并行回收
- Parallel Old GC:老年代并行回收
8.2.3 并发回收器
- CMS(Concurrent Mark Sweep):
- 并发标记清除,减少停顿时间
- 适合对延迟敏感的应用
- 会产生内存碎片,可能触发Full GC
- G1(Garbage First):
- 分代收集器,将堆划分为多个区域
- 优先回收垃圾最多的区域
- 可预测的停顿时间
- 适合大堆内存(>4GB)
- ZGC(Z Garbage Collector):
- 低延迟回收器,停顿时间<10ms
- 支持TB级堆内存
- 并发标记、并发整理
- 适合对延迟要求极高的应用
- Shenandoah:
- 低延迟回收器,停顿时间与堆大小无关
- 并发整理,减少停顿时间
- 适合大堆内存和低延迟需求
8.3 JVM性能指标
8.3.1 内存指标
- 堆使用率:堆内存使用百分比
- GC频率:垃圾回收频率
- GC时间:垃圾回收耗时
- 对象分配率:对象创建速率
8.3.2 CPU指标
- CPU使用率:JVM进程CPU使用
- 线程数:活跃线程数
- 锁竞争:锁等待时间
8.4 JVM性能分析工具
8.4.1 命令行工具
- jps:查看Java进程
- jstat:JVM统计信息
- jmap:堆内存分析
- jstack:线程堆栈分析
- jinfo:JVM配置信息
8.4.2 可视化工具
- jconsole:JVM监控
- VisualVM:性能分析
- JProfiler:商业分析工具
- MAT:内存分析工具
8.4.3 性能分析
- GC日志分析:分析垃圾回收行为
- 线程转储分析:分析线程状态
- 堆转储分析:分析内存使用
8.5 JVM性能优化
8.5.1 内存优化
- 调整堆大小(-Xms, -Xmx)
- 调整新生代大小(-Xmn)
- 选择合适的GC算法
- 优化对象生命周期
8.5.2 GC优化
- 减少GC频率
- 减少GC时间
- 避免Full GC
- 调整GC参数
8.5.3 代码优化
- 减少对象创建
- 使用对象池
- 优化字符串操作
- 避免不必要的同步
第9章 数据库性能
9.1 数据库架构
9.1.1 存储引擎
- InnoDB:MySQL默认引擎,支持事务
- MyISAM:MySQL旧引擎,不支持事务
- PostgreSQL:对象关系数据库
- MongoDB:文档数据库
9.1.2 索引
索引(Index):数据结构,用于快速定位数据,类似于书籍的目录。
索引类型:
- B树索引(B-Tree Index):
- 平衡树结构,支持范围查询
- 适合大多数场景,MySQL InnoDB默认索引类型
- 查询时间复杂度:O(log n)
- 哈希索引(Hash Index):
- 使用哈希表,支持等值查询
- 查询速度快,但不支持范围查询
- 适合等值查询频繁的场景
- 全文索引(Full-Text Index):
- 用于文本搜索
- 支持关键词搜索、模糊匹配
- 适合搜索引擎、内容管理系统
- 复合索引(Composite Index):
- 多列索引,按列顺序组织
- 支持多列查询和前缀匹配
- 需要注意列顺序,影响索引效果
- 其他索引类型:
- 位图索引(Bitmap Index):适合低基数列
- R树索引(R-Tree Index):用于空间数据
- 倒排索引(Inverted Index):用于全文搜索
9.2 数据库性能指标
9.2.1 查询性能
- 查询响应时间:查询执行时间
- QPS:每秒查询数
- TPS:每秒事务数
- 慢查询:执行时间长的查询
9.2.2 资源使用
- CPU使用率:数据库进程CPU使用
- 内存使用率:缓冲池使用
- I/O使用率:磁盘I/O
- 连接数:数据库连接数
9.3 数据库性能分析
9.3.1 查询分析
- EXPLAIN:查询执行计划
- 慢查询日志:记录慢查询
- 性能模式:MySQL性能监控
- pg_stat_statements:PostgreSQL查询统计
9.3.2 监控工具
- MySQL Workbench:MySQL管理工具
- pgAdmin:PostgreSQL管理工具
- Prometheus + Grafana:监控可视化
- Percona Toolkit:MySQL工具集
9.4 数据库性能优化
9.4.1 查询优化
- 使用索引
- 优化SQL语句
- 避免全表扫描
- 使用连接池
- 批量操作
9.4.2 索引优化
- 创建合适的索引
- 避免过多索引
- 使用复合索引
- 定期维护索引
9.4.3 配置优化
- 调整缓冲池大小
- 调整连接数
- 优化查询缓存
- 调整日志设置
9.4.4 架构优化
- 读写分离
- 分库分表
- 缓存策略
- 异步处理
第10章 Web应用程序性能
10.1 Web架构
10.1.1 典型架构
- 前端:浏览器、CDN
- Web服务器:Nginx、Apache
- 应用服务器:Tomcat、Jetty
- 数据库:MySQL、PostgreSQL
- 缓存:Redis、Memcached
10.1.2 HTTP协议
- HTTP/1.1:
- 传统协议,广泛使用
- 每个连接只能处理一个请求-响应
- 支持持久连接(Keep-Alive)
- 头部未压缩,开销较大
- HTTP/2:
- 多路复用(Multiplexing):单个连接可以并行处理多个请求
- 头部压缩(Header Compression):使用HPACK算法压缩头部
- 服务器推送(Server Push):服务器可以主动推送资源
- 二进制分帧(Binary Framing):使用二进制格式,更高效
- 显著提升性能,特别是高延迟网络
- HTTPS(HTTP Secure):
- HTTP over TLS/SSL
- 提供加密和身份验证
- 性能开销:TLS握手、加密解密
- 现代Web应用的标准
- WebSocket:
- 全双工通信协议
- 建立连接后可以双向实时通信
- 适合实时应用(聊天、游戏、监控等)
- 比HTTP轮询更高效
10.2 Web性能指标
10.2.1 前端指标
- 页面加载时间:页面完全加载时间
- 首屏时间:首屏内容显示时间
- DOM Ready:DOM就绪时间
- 资源加载时间:CSS、JS加载时间
10.2.2 后端指标
- 响应时间:服务器响应时间
- 吞吐量:每秒请求数
- 错误率:错误请求比例
- 并发数:同时处理的请求数
10.3 Web性能分析
10.3.1 前端分析
- Chrome DevTools:浏览器开发工具
- Lighthouse:性能审计
- WebPageTest:在线性能测试
- RUM:真实用户监控
10.3.2 后端分析
- APM工具:应用性能监控
- 日志分析:分析访问日志
- 性能测试:负载测试工具
10.4 Web性能优化
10.4.1 前端优化
- 资源优化:压缩、合并、CDN
- 代码优化:减少DOM操作、事件委托
- 图片优化:压缩、懒加载、WebP
- 缓存策略:浏览器缓存、HTTP缓存
10.4.2 后端优化
- 代码优化:减少计算、异步处理
- 数据库优化:查询优化、索引
- 缓存策略:应用缓存、数据库缓存
- 负载均衡:分发请求
10.4.3 网络优化
- HTTP/2:使用新协议
- CDN:内容分发网络
- 压缩:Gzip、Brotli
- 连接复用:Keep-Alive
第四部分 云计算性能
第11章 云计算的性能挑战
11.1 云计算特性
11.1.1 虚拟化
- 虚拟机:完整操作系统虚拟化
- 容器:轻量级虚拟化
- 虚拟化开销:CPU、内存、I/O开销
11.1.2 多租户
多租户(Multi-Tenancy):多个租户(客户或应用)共享同一物理资源。
多租户的特点:
- 资源共享:CPU、内存、网络共享,提高资源利用率
- 性能隔离(Performance Isolation):
- 租户间性能隔离,确保一个租户不影响其他租户
- 通过资源限制(CPU配额、内存限制、I/O限制)实现
- 噪声邻居(Noisy Neighbor):
- 其他租户的负载影响当前租户的性能
- 即使有资源限制,仍可能受到间接影响(如缓存竞争、网络拥塞)
- 需要监控和告警机制
11.1.3 弹性扩展
- 水平扩展:增加实例数量
- 垂直扩展:增加实例规格
- 自动扩展:根据负载自动调整
11.2 性能挑战
11.2.1 虚拟化开销
- CPU虚拟化开销
- 内存虚拟化开销
- I/O虚拟化开销
- 网络虚拟化开销
11.2.2 性能隔离
- CPU调度影响
- 内存竞争
- I/O带宽竞争
- 网络带宽竞争
11.2.3 网络延迟
- 虚拟网络延迟
- 跨区域延迟
- 网络拥塞
11.2.4 存储性能
- 网络存储延迟
- 存储带宽限制
- 存储IOPS限制
11.3 性能分析方法
11.3.1 监控
- 云监控服务:AWS CloudWatch、Azure Monitor
- APM工具:应用性能监控
- 基础设施监控:Prometheus、Grafana
11.3.2 基准测试
- 云环境基准测试
- 性能对比测试
- 容量规划测试
第12章 云服务的性能分析
12.1 云服务类型
12.1.1 计算服务
- EC2/VM:虚拟机服务
- Lambda/Functions:无服务器计算
- 容器服务:Kubernetes、ECS
12.1.2 存储服务
- 对象存储:S3、Blob Storage
- 块存储:EBS、Azure Disk
- 文件存储:EFS、Azure Files
12.1.3 数据库服务
- 关系数据库:RDS、Azure SQL
- NoSQL数据库:DynamoDB、Cosmos DB
- 缓存服务:ElastiCache、Azure Cache
12.2 性能分析工具
12.2.1 云平台工具
- CloudWatch:AWS监控
- Azure Monitor:Azure监控
- Stackdriver:GCP监控
12.2.2 第三方工具
- Datadog:基础设施监控
- New Relic:APM工具
- Dynatrace:全栈监控
12.3 性能优化策略
12.3.1 实例选择
- 选择合适的实例类型
- 考虑CPU、内存、网络需求
- 使用预留实例降低成本
12.3.2 架构优化
- 使用CDN加速
- 多区域部署
- 负载均衡
- 自动扩展
第13章 云应用程序性能
13.1 云原生应用
13.1.1 微服务架构
- 服务拆分:按业务拆分服务
- 服务通信:REST、gRPC、消息队列
- 服务发现:服务注册与发现
- 配置管理:集中配置管理
13.1.2 容器化
- Docker:容器化技术
- Kubernetes:容器编排
- 容器优化:镜像大小、启动时间
13.1.3 无服务器
无服务器(Serverless):一种计算模型,开发者无需管理服务器,云平台自动管理资源分配和扩展。
- 函数即服务(FaaS, Function as a Service):
- 以函数为单位部署和执行代码
- 按执行次数和时长计费
- 典型产品:AWS Lambda、Azure Functions、Google Cloud Functions
- 适合事件驱动、微服务、API后端等场景
- 事件驱动(Event-Driven):
- 函数由事件触发执行(HTTP请求、消息队列、定时任务等)
- 自动扩展,无需预配置容量
- 按需执行,空闲时无成本
- 冷启动(Cold Start):
- 函数首次调用或长时间未调用后的启动延迟
- 包括:容器启动、运行时初始化、代码加载
- 可能影响延迟敏感的应用
- 优化方法:预热、使用预留并发、减少依赖
13.2 性能优化
13.2.1 应用优化
- 代码优化
- 依赖优化
- 缓存策略
- 异步处理
13.2.2 基础设施优化
- 选择合适的服务
- 优化网络配置
- 使用缓存服务
- 数据库优化
第五部分 性能优化
第14章 系统和应用程序性能优化
14.1 优化方法论
14.1.1 优化流程
- 问题识别:识别性能瓶颈
- 量化分析:测量和量化问题
- 优化方案:制定优化策略
- 实施优化:执行优化措施
- 验证效果:验证优化效果
- 持续监控:持续监控性能
14.1.2 优化原则
- 先测量,后优化:基于数据优化
- 优化热点:优先优化影响大的部分
- 权衡考虑:考虑成本、复杂度
- 避免过度优化:保持代码可维护性
14.2 系统级优化
14.2.1 操作系统优化
- 内核参数调优
- 文件系统优化
- 网络参数优化
- 进程调度优化
14.2.2 硬件优化
- CPU选择:核心数、频率
- 内存配置:容量、速度
- 存储选择:SSD、NVMe
- 网络配置:高速网卡
14.3 应用级优化
14.3.1 代码优化
- 算法优化
- 数据结构优化
- 减少对象创建
- 避免不必要的计算
14.3.2 架构优化
- 缓存策略
- 异步处理
- 负载均衡
- 数据库优化
14.4 优化案例
(待补充具体优化案例)
第15章 云环境中的性能优化
15.1 云环境特性
15.1.1 弹性扩展
- 自动扩展:根据负载自动调整
- 预测扩展:基于历史数据预测
- 成本优化:平衡性能和成本
15.1.2 多区域部署
- 地理分布:多区域部署
- 延迟优化:就近访问
- 容灾备份:高可用性
15.2 云优化策略
15.2.1 实例优化
- 选择合适的实例类型
- 使用预留实例
- Spot实例使用
- 实例大小调整
15.2.2 网络优化
- 使用CDN
- 多区域部署
- 私有网络
- 网络加速
15.2.3 存储优化
- 选择合适的存储类型
- 使用缓存
- 数据压缩
- 存储分层
15.3 成本优化
15.3.1 资源优化
- 资源利用率优化
- 闲置资源清理
- 预留实例使用
- Spot实例使用
15.3.2 架构优化
- 无服务器架构
- 容器化部署
- 微服务架构
- 事件驱动架构
总结
《性能之巅》提供了系统性能分析的全面方法论,从基础概念到具体实践,涵盖了:
- 性能分析方法:USE方法、工作负载分析、延时分析等
- 系统性能:CPU、内存、存储、网络性能分析
- 应用性能:JVM、数据库、Web应用性能优化
- 云性能:云计算环境下的性能挑战和优化
关键要点:
- 性能分析需要系统性的方法
- 测量是优化的基础
- 延时是量化性能的重要指标
- 不同层级需要不同的优化策略
- 云环境带来新的性能挑战和机遇
通过系统性的性能分析和优化,可以显著提升系统性能,改善用户体验。