软件分析与设计笔记 15:非功能需求:把「快、稳、安全」变成数字

为什么「系统要快」不是一条需求:非功能需求怎么量化,决定性能的用户量、交易量、数据量三张表怎么估,安全需求要写清什么,以及可靠性的「不可用」该怎么定义。

学习#需求分析#非功能需求#系统性能#学习笔记

本文是 《软件分析与设计笔记》 系列的第 15 篇,共 28 篇

这是我在学习软件分析与设计时整理的系列笔记。概念部分是我按自己的理解写的,示例与图示都是自己编、自己画的。理解有偏差的地方欢迎指出。

贯穿案例:片区家电维修派单系统。前面几篇都在说「做什么」,这一篇补上「做得多好」。

0 「系统要快」害了多少项目

需求文档里写着「系统响应要快」。这句话最后会变成三种结局:

  • 开发觉得已经够快,用户觉得慢 —— 因为没有标准;
  • 上线后才发现要支持的并发量是估算的十倍 —— 因为没估过规模;
  • 为了「快」把架构做得极复杂,结果大部分是白做的 —— 因为没有说不快会怎样。

非功能需求(non-functional requirement, NFR) 要解决的正是这个问题:把「快、稳、安全」翻译成可测量、可验收的数字。其中最常见的一类,就是性能需求(performance requirement)。

1 它和功能需求的区别

功能需求非功能需求
回答系统做什么系统做得多好
本例例子工程师可以现场申请配件申请提交在派单高峰时段 2 秒内完成
验收方式按用例走一遍按指标测量
出问题的时机一眼能看出来上线后高负载时才暴露

最后一行是关键:非功能缺陷往往要到真实压力下才暴露,而那时改动的代价最高。所以它必须在需求阶段就被量化。

非功能需求的三张容量表与两类质量要求:三张表分别是用户量表、业务交易量表、数据量表,各自列出分类与规模;下方是安全需求与可靠性需求各自要写清的内容

2 性能:三个量决定一切

聊性能时最容易跑偏到「用什么技术」。其实在技术选型之前,要先回答三个规模问题 —— 也就是三张表。

贯穿案例的规模先摆出来(一个城市、6 个片区、40 名工程师的试点):

2.1 用户量表(user volume table)

有多少种使用者、各有多少人。注意区分「注册用户」和「同时在线用户(concurrent user)」——后者才是压力的来源。

使用者总量同时在线(峰值)
客户约 12 万(一年累计)约 300(早 9 点报修高峰)
客服88(全员在线)
工程师40约 30(其余在路上)
仓管64
片区经理63

注意这张表最有价值的地方:「同时在线」这一列和「总量」差了两三个数量级。如果按 12 万客户来设计并发,架构会贵得离谱;如果按 300 来设计,才是对的。

2.2 业务交易量表(business transaction volume table)

每种操作一天发生多少次。这张表的价值在于暴露各操作之间的数量级差异。

操作日均峰值(单小时)倍数
客户查工单进度3 6009006×
客户提交报修400905×
客服看排期8001604×
客服派单400905×
工程师回填工单4001207×
库存查询(含外部接口)5001507×

这里有个关键观察:「查进度」的量是「派单」的 9 倍。如果两者用同一套设计(比如都走同一条重查询链路),查询会把派单拖慢。而派单是业务核心 —— 这就是为什么值得为查询单独做缓存或读库分离。

2.3 数据量表(data volume table)

每种数据一年增长多少、要保留多久。它决定的是存储、索引和归档方案,而不是接口响应。

数据年增量保留要求说明
工单10 万条5 年(法规)5 年后约 50 万条,可归档
配件消耗30 万条5 年随工单归档
客户档案12 万条长期含手机号,属敏感数据
工单状态流水200 万条1 年用于分析,1 年后可汇总

2.4 增长率的启示

这三张表的另一个作用是引出增长率:现在的量和三年后的量可能差好几倍。只按今天的规模设计,等于提前锁定一次重构 —— 而让系统在规模增长时仍保持表现,正是可扩展性(scalability)要解决的问题。

本例的增长率很明确:王姐说要推到另外 5 个片区,也就是三年内规模可能放大 6 倍。这一句就决定了:

  • 数据表要一开始就按分片区设计(否则后期要迁移);
  • 「单城市 300 并发」这个数字不能写死进架构假设。

3 峰值与均值

估这三张表时,必须同时给出两个数:均值和峰值(peak load)。

峰值和均值的差距常常是十倍以上:本例的报修高峰在早上 9 点到 10 点(客户上班前发现家里坏了),此时的量是日均的 5–7 倍。如果只报均值,容量规划一定会出问题。

吞吐量(throughput)同理:系统每秒能处理多少请求,要按峰值来定,而不是按日均。

峰值还需要注意一件事:峰值不一定同时发生。本例里「客户查进度」的峰值在早上,「工程师回填工单」的峰值在下午 5–6 点(收工前集中填),两者错开。这意味着同一套服务器资源可以在一天里被两拨不同的流量复用。

4 安全需求(security requirement)

4.1 至少要写清四件事

「要保证系统安全」不是需求。「要按角色控制数据可见范围」也不是 —— 还是不够具体。

安全需求至少要写清四件事:

  • 认证(authentication)与授权(authorization) —— 谁能登录、登录后能看到和操作什么。要具体到角色与数据范围;
  • 加密(encryption)与脱敏 —— 哪些字段属于敏感信息、传输和存储时怎么处理、在界面上怎么打码;
  • 审计日志(audit log) —— 哪些操作必须留痕,日志保留多久,谁能查;
  • 会话管理 —— 会话有效期、异常登录的处理方式。

本例填出来是这样:

项本例的具体内容
认证与授权客户用手机号 + 验证码;工程师与客服用工号 + 密码 + 短信二次验证;工程师只能看到派给自己的工单,客服只能看到本片区的
加密与脱敏客户手机号在界面上显示为 138****5678;地址在工程师接单前只显示到街道;数据库中对手机号与地址做加密存储
审计日志派单、改派、库存扣减、工单状态变更必须留痕(含操作人、时间、变更前后值),保留 3 年
会话管理客服端 30 分钟无操作自动登出;工程师 App 记住登录 7 天;同一账号异地登录需短信确认

4.2 一个实用的追问

写这些内容时有个实用的问题可以问:「如果这个人做了这件事,我们事后能查出来吗?」 如果答案是「查不出来」,这就是一条欠缺的审计需求。

本例里这个追问很有效:

  • 「客服能不能偷偷把一个好单派给自己熟悉的工程师?」→ 需要记「派单操作人」;
  • 「仓管能不能私下扣减库存?」→ 需要记「库存变更前后值」;
  • 「工程师能不能看别人片区的客户地址?」→ 需要授权控制,不只是记日志。

注意第三条不是日志能解决的 —— 日志只能事后追责,不能事前阻止。这也说明「审计」和「授权」是两件事,都要写。

5 可靠性需求(reliability requirement)

5.1 先定义「什么叫不可用」

可靠性最容易写得含糊,因为它依赖一个关键定义:什么叫「不可用」?

  • 是完全打不开,还是慢到用户放弃?
  • 是所有人都受影响,还是只影响某一个功能?

本例里的定义可以写得很有分寸:

  • 客户查进度打不开 → 算不可用(这是最核心的体验);
  • 客户查进度打开慢于 5 秒 → 也算不可用(用户会放弃并打电话,等于没做);
  • 月度报表打不开 → 不算核心不可用(王姐可以等半小时);
  • 工程师 App 打不开但网页版能用 → 算部分不可用。

最后两条尤其重要 —— 如果不先把「哪些不算不可用」写清,可用性这个指标就永远达不成。

5.2 四项指标

把这个定义写清楚之后,几项指标才有意义:

  • 可用性(availability)目标 —— 例如 99.9% 意味着一年允许停机约 8.8 小时,这个数字对多数系统已经相当紧;这类对服务水平的正式约定通常写在服务级别协议(SLA)里;
  • 故障恢复时间 —— 出问题后多久必须恢复;
  • 备份与恢复 —— 备份频率,以及有没有真的演练过恢复;
  • 降级(degradation)策略 —— 部分功能故障时,是整体停掉还是让核心功能继续跑。

本例的降级策略可以写得很具体:

故障降级做法
供应商库存接口挂了允许工程师先提交申请,标记「库存待确认」,不阻塞流程
看板服务挂了客服端仍可派单,看板显示「数据延迟」提示
短信服务挂了通知改走 App 内消息,并记录待补发

「降级」这一条常被忽略,但对用户体验影响很大:报表打不开和派不了单,严重程度完全不同。

注意第一条降级的巧妙之处:它把「外部依赖不可用」变成了「内部流程继续」。这是本例里最值得写的一条 NFR —— 因为供应商接口的可用性你控制不了。

6 一条合格的非功能需求长什么样

6.1 指标 + 条件 + 阈值

判断标准很简单:能不能直接拿去测?

不合格合格(本例的版本)
系统要快早 9:00–10:00 报修高峰,客户查工单进度的响应时间(response time)95 分位不超过 2 秒
支持高并发早高峰 300 客户同时在线时,派单操作成功率不低于 99.5%
数据要安全客户手机号在界面仅显示后四位,数据库中以加密形式存储
系统要稳定月度可用性不低于 99.5%,故障恢复时间不超过 30 分钟
外部接口要可靠供应商库存接口超时 3 秒即降级为「待确认」,不阻塞工程师提交

合格的写法包含三样东西:指标 + 条件 + 阈值。缺任何一样,都没法验证。

最后一行值得单独说:它把「外部依赖」写进了自己的需求。很多人只写自己的系统要多快,却忘了系统里有一半的延迟来自别人的接口。

6.2 容易忘掉的一类

顺带说一句,非功能需求里还有一类容易被忘掉的:可维护性(maintainability) 与 可用性(usability) 层面的要求 —— 例如「新成员能在一周内跑通本地环境」这类看似软性的目标。它们也是需求,只是更难测。

7 常见的四个错误

  • 对所有人提同样的指标。 查进度可以放宽到 2 秒,派单不行 —— 应该按操作类型分别定;
  • 只有均值没有峰值。 见上面第 3 节;
  • 只写目标不写代价。 99.99% 的可用性比 99.9% 贵得多。需求里最好说明「这个目标值不值得」;
  • 把技术方案当需求写。 「要用 Redis 缓存」是实现方案,不是需求。需求只说要多快、多少量。

本例里第一条的具体表现:如果把「查进度」和「派单」都定成「1 秒内」,那查进度那条就是浪费 —— 它一天 3600 次、每次只是读一条记录,2 秒完全够用;而为了让它 1 秒,可能要加一层缓存,多出来的复杂度换不到任何用户价值。

本节自测

  1. 为什么非功能缺陷往往到上线后才暴露?这对需求阶段意味着什么?
  2. 三张容量表里,哪一张决定了存储与归档方案?
  3. 为什么必须同时给出均值和峰值?本例的峰值出现在什么时候?
  4. 「系统要稳定」要补上什么,才能变成一条合格的需求?
  5. 为什么「用 Redis 缓存」不能写成需求?
  6. 本例中「客户查进度的量是派单的 9 倍」,这个观察对设计有什么影响?
  7. 为什么必须先写清「哪些情况不算不可用」?
  8. 本例把「供应商接口挂了」写成降级策略,为什么这条特别值得写?

参考答案

  1. 因为非功能缺陷只在真实压力下才暴露(低负载时一切正常)。所以它必须在需求阶段就量化,否则上线后改动代价最高(§1)。
  2. 数据量表。它决定存储、索引与归档方案,而不是接口响应(§2.3)。
  3. 因为峰值和均值常差十倍以上,只报均值容量规划一定出问题。本例峰值在早上 9–10 点(客户上班前发现家里坏了),是日均的 5–7 倍(§3)。
  4. 要补上指标 + 条件 + 阈值三样,例如「月度可用性不低于 99.5%,故障恢复时间不超过 30 分钟」(§6.1)。
  5. 因为它是实现方案,不是需求。需求只说「要多快、多少量」;一旦写成 Redis,就提前锁死了技术选择(§7)。
  6. 说明两者不该共用同一套设计 —— 查询量是派单的 9 倍,若走同一条重查询链路会把派单拖慢。值得为查询单独做缓存或读库分离(§2.2)。
  7. 因为如果不先写清哪些不算不可用,可用性指标永远达不成。本例:月报打不开不算核心不可用,工程师 App 挂了但网页版能用只算部分不可用(§5.1)。
  8. 因为供应商接口的可用性你控制不了。这条降级把「外部依赖不可用」转化成「内部流程继续」(允许先提交、标记待确认),是本例最值得写的一条 NFR(§5.2)。

术语表

术语中文一句话解释
non-functional requirement(NFR)非功能需求描述系统做得多好的需求
performance requirement性能需求对响应时间、吞吐量等的要求
response time响应时间从发出请求到得到响应的时间
throughput吞吐量单位时间内能处理的请求数量
concurrent user同时在线用户数同一时刻活跃的用户数量
user volume table用户量表按类型统计用户规模的表
business transaction volume table业务交易量表按交易类型统计发生次数的表
data volume table数据量表按数据对象统计增长量的表
peak load峰值负载最繁忙时段承受的负载
scalability可扩展性规模增长时系统仍能保持表现的能力
security requirement安全需求对认证、授权、加密、审计等的要求
authentication认证确认「你是谁」
authorization授权确认「你能做什么」
encryption加密把敏感数据转换成人读不懂的形式
audit log审计日志记录关键操作的日志,用于事后追溯
reliability requirement可靠性需求对可用性与故障恢复的要求
availability可用性系统处于可服务状态的时间比例
SLA服务级别协议对服务水平的正式约定
degradation降级部分能力失效时保留核心功能运行
maintainability可维护性系统被理解和修改的难易程度

© 2026 HuanYu Blog

记录技术,也记录思考