课程一:单体架构
系统架构演进式学习方案
目标:很多复杂的系统都是从一个简单的起点逐步演化而来。本课程将通过一个渐进式场景驱动的方式,模拟一个典型 Web 应用(博客平台)在真实业务增长中可能遇到的架构挑战,带你一步步掌握经典问题的解决思路,像架构师一样思考。
阶段 0:初始系统(单体架构,一切的起点)
系统描述
- 想象一下,我们从一个最简单的博客平台开始,功能基础但够用:
- 用户注册、登录
- 发布、编辑、删除博客
- 查看博客列表和详情
- 技术栈:选型也是最常见的组合:
- 前端:HTML + JavaScript(早期可能用 jQuery,后来也许是 React/Vue)
- 后端:Python Flask 或 Java Spring Boot(经典的单体应用)
- 数据库:MySQL(单机实例,足够应对初期)
当前架构图
此刻的特点: - 代码都在一个工程里,简单直接。 - 应用直接连接数据库读写,没有中间层。 - 扩展能力?暂时还没考虑。阶段 1:流量来了 → 数据库先告急
挑战浮现
- 平台受欢迎是好事,但用户量增长后,问题随之而来:数据库查询变慢,特别是访问量大的博客列表页。
- 高峰期服务器 CPU 飙升,页面响应时间从几十毫秒恶化到半秒甚至更长。
❓ 架构师的思考时刻:瓶颈在数据库,怎么办?
(性能优化的第一反应通常是什么?加缓存?索引?还是直接读写分离?)
✅ 演进方向:缓存先行,兼顾索引
- 引入缓存救急:面对读压力,引入内存缓存(如 Redis)是性价比最高的手段。
- 缓存热门博客列表,大幅减少数据库查询。
- 先采用常见的 Cache-Aside 模式:程序先读缓存,缓存没有再查数据库,查到后写回缓存。 (当然,缓存一致性问题需要后续关注。)
- 数据库自身优化:也不能忘了根本。
- 检查
blogs
表的索引,确保created_at
等用于排序和查询的字段有合适的索引。
- 检查
- 架构微调:
阶段 2:用户激增 → 单体 Web 服务器的极限
新的瓶颈
- 流量持续上涨,峰值 QPS 从几百冲到几千,单台 Web 服务器的 CPU 直接被打满。
- 用户开始频繁遇到访问超时。
❓ 架构师的思考时刻:单点扛不住了,如何横向扩展?
(加机器是肯定的,但怎么让多台机器协同工作?用户状态怎么处理?)
✅ 演进方向:负载均衡 + 无状态化
- 横向扩展 Web 层:
- 增加部署多台 Web 服务器实例。
- 在前端引入 Nginx 作为负载均衡器,将请求分发到后端的多个实例(常用的策略有轮询、最少连接等)。
- 服务无状态化是关键:要实现轻松扩展,Web 服务器自身不能存储用户会话(Session)等状态信息。
- 将 Session 数据迁移到外部共享存储,如 Redis。这样任何一台 Web 服务器都能处理任意用户的请求。
- 架构演变为:
阶段 3:写入压力增大 → 数据库读写分离
写操作成为新焦点
- 随着用户活跃度提升,博客发布、编辑操作越来越频繁,MySQL 主库的写入压力凸显,甚至导致主从同步延迟增大。
- 用户开始抱怨:"刚发布的博客,刷新好几次都看不到!"
❓ 架构师的思考时刻:读性能解决了,写瓶颈怎么办?
(主从复制是标准答案吗?分库分表是不是太早了?有没有中间方案?)
✅ 演进方向:实施主从复制与读写分离
- 启用 MySQL 主从复制:
- 配置一个主库(Master)处理所有写操作。
- 配置一个或多个从库(Slave)处理读操作,分摊读压力。
- 引入 数据库中间件(如 ShardingSphere-JDBC/Proxy 或 ProxySQL)来自动路由读写请求,对应用层透明。
- 应对主从延迟:
- 读写分离后,需要关注主从延迟问题。对于一致性要求高的读请求(如刚发布后立即查看),可能需要强制路由到主库。
- 缓存更新策略也需调整,例如写后失效缓存而非更新,降低不一致窗口。
- 架构再次调整:
阶段 4:业务日益复杂 → 单体拆分的抉择:微服务
单体的"成长的烦恼"
- 业务不断发展,增加了"评论系统"、"用户推荐"等新模块,单体应用的代码库变得越来越庞大,维护困难。
- 不同功能的开发部署互相影响,团队协作效率下降,发布周期变长。
❓ 架构师的思考时刻:是时候"分家"了,如何优雅地拆分?
(微服务是趋势,但如何划分服务边界?服务间如何通信?异步化怎么引入?)
✅ 演进方向:拥抱微服务,引入消息队列与 API 网关
- 按业务能力拆分服务:
- 将单体应用拆分为独立的 博客服务、用户服务、评论服务 等。每个服务可以独立开发、部署和扩展。
- 服务间通信:初期可选用 REST API,性能要求高或内部调用可考虑 RPC (gRPC/Dubbo)。
- 引入消息队列实现异步解耦:
- 对于非核心、可异步处理的流程(如"博客发布后通知关注者"、"触发推荐计算"),引入 Kafka 或 RabbitMQ。生产者发送消息,消费者异步处理,提高系统韧性和响应速度。
- 构建 API 网关:
- 所有外部请求(来自客户端)统一通过 API 网关(如 Kong, Spring Cloud Gateway, Nginx+Lua)接入。
- 网关负责:路由、认证鉴权、限流熔断、日志监控等通用功能,简化后端服务。
- 演变后的微服务架构雏形:
阶段 5:数据量井喷 → 分库分表与搜索引擎
海量数据的挑战
- 博客内容和用户数据持续爆发式增长,核心的
blogs
表达到 TB 级别,即使做了读写分离,单库或单表的查询性能也急剧下降。 - 用户对内容搜索的需求越来越强烈,简单的
LIKE
查询已无法满足。
❓ 架构师的思考时刻:数据库容量和查询性能再次告急,怎么办?
(分库分表是必然选择,但按什么维度分?全文搜索用什么技术?)
✅ 演进方向:数据分片 + 引入专业搜索引擎
- 实施分库分表:
- 针对数据量最大的表(如博客表、用户表),进行水平拆分。常见的策略是按 用户 ID 或 内容 ID 哈希分片。
- 引入 数据库分片中间件(如 ShardingSphere, Vitess, MyCat)来管理分片路由规则,对应用层屏蔽底层细节。
- 引入 Elasticsearch 实现全文检索:
- 将需要搜索的博客内容(标题、正文等)同步到 Elasticsearch 集群中。
- 利用 ES 强大的倒排索引和分词能力,提供高效、精准的全文搜索功能。同步机制可以考虑用 CDC (Canal/Debezium) 或双写。
- 考虑冷热数据分离:
- 对于访问频率很低的旧博客数据,可以考虑从主存储(MySQL/ES)归档到成本更低的对象存储(如 AWS S3, 阿里云 OSS),降低在线存储压力。
- 数据存储层的演变:
阶段 6:全球化征程 → 多活架构的挑战
业务出海的新需求
- 平台需要服务全球用户,但海外用户访问国内数据中心延迟太高,体验不佳。
- 对可用性提出更高要求:即使单个数据中心发生故障,服务也不能中断。
❓ 架构师的思考时刻:如何实现全球低延迟访问和跨地域容灾?
(多地部署是必须的,但数据怎么同步?用户请求怎么路由?)
✅ 演进方向:构建多活数据中心 + CDN 加速
- 多地域部署(多活架构):
- 在不同的地理区域(如美东、欧洲、新加坡)部署独立的、功能完整的服务集群。
- 数据库层面需要支持跨区域复制和一致性的方案,如 全球数据库 (AWS Aurora Global Database, Google Spanner, CockroachDB) 或自建同步方案(可能牺牲强一致性)。
- CDN 加速静态资源:
- 将图片、CSS、JavaScript 等静态资源部署到 CDN (Content Delivery Network),利用其全球边缘节点为用户提供就近访问,极大降低延迟。
- 全局流量调度:
- 使用 智能 DNS 或 全局负载均衡 (GSLB) 服务,根据用户地理位置、网络延迟或服务健康状况,将用户请求路由到最近或最健康的区域数据中心。
- 最终架构形态(示意):
总结:一条典型的架构演进之路
阶段 | 核心问题 | 关键解决方案 | 代表技术/模式 |
---|---|---|---|
0. 单体 | 业务简单 | 单体应用 + 单机数据库 | Flask/Spring Boot, MySQL |
1. 缓存 | 读性能瓶颈 | 引入缓存 + 数据库索引优化 | Redis, Cache-Aside |
2. 水平扩展 | Web 服务器压力 | 负载均衡 + 服务无状态化 | Nginx, Redis (Session) |
3. 读写分离 | 数据库写瓶颈 | 主从复制 + 读写分离中间件 | MySQL Replication, ProxySQL/ShardingSphere |
4. 微服务 | 单体复杂难维护 | 服务拆分 + 异步解耦 | RPC/REST, Kafka/RabbitMQ, API Gateway |
5. 数据扩展 | 数据量巨大/搜索需求 | 分库分表 + 搜索引擎 | ShardingSphere/Vitess, Elasticsearch |
6. 全球化 | 低延迟/高可用 | 多活部署 + CDN | 全球数据库, GSLB, CDN |
学习方法建议
- 动手实践至关重要:每个阶段都可以尝试用云服务(AWS/Azure/阿里云等免费套餐或小规格实例)或本地 Docker/K8s 搭建一个最小化的 Demo,亲身体验配置和效果。
- 深入对比思考:主动比较同类技术的优劣,例如:"Kafka vs RabbitMQ 各自适合什么场景?"、"Redis Sentinel 和 Cluster 模式有何不同?"。
- 模拟故障场景:如果条件允许,可以尝试使用混沌工程工具(如 Chaos Mesh)或手动方式模拟节点宕机、网络延迟等故障,观察系统的反应和恢复能力。
通过模拟这条真实的业务增长和技术演进路径,我们能更好地理解各种架构设计决策背后的权衡与取舍,这正是架构师的核心价值所在。