DDIA 导读 CH2 — 非功能需求 (Non-functional Requirements)
2026年4月13日
在开发软件产品时,产品本身要实现的能力会被归类为功能需求 (functional requirement)。例如在社交媒体网站中,让用户可以浏览动态、留言、点赞,这些都属于功能需求。但要让一个产品真正受到用户青睐,除了功能本身,还有其他同样关键的面向。
比如,性能就是多数用户非常在意的一项。过去有不少研究指出,如果电商网站加载更快,用户留存会显著提升。以大多数人的使用体验来说,很少有人愿意持续使用一个每次都要等五秒、十秒的电商平台或社交媒体。性能属于非功能需求,而除了性能之外,软件产品的可用性、信息安全等,也都是重要的非功能需求。
从我们的视角看,作为软件工程师,把功能做出来只是基本门槛;如果你希望成长为资深工程师,就不能只满足于“能跑就好”,“把非功能需求设计好”是绕不过去的一关。
在众多非功能需求中,作者在这一章重点讨论了四类:性能、可靠性、可扩展性与可维护性。下面我们逐一展开。
性能 (Performance)
提到软件性能时,多数人会先想到两个衡量指标:延迟 (latency) 和吞吐量 (throughput)。
所谓延迟,是指请求进入系统到系统返回响应这段时间,理想情况下越低越好。比如某个 API 能在 100 毫秒内返回,它的延迟就优于 500 毫秒返回的实现。吞吐量则是系统每秒能处理多少请求或数据,例如每秒可处理一万次写入请求,理想上越高越好。
理想状态下,低延迟和高吞吐 (low latency and high throughput) 都是系统设计者追求的目标。但现实里资源有限,两者经常需要权衡。比如同一台机器上的请求量上升后,CPU 正在处理现有请求,新请求就可能无法立刻被处理,延迟自然会上升。
作者在后文讲可扩展性时,会更多讨论吞吐量。这里我们先聚焦延迟。
拆解响应时间
讨论延迟时,书里特别强调要进一步拆分。一个请求进来后,会先经历网络延迟,接着可能在队列中等待,之后才进入实际处理;处理完成后,响应返回还会再经历一次网络传输时间。虽然书里没有展开到最细粒度,但在工程实践中,这条链路通常可以拆得更细。比如请求回到客户端后,还可以继续拆解前端阶段,我们在 关键渲染路径 (critical rendering path) 一文里就讨论过如何从前端视角拆解这段过程。
在实践中,这样拆链路非常有价值。比较推荐的做法是:流程中每个关键节点都记录对应耗时。这样一旦请求变慢,你可以快速定位到底是哪一段异常,帮助团队更快排查问题。
为什么推荐用中位数和百分位
在衡量延迟时,书里建议不要用平均值 (我们在 SLO 是什么? 如何为团队设置 SLO? 这篇文章里也讲过同样观点)。
原因是平均值很难反映“到底有多少用户遇到了慢请求”。举例来说,平均响应时间是 200 毫秒,看起来可能不错;但现实可能是“一大批非常快,另一大批非常慢”,仅靠平均值看不出慢请求到底有多糟。
相对地,用中位数和百分位会更清晰。比如中位数 (p50) 是 200 毫秒,表示有一半请求超过 200 毫秒才完成;如果第 95 百分位 (p95) 是 1.5 秒,就说明有 5% 的请求超过 1.5 秒才拿到响应。对于用户规模很大的系统(例如千万级用户),即使是 5% 也会超过 50 万,这个数量已经非常可观。百分位指标能帮助团队更有针对性地照顾这部分真实用户体验。
除了“不要只看平均值”之外,作者在这里也提到 SLO。关于 SLO 的核心内容,我们在 SLO 是什么? 如何为团队设置 SLO? 中已有更深入讨论,建议还不熟悉的读者回顾。
可靠性 (reliability)
对应用来说,可靠性意味着用户在使用时不会遇到超出预期的问题,例如功能无法按预期工作、性能差到不可用等。
但软件运行过程中,出问题几乎不可避免,不可能构建一个永远零故障的产品。所以从系统视角看,更关键的是具备韧性 (resilience):即使出现错误,系统也能容错并持续运行。业界有一类成熟实践叫混沌工程 (chaos engineering)(最知名案例之一是 Netflix 的 Chaos Monkey),会在生产环境中主动注入不同类型故障,验证系统在故障下仍能持续服务。
书中将常见故障分为三类:硬件故障 (hardware faults)、软件错误 (software errors)、人为错误 (human errors)。
磁盘损坏、海底光缆受损、龙卷风摧毁电网等都可能引发硬件故障。由于应用最终运行在硬件上,这类故障可能直接导致服务不可用。针对硬件故障,最直观的办法是做冗余 (redundancy),也就是预留额外硬件作为备份。比如某地数据中心遭遇灾害时,可通过多地域数据中心把请求切到其他区域处理(补充:我们在 什么是爆炸半径 (blast radius)? 如何有策略地缩减? 一文里有相关讨论)。
与硬件故障相比,软件错误往往影响范围更大。硬件故障通常是局部的(例如某次台风破坏东亚区域设备,不会影响北美区域),但软件错误很难被这种“天然地理边界”限制。比如 2025 年 Cloudflare 全球事故(新闻链接),就是一次软件错误导致全球范围受影响的案例。
最后,人为错误是由人的操作引发的问题。比如我们在 什么是功能旗标 (feature flags)? 为什么要用功能旗标? 一文提到,AWS 曾因人为配置错误造成巨大经济损失,就是典型的人为错误。通过简洁清晰的界面设计、充分测试和上线监控,可以有效降低这类错误带来的损害。
阅读更多
除了上面提到的内容,在 DDIA 第二章中作者还讨论了可维护性与可扩展性。如果你对完整的 DDIA 第二章导读感兴趣,可以在 E+ 成长计划 的主题文章中阅读完整版。