1.1 功能性需求与非功能性需求

一句话

功能性需求回答 “系统做什么”,非功能性需求回答 “系统做到什么程度”;前者决定系统有没有用,后者决定系统能不能上线。

先分成三类,别混成一锅

类型 回答的问题 例子 可协商性 谁主导
功能性需求(FR) 做什么 下单后 30 分钟未支付自动取消 范围可剪,行为要准 业务方 + 产品
非功能性需求(NFR) 做到什么程度 下单接口 P99 ≤ 200ms @ 5000 TPS 阈值可谈,维度不能缺 架构师 + 业务方
约束(Constraint) 不能怎么做 数据必须境内存储;必须复用现有 Oracle 授权 不可谈 外部(合规 / 预算 / 现实)

P99 ≤ 200ms:P99 是延迟百分位。表示把一段时间内所有请求的响应时间从快到慢排序,第 99% 那个请求的耗时 ≤ 200ms。换句话说:99% 的请求要在 200ms 内返回,允许最多 1% 的请求超过 200ms。它不是平均耗时,也不是 “99ms”。

@ 5000 TPS:在这个性能目标下,系统要能承受每秒 5000 次下单请求。TPS = Transactions Per Second,每秒事务数/请求数。

举个例子:压测时每秒发 5000 个下单请求,统计下来如果有 100 万个请求,那么至少 99 万个请求的响应时间要 ≤ 200ms,最多 1 万个可以 >200ms。

🔑 **约束不是非功能性需求。**约束是 “给定条件”,NFR 是 “要达成的目标”。把约束写成 NFR,会在评审会上被反复追问 “那能不能优化一下”——它根本没有优化空间。

功能性需求:写 “行为”,不写 “实现”

❌ 写成实现 ✅ 写成行为 为什么
用 Redis 缓存商品详情 商品详情读取 P99 ≤ 50ms 缓存是架构手段,不该出现在需求里
加一个"提交订单"按钮 用户在确认页提交订单,成功进入支付页,失败停在原页并提示原因 前端形态可换,行为契约不变
用 Kafka 异步通知库存 订单创建成功后 3 秒内,库存服务收到扣减事件 消息中间件可换,投递承诺不可换

判断标准:这条需求换一个技术栈实现,是否还要成立?要成立 → 是需求;不成立 → 是实现,归架构决策。

一条 FR 的五个要素

要素 要回答的问题 例子(订单取消)
触发 谁 / 什么条件下开始 定时任务每分钟扫描一次待支付订单
输入 进来什么数据 订单号、创建时间、支付状态
业务规则 按什么规则算 超过 30 分钟且状态仍为待支付
输出 / 状态变化 世界变成什么样 订单置"已取消",释放库存,退款 0 元
异常分支 规则不成立时怎么办 已支付 → 跳过;取消时支付回调刚到 → 以支付成功优先

五要素缺一,开发就得自己猜;猜出来的部分,就是上线后的 bug。

非功能性需求:八个维度,每个都要落到数字

按 ISO/IEC 25010 的产品质量模型,工程质量属性收敛为八类:

维度 问什么 可验收的写法
功能适合性 覆盖全不全、算得准不准 订单金额计算准确率 100%,对账差异率 < 0.01%
性能效率 多快、扛多少 P99 ≤ 200ms @ 5000 TPS,持续 30 分钟
可靠性 / 可用性 一年能挂多久 99.95%,即年停机 ≤ 4.38 小时
安全性 谁能看、谁能改、留痕多久 手机号 AES-256 加密存储,审计日志留存 ≥ 180 天
易用性 几步完成核心任务 新用户 3 分钟内完成首单,成功率 ≥ 90%
兼容性 支持哪些端和版本 iOS 14+、Android 8+、Chrome 最近 2 个大版本
可维护性 改一次要多久 中等需求平均交付周期 ≤ 5 人日
可移植性 换云 / 换环境要多久 迁移到另一云厂商 ≤ 3 人月

可用性的 “9” 必须背下来

SLA 年停机 月停机 含义
99% 3.65 天 7.2 小时 两个 9 属于"尽力而为"
99.9% 8.76 小时 43.8 分钟 单机房 + 主从,多数业务起点
99.95% 4.38 小时 21.9 分钟 需要多可用区
99.99% 52.6 分钟 4.38 分钟 需要自动切换 + 演练
99.999% 5.26 分钟 26.3 秒 需要多活,成本量级翻倍

NFR 的四件套:指标 + 阈值 + 负载前提 + 测量方法

# nfr.yaml —— 一条不可测的 NFR 等于没写
- id: NFR-PERF-001
  name: 下单接口延迟
  metric: http_server_request_duration_seconds   # 指标:由哪个监控数据承接
  target: p99 <= 0.2                             # 阈值:带单位,带分位数
  load: 5000 rps, 读写比 1:4                      # 负载前提:不写负载的延迟没有意义
  window: 5m 滑动窗口                             # 窗口:避免被平均值稀释
  method: k6 压测 + 生产 SLO 双验证                # 测量方法:谁、用什么工具量
  owner: 交易域                                   # 责任人:达不到谁改
  verify: 每次发布后 24 小时内回归                # 验证时机

三个容易漏的点:

  • 负载前提:5000 rps 下的 200ms 和 5 rps 下的 200ms 是两个系统。
  • 分位数:平均 50ms、P99 3s 的系统,1% 的用户每次都在骂。5000 rps 下,P99 超标意味着每秒 50 个慢请求。
  • 测量方法:写不出 “怎么量”,这条 NFR 在验收时必然变成主观判断。

为什么 NFR 才是架构的真正驱动力

同一组功能需求,NFR 不同,架构完全不同。

场景 关键 NFR 架构结果
企业内部下单,1 千单/天,团队 5 人 99.9%,成本优先 单体 + 单库主从
电商大促,50 万单/天,团队 50 人 99.99%,P99 ≤ 200ms 微服务 + 分库分表 + 多可用区 + 缓存
支付核心,99.995%,RTO < 1 分钟 可用性 + 一致性优先 单元化多活 + 两地三中心

🔑 功能性需求决定 “要几个模块”,非功能性需求决定 “模块怎么切、要不要冗余、要不要缓存、上不上多活”。代码可以一样,架构一定不一样。

NFR 之间天然打架,必须排序

冲突对 表现 典型取舍
性能 ↔ 安全 每跳 mTLS、全链路加密都有开销 内网 mTLS + 硬件加速,不取消加密
可用性 ↔ 一致性 多活写入必然遇到冲突 交易走单元内闭环,跨单元最终一致
可用性 ↔ 成本 多活 = 至少 2 倍资源 按业务分级:核心多活,边缘单机房
可维护性 ↔ 性能 每层抽象都有开销 热路径去掉抽象,冷路径保留分层
交付速度 ↔ 质量 赶工期就砍测试 用错误预算说话,不靠拍脑袋

写法:在需求文档里显式写一句 “当 A 与 B 冲突时,优先 A”。没有这句话,架构评审就会变成 3 小时的立场之争。

反模式

反模式 后果
"系统要高性能、高可用、高并发" 无法验收,交付时双方各说各话
NFR 用形容词(快、稳、安全、友好) 没有阈值 → 没有测试 → 上线才发现
把实现写进需求("用 Redis""上 K8s") 设计空间被提前锁死,架构师沦为执行者
所有 NFR 都是 P0 等于没有优先级,资源平均分配,哪个都没达标
NFR 只活在需求文档里 没有监控指标承接,上线即失忆
只写平均值不写长尾 平均值达标、P99 崩盘,用户体感极差
把合规约束当 NFR 讨论 反复"优化"一个不可谈的边界,浪费整个迭代

三条铁律

🔑 一条 NFR 只有能写出 “在什么负载下、用什么方法测、达不到谁负责” 才算写完。

🔑 功能性需求可以用 “增删改查” 验收,非功能性需求只能用数字验收。

🔑 性能可以后补缓存,安全与合规不能后补——它们改的是架构,不是代码。

自检

Q1 “系统应支持高并发” 要补齐哪四样东西,才能变成一条可验收的 NFR?

▸ 答案:指标 (延迟还是吞吐)、阈值 (带单位和分位数)、负载前提 (多少 QPS / 多少连接)、测量方法与窗口。缺任何一项,开发都可以说 “已经支持了”。

Q2 客户张口就要 “99.99% 可用性”,你先问哪三个问题?

▸ 答案:① 计划内维护算不算停机 (很多 SLA 把维护窗口排除在外);② 降级算不算可用 (只读模式、关闭非核心功能算不算 “服务中”);③ 这笔钱谁出——99.99% 要从 99.9% 的单机房主从升级到自动切换 + 多可用区,资源与演练成本至少翻倍。第三个问题最能筛掉伪需求。

Q3 需求文档里写 “订单列表用 Elasticsearch 实现”,问题出在哪?

▸ 答案:这是实现,不是需求。改成 “NFR:订单列表按 8 个条件组合查询,P99 ≤ 300ms,数据量 5 亿行”——满足它的手段可以是 ES、可以是覆盖索引、也可以是列存,架构师才有选择权。

Q4 同一组功能需求,团队 5 人和团队 500 人的系统架构差异,根源是哪类需求?

▸ 答案:非功能性需求 (以及隐含的组织约束)。500 人团队需要独立部署、独立扩缩容、独立发布节奏,本质上是在用 NFR 的 “可维护性 / 可扩展性” 换取架构复杂度;5 人团队上微服务,是拿最贵的成本换最不需要的属性。

Q5 一条 NFR 写着 “P99 ≤ 200ms”,为什么还是不够?

▸ 答案:缺负载前提和测量方法。5 rps 下的 200ms 与 5000 rps 下的 200ms 不是一回事;没有压测脚本与监控指标承接,这条 NFR 在验收时只能靠吵。