news 2026/9/27 10:23:12

系统故障排查与性能优化实战:School of SRE 课程(Level 102)完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
系统故障排查与性能优化实战:School of SRE 课程(Level 102)完整指南
  • 教程

【免费下载链接】school-of-sre

At LinkedIn, we are using this curriculum for onboarding our entry-level talents into the SRE role.

项目地址:https://gitcode.com/gh_mirrors/sc/school-of-sre
点击查看免费下载

本指南基于 School of SRE 课程level102/system_troubleshooting_and_performance整理,面向以 Web API 服务为核心场景的 SRE 新人,系统讲解故障排查的方法论、必备 Linux 工具、性能分析与基准测试手段,并通过一个真实的 Python/Flask 内存泄漏排查案例演示"问题复现 → 信息收集 → 定位根因 → 验证修复"的完整闭环。读完本文,你将掌握一套可复用的系统故障排查流程,学会用top、sar、strace、lsof等命令快速定位问题,并能借助tracemalloc、ab等工具对服务进行性能剖析与压测验证。

课程定位与前置知识

这是 School of SRE 课程体系(位于 courses/level102/system_troubleshooting_and_performance/)中面向初级 SRE 的入门课程。它尝试为以下场景提供通用性的故障排查入门指引:

  • 分析 API 失败
  • 资源利用率问题(CPU、内存、磁盘、网络)
  • 网络问题
  • 硬件与操作系统问题
  • 通过性能剖析(Profiling)与基准测试(Benchmarking)衡量系统整体性能

在开始本课程之前,官方建议你先掌握以下 Level 101 的基础内容:

  • Linux 基础
  • 系统设计
  • 基础网络
  • 指标与监控

本课程不涵盖的内容

为避免范围失控,本课程明确不涉及以下主题,它们由课程体系中的其他部分承担:

  • 系统设计与架构(参见 systems_design 与 system_design)
  • 编程实践(参见 python_web)
  • 指标与监控(参见 metrics_and_monitoring)
  • 操作系统基础(参见 linux_basics)

为什么 SRE 必须掌握故障排查

故障排查是运维与开发工作中最重要的组成部分之一,但它无法通过阅读一篇文章或完成一门在线课程就能学会——它是一个持续的学习过程,需要在以下场景中不断积累:

  • 日常运维与开发
  • 发现并修复应用 Bug
  • 发现并修复系统与网络问题
  • 性能分析与优化

排查问题前应具备的知识储备

从 SRE 的视角出发,要能够排查单机或分布式系统的问题,你需要在平时就建立以下认知:

  1. 充分了解你的资源:清楚主机的规格,如 CPU、内存、网络、磁盘等。
  2. 理解系统设计与架构:只有知道系统如何组织,才能判断故障出在哪一层。
  3. 确保关键指标被正确采集与展示:监控是排查的基础。

HP 创始人有一句名言:"What gets measured gets fixed"(能被度量的,就能被修复)。如果系统组件与性能指标被完整地采集,那么在问题发生的最早期成功排查的概率就会大大提高。这正是本课程把 指标与监控 列为前置课程的原因。

课程范围界定

不同类型的应用或服务没有统一的排查方法,故障可能发生在服务的任意一层。本课程将范围聚焦于Web API 服务这一典型场景。

说明:Linux 生态非常庞大,有成百上千种可用于系统故障排查的工具与实用程序,每种工具都有各自的优势与功能。本课程只覆盖一部分知名工具(要么 Linux 自带,要么来自开源社区),对工具的详细用法不做展开,建议通过man手册页或在线资料深入学习。

课程内容全景

本课程共分五个部分,每一部分都有独立的 Markdown 文档,位于同一目录下,可按顺序学习:

  1. Introduction(本页)
  2. Troubleshooting(故障排查方法论):包含故障排查流程图、通用实践、通用主机问题
  3. Important tools to know(必备工具):重要 Linux 命令、日志分析工具
  4. Performance improvements(性能改进):性能分析命令、性能剖析工具、基准测试、扩展
  5. Troubleshooting Example(排查实战示例):内存泄漏排查全程演示
  6. Conclusion(总结):延伸阅读

故障排查:系统化方法论

排查系统故障有时非常棘手和耗时。这项实践中,我们需要检查一个服务的端到端流程:所有下游依赖、日志分析、内存泄漏、CPU 占用、磁盘 IO、网络故障、主机问题等。掌握一定的实践与工具,能更快地发现并缓解故障。

故障排查流程图

下面这张流程图(原图见 TroubleshootingFlow.jpg)是整个排查过程的高层指引,它是一个典型的闭环流程:

流程从Start开始,依次经历:

  1. Reproduce Problem(复现问题)→ 2.Gather Information(收集信息)→ 3.Understand Problem(理解问题)→ 4.Find Solution(找到解决方案)→ 5.Apply Fix(应用修复)

随后进入判断节点"Fix working?(修复是否生效?)":

  • 若No,回到Reproduce Problem重新排查;
  • 若Yes,进入Verify complete flow(验证完整流程)。

最后再次判断"Working?(是否正常运行?)":

  • 若No,同样回到Reproduce Problem重新排查;
  • 若Yes,流程以End结束。

这个闭环设计体现了排查的核心原则:修复未生效或未达预期时,必须回到起点重新复现与定位,而不是在错误的方向上继续深挖。

通用实践:五步定位 Web 应用故障

不同系统需要不同的排查方法。以下五个高层实践点针对"寻找 Web 应用故障并找到修复方案"这一目标展开:

1. 复现问题(Reproduce problem)

  • 尝试复现失败的请求,例如重放失败的 http/https 请求;
  • 检查请求的端到端流程,关注返回码:3xx多为重定向,4xx多为未授权、错误请求、禁止访问等客户端问题,5xx多为服务端问题。根据返回码决定下一步排查方向;
  • 客户端侧的问题主要是静态内容缺失或存在 Bug,例如 JavaScript 脚本错误、损坏的图片、异步调用返回的损坏 JSON 等,这些会导致浏览器页面渲染不正确。

2. 收集信息(Gather Information)

  • 在应用日志中查找错误/异常,例如 "Can't Allocate Memory"、OutOfMemoryError、"disk I/O error"、DNS 解析错误等;
  • 检查应用与主机指标,寻找服务与主机图表中的异常:CPU 使用率从何时开始升高、内存使用率从何时开始升高、磁盘空间从何时开始减少、磁盘 IO 从何时开始增加、负载均值(load average)从何时开始飙升等。监控相关的细节可参考 指标与监控;
  • 查找近期可能破坏系统的代码或配置变更。

3. 理解问题(Understand the problem)

  • 尝试将收集到的数据与近期操作关联起来,例如配置/代码部署后日志中出现异常;
  • 判断根因:是因为 QPS(每秒查询数)上升?是糟糕的 SQL 查询?还是最近的代码变更要求更好或更多的硬件?

4. 找到解决方案并应用修复(Find a solution and apply a fix)

  • 基于以上发现,尽可能寻找快速修复方案,例如当错误/异常与变更相关时直接回滚(Rollback);
  • 如果想向前修复(Fix forward),尝试在预发布(Staging)环境打补丁或热修复(Hotfix);
  • 如果高 QPS 是系统失败的原因,尝试纵向扩容,按需增加资源(计算、存储、内存等);
  • 必要时优化 SQL 查询。

5. 验证完整请求流程(Verify complete request flow)

  • 再次发起请求,确保返回成功(返回码2xx);
  • 检查日志,确保不再出现此前发现的异常/错误;
  • 确保指标恢复正常。

通用主机问题排查

要判断主机健康状况是否正常,排查硬件故障或性能问题,可以尝试以下手段:

手段用途
dmesg显示内核近期抛出的错误/故障,有助于发现硬件故障
lspci/lsblk/lscpu/lsscsi分别列出 PCI 设备、磁盘块设备、CPU 信息、SCSI 设备
/var/log/messages显示系统应用/服务相关的错误与警告,也包含内核问题
smartd检查磁盘健康状态

必备工具:常用 Linux 命令与日志分析平台

掌握以下命令能帮助你更快地定位问题(各命令的详细用法请查阅man手册页):

场景命令
日志解析grep、sed、awk、cut、tail、head
网络检查nc、netstat、traceroute/6、mtr、ping/6、route、tcpdump、ss、ip
DNSdig、host、nslookup
系统调用跟踪strace
多主机并行执行GNUparallel、xargs+ssh
HTTP/S 检查curl、wget
列出打开的文件lsof
修改系统内核属性sysctl

分布式系统下的批量执行工具

在分布式系统中,一些优秀的第三方工具可以帮助你在大量主机上同时执行命令/指令:

基于 SSH 的工具

  • ClusterSSH:可以在多台主机上并行运行同一条命令;
  • Ansible:编写 Ansible playbook,可在成百上千台主机上同时执行。

基于 Agent 的工具

  • SaltStack:配置、状态与远程执行框架,提供了丰富的灵活性,可在大规模主机上执行模块;
  • Puppet:面向 Linux、Unix、Windows 系统的自动化管理引擎,执行各类管理任务。

日志分析工具

这类工具支持用类 SQL 查询来解析和分析日志,并提供易用的 UI 界面来创建基于查询渲染各种图表的仪表盘:

  • ELK(Elasticsearch、Logstash、Kibana):提供解析日志、索引日志、分析日志的完整工具包。日志经 Logstash 解析/过滤并索引到 Elasticsearch 后,几分钟内即可在 Kibana 中创建动态仪表盘,从而方便地对应用错误/异常/警告进行分析与关联;
  • Azure Kusto(Azure Data Explorer):与 Elasticsearch + Kibana 类似的云服务,支持对海量日志进行索引,提供类 SQL 查询接口和动态仪表盘创建界面。

性能改进:分析、剖析、基准测试与扩展

性能工具是开发/运维生命周期中重要的一部分,对理解应用行为至关重要。SRE 通常使用这些工具评估服务将如何表现,并据此做出/提出改进建议。

性能分析命令

以下命令是做系统或服务性能分析时的必知命令:

命令用途
top实时查看运行系统、进程、线程等
htop类似top,但更具交互性
iotop交互式磁盘 I/O 监控工具
vmstat虚拟内存统计探查工具
iostat设备和分区的输入/输出统计监控
free显示物理内存与交换内存信息
sar系统活动报告,报告 CPU、磁盘、内存、网络等多种指标
mpstat显示 CPU 利用率与性能信息
lsof提供打开文件列表及其所属进程信息
perf性能分析工具

性能剖析(Profiling)工具

剖析是服务性能分析的重要部分。多种剖析器可帮你找出最高频的代码路径(hot code-paths)、进行调试、内存剖析等,还能生成热力图(heatmap)来理解服务在负载下的代码性能:

  • FlameGraph(火焰图):被剖析软件的图形化可视化工具,可快速准确地识别最高频代码路径;
  • Valgrind:用于内存调试、内存泄漏检测与剖析的编程工具;
  • Gprof(GNU profiler):混合使用插桩(instrumentation)与采样(sampling)的剖析工具——插桩用于收集函数调用信息,采样用于收集运行时剖析信息。

工程实践参考:LinkedIn 曾在其工程博客中介绍ODP(On-Demand Service Profiling,按需服务剖析基础设施),展示了在大型分布式系统中按需对线上服务进行剖析的实践思路。

基准测试(Benchmarking)

基准测试是衡量服务最佳性能的过程,例如:服务能承受多高的 QPS、负载上升时的延迟表现、主机资源利用率、load average 等。回归测试(即负载测试)在服务部署到生产环境之前是必须执行的。

常用工具:

工具说明
ab(Apache Benchmark Tool)对 Web 应用模拟高负载并收集数据用于分析
httperf按指定速率向 Web 服务器发送请求并收集统计信息,可逐步加压直至找到饱和点
Apache JMeter流行的开源 Web 应用性能测量工具,基于 Java,不仅可用于 Web 服务器,还可用于 PHP、Java、REST 等
wrk现代性能测量工具,可对 Web 服务器施压并输出延迟、每秒请求数、每秒传输量等指标
Locust易用、可脚本化、可扩展的性能测试工具

局限性:以上工具属于合成负载(Synthetic Load)或压力测试,它们无法测量真实终端用户体验——无法感知终端用户因内存、CPU 不足或互联网连接质量差而对应用性能产生的影响。

工程实践参考:LinkedIn 工程博客曾介绍如何在整支舰队(fleet)范围内做全自动负载测试以消除 toil,以及如何利用RUM(Real User Monitoring,真实用户监控)数据可视化来弥补负载测试的上述局限、改善终端用户体验。

扩展(Scaling)

一个设计良好的系统,其性能上限也受限于可用资源。持续优化始终是保证资源在峰值期得到最优利用的必要手段。随着 QPS 的增长,系统需要扩容,方式主要有两种:

  • 纵向扩展(Vertical):增加 CPU、内存、磁盘、GPU 等规格,但存在物理上限;
  • 横向扩展(Horizontal):受限于应用设计与环境属性,但原则上可以近乎无限地扩展。

扩展一个 Web 应用通常需要以下一项或多项操作:

  • 增加更多主机以分担服务器负载;
  • 使用负载均衡器(Load Balancer)在服务器之间分发流量;
  • 通过数据分片(Sharding)和增加只读副本(Read Replicas)来扩展数据库。

工程实践参考:LinkedIn 工程博客的《A Brief History of Scaling LinkedIn》一文详细介绍了 LinkedIn 应用栈的演进式扩展历史,是理解大规模扩展挑战的经典读物。

实战示例:用 tracemalloc 定位 Python/Flask 内存泄漏

这一节演示一个真实可操作的案例:一个带有内存泄漏 Bug 的 Flask Web 应用,每次请求内存都会持续增长,我们将使用 Python 内置的tracemalloc模块定位泄漏源头。

内存泄漏问题往往在服务运行数天、数周甚至数月后、直到服务变得无响应才被发现,除非重启服务或修复 Bug。这类服务的指标图会呈现持续上升的曲线,如下图所示(原图见 MemUsageChart.png):

内存泄漏本质上是应用对内存分配的管理失误:不再需要的内存没有被释放,随时间推移对象不断堆积,最终导致服务崩溃。通常情况下,这类未释放的对象会被垃圾回收器(Garbage Collector)自动回收,但有时由于 Bug,回收失败。调试可以帮助弄清应用存储内存主要被用在哪里,然后你就可以基于使用情况跟踪并过滤一切对象;如果发现某些对象未被使用但仍有引用,就可以通过删除它们来避免内存泄漏。

对于 Python 应用,内置的tracemalloc模块可以帮助精确定位对象首次被分配的位置。几乎每种语言都有(内置或外部的)工具/库来帮助发现内存问题,例如 Java 生态中著名的内存泄漏检测工具 Java VisualVM。

步骤 1:准备带 Bug 的 Flask 应用

假设:已经创建 Python 虚拟环境,并在其中安装了 Flask。

示例包含两个 Python 文件(代码截图见 FlaskCode.png):

app.py(Flask 主文件),一个存在内存泄漏 Bug 的最小应用:

from flask import Flask from fetchuserdata import user_data users_list = [] # 用于累积用户数据的列表(泄漏载体) # buggy_list = [] # 注释说明:此列表并非泄漏载体 app = Flask(__name__) @app.route("/") def index(): if user_data(users_list): # 每次请求都会向 users_list 追加数据 return f"Total users found {len(users_list)}" return "Failed to get user data" if __name__ == "__main__": app.run()

fetchuserdata.py(数据模块):

def user_data(users_list): # 从数据库拉取用户数据并存入传入的列表 data = [("Foo", "Bar", "0123456789") for _ in range(5000)] # 每次调用构造 5000 条模拟数据 users_list.extend(data) # 内存泄漏根源:列表不断累积数据,直至耗尽内存 return True

关键点在于users_list.extend(data)这一行:它作为模块级全局变量在app.py中被反复传入并扩展,每次 GET 请求都会向列表中追加 5000 条元组,而这些数据从未被清理。

步骤 2:启动应用并观察内存增长

在虚拟环境中启动应用(启动输出见 FlaskStart.png):

(flaskapp) [user1@user1 flaskapp]$ flask run

启动后应用监听在http://127.0.0.1:5000/。此时用ps观察进程内存(见 MemUsage01.png):

$ ps auxwh | grep [f]lask

初始内存约为26576 KB(约 26 MB)。

步骤 3:逐次请求观察内存缓慢攀升

每次发起 GET 请求,进程内存都会缓慢但持续地增长(见 MemUsage02.png),四次请求后的表现:

请求次数响应内容进程内存
第 1 次Total users found 500026948 KB(较初始 +372 KB)
第 2 次Total users found 1000027076 KB(+128 KB)
第 3 次Total users found 1500027120 KB(+44 KB)
第 4 次Total users found 2000027160 KB(+40 KB)

内存只增不减,且响应中的用户总数在持续累加——这是"列表在全局范围内不断扩展"的直接证据。

步骤 4:用 ab 加压 10000 次请求验证

为了确认泄漏规模,使用 Apache 基准测试工具ab发起 10000 次请求:

$ ab -n 10000 -c 10 http://127.0.0.1:5000/

压测完成后再次查看进程内存(见 MemUsage03.png):

$ ps auxwh | grep [f]lask

此时 Flask 进程内存已从初始的26576 KB 暴涨到 419316 KB——从约 26 MB 跳到约419 MB,几乎增长15 倍。对于一个如此小的 Web 应用,这是非常惊人的内存增幅,明确证实了泄漏。

步骤 5:接入 tracemalloc 定位泄漏源头

tracemalloc模块可在特定时间点抓取内存快照,并对快照执行各种统计。在app.py中增加最小代码(fetchuserdata.py无需改动),新增一个/capture路由,用于在访问时抓取 tracemalloc 快照:

import tracemalloc from flask import Flask from fetchuserdata import user_data users_list = [] app = Flask(__name__) tracemalloc.start() # 启动内存跟踪 @app.route("/") def index(): if user_data(users_list): return f"Total users found {len(users_list)}" return "Failed to get user data" @app.route("/capture") def capture(): snapshot = tracemalloc.take_snapshot() # 抓取当前内存快照 top_stats = snapshot.statistics("lineno") # 按行号统计 result = [] for stat in top_stats[:10]: result.append(f"{stat.traceback}: {stat.size / 1024 / 1024:.1f} MB") return "<br>".join(result) if __name__ == "__main__": app.run()

注:截图版示例代码位于 Tracemalloc01.png,此处为便于阅读整理的等价实现;核心思路一致——在快照后对分配对象按文件行号(lineno)分组统计。

重启app.py(flask run)后,按以下顺序操作:

  1. 先访问http://127.0.0.1:5000/capture,记录基线快照;
  2. 再访问http://127.0.0.1:5000/共 10000 次,让内存泄漏充分发生;
  3. 最后再次访问http://127.0.0.1:5000/capture,抓取第二次快照。

对比两次快照(见 Tracemalloc02.png 与 Tracemalloc03.png),最终快照会精确指出内存分配量最大的模块与行号:fetchuserdata.py的第 6 行(即users_list.extend(data)),在 10000 次请求后持有了约419 MB的内存。

排查结论与生产环境注意事项

以上示例展示了一个 Bug 如何导致内存泄漏,以及如何借助tracemalloc定位其源头。真实世界的应用远比这个示例复杂,请注意:

  • 使用tracemalloc会因自身开销而在一定程度上降低应用性能;
  • 在生产环境中使用需谨慎,建议仅在调试窗口期开启,或优先在预发布环境复现排查。

对于 Python 对象内存分配内部机制与内存泄漏调试的深入探讨,可参考 PyCon India 2019 的相关技术分享《Debug Memory Leak In Python Flask | Python Object Memory Allocation Internals》。

总结

复杂系统有太多可能出错的环节:糟糕的设计与架构、管理不善的代码、不合理的缓存策略、糟糕的数据库查询或架构、不恰当的资源使用、不合适的 OS 版本、监控不到位的系统、数据中心问题、网络故障等——任何一项都可能引发故障。

作为 SRE,掌握关键工具与命令、最佳实践、性能剖析、基准测试与扩展手段,将帮助你更快地完成故障排查与整体系统的性能改进。本课程的 Conclusion 中还列出了 LinkedIn 工程博客上的经典实战文章作为延伸阅读,主题包括:

  • 用 Jemalloc 驯服 Venice 中的内存碎片
  • 修复 Linux 文件系统性能回归
  • 慢速 NFS 对数据系统的影响
  • 运维中的"每天都是星期一"精神

这些来自一线 SRE 的实战记录,与本文的方法论和示例相互印证,值得在完成本课程后逐一精读。

课程学习路径建议

  • Level 101 前置:Linux 基础 → 系统设计 → 基础网络 → 指标与监控;
  • 本课程正文:Troubleshooting → Important tools → Performance improvements → Troubleshooting Example → Conclusion。

建议在学习本课程时,动手在你的实验环境里复现内存泄漏示例,亲手运行ab压测与tracemalloc快照,把方法论转化为可迁移的排查直觉。

  • 教程

【免费下载链接】school-of-sre

At LinkedIn, we are using this curriculum for onboarding our entry-level talents into the SRE role.

项目地址:https://gitcode.com/gh_mirrors/sc/school-of-sre
点击查看免费下载

相关推荐

上一篇:Redux 设计溯源:从 Flux、Elm、Immutable 到 RxJS 的"前人艺术"全解析
下一篇:如何3步解锁网易云音乐NCM文件:Windows图形界面终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 10:22:57

wordpress主题innmx实测3坑:被黑后如何用代码加固

wordpress主题innmx实测3坑:被黑后如何用代码加固 网站被黑挂马后,很多项目经理第一反应是删库重装,但往往忽略了底层代码的脆弱性。近期对 wordpress主题innmx 进行深度 对比评测…

作者头像 李华
网站建设 2026/9/27 10:22:53

做网站流程优帮云:3步搞定域名服务器配置与免费工具实战

做网站流程优帮云:3步搞定域名服务器配置与免费工具实战 域名解析报错、服务器 IP 找不到、SSL 证书装不上……是不是每次搞这堆东西头都大?很多甲方对接人最头疼的就是这块,明明网站做好了,上线却卡在基础设施上。其实, 做网站流程优帮云…

作者头像 李华
网站建设 2026/9/27 10:22:43

godday网站建设新手从零搭建避坑指南

godday网站建设新手从零搭建避坑指南 昨晚三点,盯着后台满屏红色的“网站被黑挂马”警报,那种绝望感谁懂?辛辛苦苦搞了半年的 godday 网站建设,一夜之间变成钓鱼网站,客户投诉电话打爆,SEO排名归零。别慌,先深呼吸。很多新手在从零搭建阶段,因为忽视基础安全配置,导致上线即裸奔,被脚本攻击是迟…

作者头像 李华
网站建设 2026/9/27 10:22:34

网站建设服务兴田德润:不懂代码别乱问建站报价,先防住这5个安全坑

网站建设服务兴田德润:不懂代码别乱问建站报价,先防住这5个安全坑 自己不会代码想做网站,千万别一上来就满世界找【建站报价】。 我见过太多老板,拿着几千块的预算,觉得“不就是个页面吗”,结果上线不到一周,后台被黑、数据被拖、SEO权重清零。 在【网站建设服务兴田德润】这类实战项目中,…

作者头像 李华
网站建设 2026/9/27 10:22:17

拒绝拖延!网站可以自己做图解步骤实战

拒绝拖延!网站可以自己做图解步骤实战 改个需求建站公司拖一周,这种憋屈感创业团队负责人肯定懂。 别等了, 网站可以自己做 ,这篇图解步骤带你从0到1落地。 很多河南老板觉得建站是技术活,其实没那么玄乎。 我干了十年SEO和建站,见过太多企业被外包公司坑。…

作者头像 李华