质量属性
性能、可用性、安全性、可修改性等架构质量属性与策略。
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 可用性的量化
可用性 = 系统正常服务的时间比例:
- MTTF(平均无故障时间):系统能连续运行多久
- MTTR(平均修复时间):故障后恢复要多久
提高可用性 = 延长 MTTF(少出事)+ 缩短 MTTR(出事快恢复)。
3.2 “几个 9”的含义
| 等级 | 可用性 | 年停机时间 | 类比 |
|---|---|---|---|
| 2 个 9 | 99% | 3.65 天 | 每年坏 4 天还能接受? |
| 3 个 9 | 99.9% | 8.76 小时 | 每年坏 1 天以内 |
| 4 个 9 | 99.99% | 52.6 分钟 | 每年坏 1 小时内 |
| 5 个 9 | 99.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 的几倍 |
权衡的正确姿势:
- 先确定”必须满足”的质量属性(业务红线,如支付必须安全)
- 再确定”可以妥协”的属性(如性能可以接受 P99 500ms)
- 把权衡决策写进 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),不能靠猜。凭感觉优化的结果往往是”优化了不存在的瓶颈”。