Reading Notes - System Performance
# Introduction
系统性能 (system performance) 指的是整个计算机系统的性能,涵盖了系统中所有的软件和硬件:从存储设备到操作系统内核、再到上层的应用软件,所有会影响性能的组件都在考虑的范围之内。
对于分布式系统来说,这意味着复数的服务器和应用程序都在考虑的范围之内。
定义 全栈 (full stack) 为从应用程序到金属硬件的整个软件栈,那么全栈就是系统性能的研究范围。
性能分析的两个 视角 (perspective) 从不同的方向遍历软件堆栈,二者具有不同的优点且互补:
资源分析的视角 (resource analysis perspective) 通常由对系统资源负责的系统管理员使用,
负载分析的视角 (workload analysis perspective) 通常由对交付的 workload 的性能负责的应用程序开发者使用。
# Performance is Challenging
性能工程是一个具有挑战性的领域,这是多方面的原因所致,包括主观性、复杂性、root cause 的非单一性,并且(?)经常会涉及多个问题。
# Subjectivity
对于通常的软件测试和故障排除而言,结果往往是非黑即白的,例如 BUG 存在或不存在、已修复或未修复,其存在很容易被解释和理解。
对于性能问题而言,结果往往是 主观的 (subjective) ,例如可能不清楚是否从一开始就存在问题,如果有问题也可能不知道何时修复。另一方面,被一个用户认为是“差”性能的东西,可能会被另一个用户认为是“好”性能的体现。
- 考虑一条信息:磁盘 I/O 的平均响应时间为 1 ms ,这是“好”还是“坏”?这取决于应用程序开发者和下游用户的性能预期。
定义明确的目标可以使主观变得客观,例如提出目标平均响应时间,或要求一定百分比的请求的时延在某个预设范围之内。
# Complexity
性能的复杂性源于多个方面。
其一,大型系统本身就具有复杂性,以及可能缺少一个明显的分析起点。性能分析师可能要从假设开始,尝试分析各个软硬件组件的性能,并判断是否走上了正确的方向。
- 对于云计算环境,可能甚至不知道要先查看哪个服务器实例,需要假设是网络或数据库存在性能问题。
其二,性能问题可能源于子系统之间的复杂交互。即便每个子系统在单独的性能分析中都表现良好,当它们协同工作时,可能某个组件中的故障会间接导致其它组件产生性能问题,这被称为 级联故障 (cascading failure) 。为此,性能分析师必须理清各个组件之间的关系,并了解每个组件对系统整体的 contribution 。
其三,性能瓶颈本身就具有复杂性,可能以意想不到的方式相关。修复性能瓶颈可能只会将其转移到系统的其他位置,而并没有像期望的那样提高系统的整体性能。
其四,性能问题可能源于生产环境下 workload 的复杂特性,导致性能问题在实验环境下无法重现,或是间歇性重现。
# Multiple Causes and Issues
一方面,一个性能问题可能有不止一个 root cause ,甚至这些因素独立起来都不会导致性能问题;另一方面,系统中可能同时存在多个性能问题。
发现性能问题未必是困难的,复杂软件系统中通常存在大量已知但尚未修复的性能问题。事实上,真正的困难不是发现问题,而且确定哪些问题是最重要的:性能分析师必须 量化 (quantify) 问题的严重程度,甚至是估算每个问题的修复能带来的加速程度。
- 某些性能问题可能仅与特定的 workload 有关,或是仅适用于(?or apply to a very small degree)。
# Terminology for Tools
对应地,观察性工具 (observability tools) 指的是通过观察来理解系统的工具,这包括使用 counter / profiling / tracing 的工具。
实验性工具 (experimental tool) 指的是在系统上执行 workload 并测量其性能的工具。使用实验性工具需要谨慎,因为它们的存在本身会干扰被测系统的性能。
观察 (observability) 和 实验 (experimentation) 是性能工具的两只手,只使用其中一种是不明智的。
在生产环境下,应当尽可能先尝试使用观察性工具,因为实验性工具可能会因为资源争用而扰乱 workload 。在实验环境下,可能更多地会先使用实验性工具来确定硬件性能。
# Observability
术语 counters, staticstics, metrics 通常可以互换使用。
计数器 (counters) 指的是应用程序和内核记录为整数计数器的、有关其状态和活动的累积型数据,例如 operation counts, byte counts, latency measurements, resource utilization, error rates 等等。
性能工具可以在不同的时间读取计数器以计算 统计数据 (staticstics) ,例如随时间的变化率、平均值、百分比等等。
度量 (metrics) 指的是已用于评估或监控目标的统计数据。
profiling 通常指的是使用工具进行 采样 (sampling) 以绘制目标的“缩略图”,例如 火焰图 (flame graph) 。
tracing 是基于事件的记录,即在系统运行时捕获并存储事件数据,以用于后续分析工作,或即时使用以获取 custom summaries 。
tracing 工具使用各种事件源,特别是静态和动态插桩,以及用于实现可编程性的 BPF 。
静态插桩 (static instrumentation) 描述了硬编码到源代码中的 检测点 (instrument point) 。
用于内核静态插桩的技术被称为 tracing point 。Linux 内核中有数百个这样的检测点,用于检测磁盘 I/O 、scheduler events 、系统调用等。
用于 user-space 静态插桩的技术被称为 (user statically defined tracing, USDT) 。USDT 被诸如 libc 的库用于检测库函数调用,并被许多应用程序用于检测 service requests 。
动态插桩 (dynamic instrumentation) 在软件开始运行后通过修改内存中的指令来插入检测点。
- 动态插桩有些类似于调试器打断点:当断点被命中时,调试器将执行流传递给交互式调试器,而动态插桩执行 instrument routine 后继续执行目标程序。
# Experimentation
大部分实验性工具都是 基准测试工具 (benchmarking tools) 。
macro-benchmark tools 可以模拟真实事件的 workload ,例如客户端发起应用程序请求。
micro-benchmark tools 可以独立测试特定组件,例如 CPU 、磁盘或网络。micro-benchmark 通常更易于调试、理解和重现,并且更稳定。
打个比方,一辆赛车在赛道上的单圈时间可以被认为是一个 macro-benchmark ,而其最高时速 60 英里每小时可以被认为是一个 micro-benchmark 。
两种 benchmark 都很重要。
# Basics
# Terminology
以下列举了系统性能的关键术语。
IOPS (I/O operations per second) 是数据传输操作的速率的度量。对于磁盘 I/O ,IOPS 是指每秒磁盘读写的次数。
吞吐量 (throughput) 是执行工作的速率。在通信中,吞吐量用于指代 data rate ,即 byte per second 或 bit per second 。在某些情况下,吞吐量也可以用于指代 operation rate ,即 operations per second 或 transactions per second 。
响应时间 (response time) 是整个操作完成的时间,这包括任何用于等待服务的时间、被服务花费的时间 (service time) 、以及传输结果花费的时间。
时延 (latency) 是衡量操作用于等待服务的时间,即在执行操作之前等待的时间。在某些情况下也用于表示整个操作完成的时间(相当于响应事件)。
利用率 (utilization) 是衡量资源繁忙程度的指标。考虑服务请求资源,利用率就是在给定时间间隔内资源被用于执行工作的时间比率。对于存储资源,利用率可以是消耗的容量(例如内存利用率)。
饱和度 (saturation) 是资源排队工作因而无法提供服务的程度。
瓶颈 (bottleneck) 是限制系统性能的资源。识别和消除瓶颈是系统性能工作的关键。
工作负载 (workload) 是系统的输入或应用于系统的负载。对于数据库,workload 由客户端发送的数据库查询和命令组成。
# Modeling
以下简单模型说明了系统性能的一些基本原理。
TBD.
# Concepts
# Latency
时延 (latency) 是衡量等待时间的性能指标,是一项非常重要并且被广泛使用的性能指标。它可以用于表示任何操作完成的时间,例如应用程序请求、数据库查询、文件系统操作,网页完全加载的耗时(从点击链接到网页绘制完成)等。
时延可以用于量化性能问题,以及用于估算最大加速。
- 对于一个需要 100 ms 的数据库查询操作,假设操作期间花费 80 ms 阻塞等待磁盘读,那么可以计算出理想最大加速为 5x 。
并非每个指标都具有量化的能力。例如 每秒 I/O 操作 (I/O operations per second, IOPS) ,其数值量化取决于 I/O 的类型,通常无法进行比较,并且很难直接确定其数值升降对性能的影响。
- 如果一个改变是将 IOPS 比率降低 80% ,看似速度下降了 5x ,但是如果每次 I/O 的数据库大小都增加了 10x 呢?
如果没有限定术语,延迟可能会成为一个模棱两可的指标。
- 在网络中,延迟可能是指建立连接的时间,也可能是指数据传输的时间,或是连接的总持续时间。
# Time Scales
不同的系统组件在非常不同的 time scales 下运行,可能会相差几个数量级,很难掌握这其中的差异。
下表是展示系统组件之间 time scales 的差异的一个示例,并将单个 CPU 周期从 0.3 ns 放大到现实生活尺度的 1 s 以助于理解。
Event | Latency | Scaled |
---|---|---|
1 CPU cycle | 0.3 ns | 1 s |
# Trade-Offs
IT 项目开发的 good / fast / cheap 三选二 trade-off 三角形如下图所示。在系统性能的上下文中,good / fast / cheap 意味着 high-performance / on-time / inexpensive 。
[]
许多 IT 项目选择了 on-time 和 inexpensive ,将性能问题留待以后修复。这可能会成为隐患,例如使用效率低下的编程语言或底层系统,或者选择缺乏综合性能分析工具支撑的系统架构。
在性能调优中同样存在 trade-off :一个常见的例子是 CPU 和内存之间的 trade-off ,因为内存可以用于 cache 以减小 CPU 使用率。在具有大量 CPU 的现代机器上,trade-off 可能以另一种形式存在:CPU time 可以用于压缩数据以减小内存消耗。
# Tuning Efforts
在最接近执行工作的位置进行 性能调优 (performance tuning) 是最有效的。对于由应用程序驱动的 workload ,这意味着在应用程序本身内部。
下表显示了一个示例软件栈各层的可能的调优目标。
Layer | Example Tuning Targets |
---|---|
Application | Application Logic, ... |
# Methodologies
I began my tech career as a junior system administrator, and I thought I could learn performance by studying command-line tools and metrics alone. I was wrong. I read man pages from top to bottom and learned the definitions for page faults, context switches, and various other system metrics, but I didn’t know what to do with them: how to move from signals to solutions.
I noticed that, whenever there was a performance issue, the senior system administrators had their own mental procedures for moving quickly through tools and metrics to find the root cause. They understood which metrics were important and when they pointed to an issue, and how to use them to narrow down an investigation. It was this know-how that was missing from the man pages—it was typically learned by watching over the shoulder of a senior admin or engineer.
方法论 (methodology) 记录了在系统分析过程中执行各种任务的推荐步骤。如果没有方法论,性能分析可能会变得低效、不完整且偏颇。
# Linux Perf Analysis in 60 Seconds
# | Tool | Check | Section |
---|---|---|---|
1 | uptime | ... | 6.6.1 |
# Tools to Learn
staticstics :
- vmstat(8) : prints a system-wide summary of virtual memory staticstics and more, based on kernel counters in the procfs.
tracing :
strace(1), tcpdump(8) : special-purpose tracing tools for system calls / network packets.
Linux Ftrace, BCC, bpftrace : general-purpose tracing tools that can analyze the execution of all software and hardware events.
static / dynamic instrumentation :
execsnoop(8) : prints new processes created during tracing (running) through instrumenting a tracingpoint for execve(2) system call.
BPF (which originally stood for Berkeley Packet Filter) is powering the latest dynamic tracing tools for Linux. PROBLEM : What are BPF-based observability tools ?
PROBLEM : What is BPF (Berkeley Packet Filter) and ?
tools used in 1.11 case studies : mpstat(1), iostat(1), offcputime(8), cachestat(8)