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 在验收时只能靠吵。