回到首页

输入关键词,多个关键词用空格分隔。

← 工程原理与设计 · 系列目录

云服务架构:围绕状态、故障与容量做取舍

约 3 分钟
本页目录

云平台提供了很多组件,但把组件接起来,并不自动得到可靠系统。架构首先要回答的是:系统保存哪些状态,允许哪些失败,需求增长时哪里会先达到上限。

本文重写自《云平台架构沉思录》,保留负载均衡、缓存、业务层和数据层的主线,移除旧产品配置,以及“换成某类数据库就能解决性能问题”的判断。

从一条请求开始

假设一个服务接收用户提交,保存记录,并生成一份耗时的报告。先画出同步请求必须完成的步骤:认证、校验、保存、返回任务标识。报告生成可以交给后台处理,用户稍后查询结果。

这个拆分不是因为异步天然更好,而是因为用户不必一直等待计算完成。但它同时引入新问题:任务如何可靠入队,失败怎样重试,用户如何知道最终状态。选择异步,就要承担这些状态管理成本。

无状态服务仍然依赖状态

把业务实例放在负载均衡之后,有助于分配请求与替换实例。实例不保存唯一的会话或任务状态,才能减少请求落到不同实例时的差异。

这不意味着系统没有状态,只是状态被放在数据库、对象存储或其他明确的持久层。也不意味着负载均衡提供了全部隔离:健康检查、网络访问、认证和服务权限仍需分别设计。

如果请求需要跨多个服务,必须考虑整个路径。单个服务各自表现良好,并不保证调用链在超时、重试和部分失败时仍然可用。

重试会消耗容量,也可能重复执行

请求超时不能证明服务端没有执行成功。例如保存已完成,但响应在网络中丢失,客户端重试就可能创建重复记录。对于这类操作,需要业务层的幂等标识或其他去重约定。

重试应区分临时错误与不会自行恢复的错误,并限制次数、设置退避和随机抖动。多层同时重试会放大流量;系统已经过载时,无限制重试尤其危险。相关原则见 AWS 重试控制说明。

设计时应写清楚哪一层负责重试,以及超过预算后如何向调用方表达失败,而不是让每层都“尽最大努力”。

缓存必须先定义一致性要求

缓存可以降低读取成本,但要先说明允许读到多旧的数据、谁负责更新、未命中怎么办。商品展示信息与订单支付状态可能有完全不同的要求,不能使用同一个“过期几分钟”策略解释所有业务。

缓存丢失时,后端是否承受得住回源流量,也是架构的一部分。热点键同时失效、查询结果为空、单个大对象等情况,都应进入测试场景。

原文把共享 Map 的锁问题直接类比到 Redis,容易混淆进程内数据结构与远程存储的并发语义。具体需要什么锁或原子操作,应根据实际实现分析,不能仅凭容器名称决定。

数据层按约束选择

先列出访问模式:按键读取、范围查询、多表关联、事务更新还是图关系遍历。再检查一致性、索引、容量和团队维护能力。

关系数据库和不同类型的非关系数据库各有约束。增加节点之前,也应检查数据模型、索引和查询是否合理。分片带来的迁移、跨分片查询与运维成本,不会因为部署在云上就消失。

报告文件适合放在可持久保存文件的存储中,但任务消息与文件不是同一类数据。消息队列负责传递工作,文件存储负责保存结果,中间需要明确的生产和消费过程。

扩容前检查限制在哪里

如果数据库连接池只有固定容量,增加业务实例可能只是增加竞争。如果后台消费者比生产者慢,队列会延后失败,而不是消除失败。扩容应根据真实瓶颈和服务目标触发。

一次完整验证应覆盖正常负载、峰值负载、单个依赖变慢和实例退出。关注吞吐、延迟分布、错误率和资源占用,同时验证降级与恢复路径。

架构的最终结果应是一组解释得通的取舍:为什么这样划分状态,为什么采用这个同步边界,什么条件下需要调整。组件清单只是实现这些取舍的手段。

相关文章