前置知识: 软件工程与测试

质量属性

11 min中级

性能、可用性、安全性、可修改性等架构质量属性与策略。

1. 从”买房子”说起:什么是质量属性

1.1 买房时你看什么

想象你要买一套房子。你关心的不会只是”有几个房间”(功能需求),还会关心很多”质量”问题:

  • 地段:交通方便吗?(可访问性)
  • 结构:隔音好吗?抗震吗?(性能、可靠性)
  • 采光通风:住得舒服吗?(用户体验)
  • 物业:小区管理靠谱吗?(可运维性)
  • 能不能改:以后能不能打通阳台?(可修改性)

这些”房子本身能用,但用得好不好、耐用不耐用”的特性,就是质量属性(Quality Attributes)。

1.2 软件的质量属性

软件也一样。一个系统”功能上能用”(能下单、能登录)只是及格线,真正区分好坏的是它的质量属性:

质量属性问的问题买房子类比
性能快不快?隔音好不好
可用性动不动就挂?建筑质量过不过关
安全性安不安全?门锁和监控
可修改性好改吗?能不能改造
可扩展性能变大吗?地皮有没有扩展空间
可测试性好验证吗?有没有验收标准
可部署性好上线吗?装修方不方便

关键认知:功能需求(Functional Requirements)回答”系统做什么”,质量属性回答”系统做得怎么样”。架构决策的核心,就是在各种质量属性之间做权衡——因为几乎所有质量属性都是互相冲突的(见第 6 节)。

1.3 质量属性场景:把”感觉”变成”可测量”

质量属性最大的难点是:它不像功能那样有明确的对错。为了解决这个问题,业界提出用**质量属性场景(Quality Attribute Scenario)**来精确描述质量需求——一个场景包含六个要素:

组成说明示例
刺激源谁触发的用户
刺激具体事件发起 1000 个并发请求
环境系统当时状态正常运行
制品受影响的对象Web 服务器
响应系统应该怎么反应处理所有请求
度量可量化的标准99% 的请求在 200ms 内完成

完整场景示例:“当用户(刺激源)在系统正常运行时(环境)同时发起 1000 个并发请求(刺激),Web 服务器(制品)应处理所有请求(响应),且 99% 的请求在 200ms 内完成(度量)。”

为什么场景重要:因为”性能要好”无法验收,但”99% 请求 < 200ms”可以。场景把质量属性从”形容词”变成了”验收标准”。

2. 性能(Performance)

2.1 性能的核心指标

指标定义类比
响应时间请求发出到收到响应的耗时从点菜到上菜的时间
吞吐量单位时间处理的请求数(QPS)餐厅每小时接待多少桌
并发数同时处理的请求数同时坐满多少桌
P50/P95/P99延迟的百分位数90% 的客人上菜在 5 分钟内

为什么看 P99 而不是平均值:平均值会掩盖问题。100 个请求里 99 个是 10ms、1 个是 10 秒,平均值 110ms”看着不错”,但那个 10 秒的用户体验极差。P99 反映”最差的那 1% 用户”体验如何——这往往才是系统真正的瓶颈。

2.2 性能策略工具箱

策略原理适用场景
缓存用空间换时间,减少重复计算/IO热点数据、读多写少
并发并行处理提高吞吐CPU 密集任务
负载均衡分散请求到多个实例无状态服务
数据库优化索引、分库分表、读写分离数据访问瓶颈
异步处理非关键路径异步化发邮件、发通知
CDN静态资源就近访问图片、静态文件
压缩减少传输体积大响应体

实战原则:性能优化要”先测量再优化”。不要凭感觉猜瓶颈,先用性能分析工具找到真正的热点,再针对性优化(详见《架构评估》的 CBAM 方法)。

3. 可用性(Availability)

3.1 可用性的量化

可用性 = 系统正常服务的时间比例:

可用性=MTTFMTTF+MTTR\text{可用性} = \frac{\text{MTTF}}{\text{MTTF} + \text{MTTR}}

  • MTTF(平均无故障时间):系统能连续运行多久
  • MTTR(平均修复时间):故障后恢复要多久

提高可用性 = 延长 MTTF(少出事)+ 缩短 MTTR(出事快恢复)。

3.2 “几个 9”的含义

等级可用性年停机时间类比
2 个 999%3.65 天每年坏 4 天还能接受?
3 个 999.9%8.76 小时每年坏 1 天以内
4 个 999.99%52.6 分钟每年坏 1 小时内
5 个 999.999%5.26 分钟每年坏 5 分钟

关键认知:每多一个 9,成本翻几倍(需要更多冗余、更复杂的系统)。99.9% 和 99.99% 之间的差距,是巨大的成本差距。 所以可用性目标不是”越高越好”,而是”业务可接受的最高值”。对普通网站 99.9% 足够,对支付系统才需要 99.99%+。

3.3 可用性策略

策略原理
冗余多实例、多机房,一个挂了其他顶上
故障检测心跳、健康检查,及时发现问题
故障恢复自动重启、故障转移
降级核心功能保障,非核心功能降级
熔断依赖故障时快速失败,防止级联
限流防止过载导致雪崩
备份数据可恢复(备份 + 恢复演练)

可用性设计的核心思路:单点是敌人。任何一个”只有一个”的东西(单台服务器、单个数据库、单个机房),都是潜在的故障点。可用性设计就是不断消灭单点。

4. 安全性(Security)

4.1 安全的核心策略

策略说明例子
认证验证”你是谁”OAuth2、JWT、SSO
授权控制”你能做什么”RBAC(角色)、ABAC(属性)
加密数据不可读传输 TLS、存储加密
审计记录”你做了什么”操作日志、安全日志
输入验证防止攻击输入防 SQL 注入、防 XSS
最小权限只给必要权限服务账号最小化

4.2 安全的两条原则

原则一:纵深防御(Defense in Depth)。不依赖单一防线——认证、授权、加密、审计、输入验证层层设防。一层被突破,还有下一层兜底。

原则二:默认安全(Secure by Default)。默认关闭/拒绝,按需开放,而不是默认全开再关。比如默认拒绝所有网络端口,只开放需要的。

安全是质量属性中最”严格”的:性能差用户会抱怨,安全漏洞会造成真实损失。而且安全问题往往”平时看不见,出事就是大事”。

5. 可修改性(Modifiability)与其他属性

5.1 可修改性

可修改性衡量”改代码的成本”。影响可修改性的策略:

策略说明
模块化高内聚、低耦合,改动局部化
抽象层隐藏实现细节,改实现不改接口
接口稳定接口向后兼容,不破坏调用方
配置外部化运行时配置而非硬编码
插件化可扩展的插件机制

判断标准:新增一个功能/修改一个规则,需要改动多少个地方?改得越少,可修改性越好。

5.2 其他重要质量属性

质量属性问的问题关键策略
可扩展性流量涨 10 倍能扛住吗?无状态设计、水平扩展、缓存
可测试性好验证正确性吗?模块解耦、依赖注入、测试接口
可部署性上线/回滚顺畅吗?CI/CD、灰度发布、配置分离
可观测性出问题能快速定位吗?日志、指标、追踪、告警
互操作性能和外部系统对接吗?标准协议、开放接口
可维护性长期维护成本高吗?清晰代码、完整文档、规范

6. 质量属性之间的权衡:没有免费的午餐

这是本篇文章最重要的部分:质量属性之间经常互相冲突。架构师的核心工作,就是理解这些冲突并做出权衡决策。

冲突说明例子
性能 vs 安全加密、认证增加延迟每次请求都做 TLS 握手会变慢
可用性 vs 一致性CAP 定理分区时保可用还是保一致
性能 vs 可修改性深度优化降低灵活性硬编码索引更快但不可配置
安全 vs 易用性认证步骤增加操作成本强密码策略让用户记不住
可扩展性 vs 简单性预留扩展增加复杂度为”也许”的需求设计插件体系
成本 vs 可用性高可用需要更多资源5 个 9 的成本是 3 个 9 的几倍

权衡的正确姿势:

  1. 先确定”必须满足”的质量属性(业务红线,如支付必须安全)
  2. 再确定”可以妥协”的属性(如性能可以接受 P99 500ms)
  3. 把权衡决策写进 ADR(记录”我们选择了 X,放弃了 Y,因为……”)

案例:某社交 App 的”点赞数”显示。

  • 方案 A:实时准确(每次请求都查数据库计数)→ 性能差、数据库压力大
  • 方案 B:缓存 + 最终一致(显示缓存值,稍后同步)→ 性能好,但数值可能滞后几秒

最终团队选 B,并在 ADR 里记录:“点赞数允许 5 秒内的滞后,换取 10 倍查询性能。若未来需要实时计数,可升级为 CQRS 方案。“——这就是一次清晰的权衡决策。

7. 质量属性驱动的架构设计

7.1 先定质量目标,再选架构

错误顺序:先选架构(“我们用微服务”),再想质量(“微服务应该能满足”)。

正确顺序:先明确质量目标(“系统要 99.9% 可用、P99 延迟 < 300ms”),再评估哪种架构能满足这些目标。

7.2 一个设计流程

1. 收集质量需求 → 写成质量属性场景(可测量)
2. 排序优先级 → 哪些是红线、哪些可妥协
3. 候选架构评估 → 每个候选架构能满足哪些属性
4. 权衡决策 → 选择最优组合,记录 ADR
5. 验证 → 压测、演练,确认质量目标达成

7.3 质量目标要可测量、可验收

目标不可验收的写法可验收的写法
性能“系统要快”“P99 响应 < 300ms,压测 1000 QPS 稳定”
可用性“系统要稳定”“月度可用性 ≥ 99.9%(年停机 < 8.76h)”
安全“系统要安全”“OWASP Top 10 全部通过,关键接口有审计日志”
可扩展“系统要能扩展”“无状态设计,支持水平扩容到 20 实例”

没有度量标准的质量目标 = 没有目标。因为它无法被验证、无法被讨论、无法被改进。

8. 常见误区

误区一:质量属性是上线后再考虑的

真相:大部分质量属性(性能、可用性、安全)是架构决定的——架构选错了,后面再怎么优化都有限。比如选了不支持的架构,就无法做到水平扩展。质量属性必须在架构设计阶段就纳入。

误区二:所有质量属性都要”最好”

真相:质量属性之间互相冲突,不可能全都最好。关键是明确优先级:哪些是红线(必须满足)、哪些可妥协。什么都想最好的系统,最终什么都做不好。

误区三:可用性 99.99% 一定比 99.9% 好

真相:多一个 9,成本可能翻几倍。可用性目标是”业务可接受的最高值”,不是”技术能达到的最高值”。为用不到的高可用白白花钱,是常见的资源浪费。

误区四:性能优化靠感觉

真相:性能问题要靠测量定位(Profile),不能靠猜。凭感觉优化的结果往往是”优化了不存在的瓶颈”。