架构设计到底在设计什么 —— 从单体到微服务的演进
"我们要不要上微服务?""这个得做成分布式的吧?"——聊到架构,这类话满天飞,但架构设计到底在设计什么? 这个问题反而很少被说清。至少我刚开始补这块时是一头雾水的:总以为架构就是画框图、堆时髦技术,后来才慢慢发现不是这么回事。
这是《服务端架构设计》系列的开篇,先建一张全局地图:架构的本质是什么、它在哪几个目标之间权衡,以及一个系统从单体长到微服务,每一步到底在解决什么问题。把这张地图揣在手里,后面每一块(高并发、高可用、微服务、分布式)才挂得上去。
一、架构设计到底在设计什么
是什么。 架构是一个系统的骨架:它决定了系统拆成哪些模块、模块之间怎么协作、数据怎么流动、请求怎么被处理。但更本质的一句话是——
架构设计不是"选最牛的技术",而是在一组互相冲突的目标之间做权衡(trade-off)。
评价一个架构好不好,业界有一套公认的坐标系,叫非功能性需求(功能之外、但决定系统"扛不扛得住"的那些):
| 维度 | 一句话 | 衡量 |
|---|---|---|
| 高性能 | 快不快 | 响应时间、吞吐(QPS / TPS) |
| 高可用 | 稳不稳、宕不宕机 | 可用性(几个 9,如 99.99%) |
| 可扩展性 | 能不能长大 | 加机器能不能线性扛更多 |
| 可维护 / 可演进 | 好不好改 | 加功能要不要动全身 |
| 安全 | 守不守得住 | 鉴权、防攻击、数据保护 |
| 成本 | 烧多少钱 | 机器、带宽、人力 |
关键认知:这些维度互相冲突。 高可用要靠冗余(多备几台)→ 成本上升;高性能加缓存 → 一致性变难、复杂度上升;微服务让系统更可扩展 → 运维和排查的复杂度暴涨。
所以没有"完美架构",只有"最适合当前业务阶段的权衡"。脱离业务场景问"要不要上微服务""要不要上 K8s",其实很难有答案——基本都是"看情况"。所以搞懂一个架构,关键是看清它在为哪个目标、牺牲了什么代价。
二、为什么需要"设计"架构
为什么。 因为业务会增长,而系统要跟着长大。今天扛 100 个用户的写法,到 100 万用户时大概率会崩;架构决定了系统能不能平滑地跟上这个增长,而不是每翻一个量级就推倒重来。
不设计的代价很具体:单体代码堆到几十万行,改一行牵一发动全身,上线前总担心带崩别的模块;所有功能挤在一个进程里,一个不起眼的模块内存泄漏,能把整个系统一起拖下水;数据库一个慢查询,也能让全站跟着卡——而且这类线上事故,还特别爱挑凌晨来。
但反过来——过度设计是另一个坑,而且更隐蔽。一个日活几百的产品,一上来就上微服务、上 K8s、上消息队列,背上了一整套分布式的复杂度和成本,却没有任何与之匹配的流量。这就是著名的 YAGNI(You Aren't Gonna Need It,你并不会用到它)反面教材。
所以架构设计真正要做的,是匹配业务的当前阶段,既不滞后(扛不住)、也不超前(白烧钱),并给未来留好演进的空间。
三、AI 写代码越来越快,架构把关反而更值钱
补到这儿,可能有人(我自己一开始也犯过嘀咕)会想:AI 都能写代码了,还费劲学架构干嘛? 这事得正过来看。
现状是什么。 现在用 AI 写代码,几秒就生成一大段,能跑就想直接上线。但凡用 AI 写过东西的人大概都体会过:它写的代码"能跑",离"扛得住"还差一截——demo 跑得好好的,一上量、一上线,各种意想不到的 bug 就冒出来了。
为什么会这样。 因为 AI 特别擅长"局部正确":你让它写一个函数、一个接口,它大概率又快又对。但它默认只盯着你给的那一小段上下文,不会主动替你操心全局的那些事:
- 这段代码并发跑会不会出问题(超卖、脏数据)?
- 数据量大了会不会慢、会不会拖垮数据库?
- 依赖的下游挂了,它怎么办?
- 异常、边界情况兜住了吗?
- 有没有安全洞(越权、注入)?
这些恰恰不是"写代码"的问题,而是"架构设计"的问题。"能跑"和"扛得住"之间那段距离,基本就是架构——AI 默认不会替你想,除非你明确告诉它该考虑什么;而你得先自己懂,才说得出来。
于是带来一个反直觉的转变。 当"写代码"这件事变得越来越便宜,真正稀缺、也更值钱的,反而是另一种能力:做架构设计 + 给 AI 把关——知道这段东西上线会不会出事、哪里得约束它、该怎么 review。
业界正在形成的做法,大致是这样:
- 先设计、再让 AI 填。 由你来定:模块怎么拆、边界在哪、数据怎么流、关键路径(钱、库存)怎么保护——这就是架构;让 AI 在你搭好的框架里实现细节,而不是反过来让 AI 替你决定架构。
- review 盯"架构层",而不是"语法层"。 AI 生成的代码语法基本没错,真正要审的是:并发安全吗?一致性?错误处理?能不能扩展?有没有安全问题?——这些 AI 不会主动给你兜底。
- 一句话:AI 负责"把代码写出来",你负责"把系统设计对、把关住"。
这也是这个系列想补的东西:不是"怎么写代码"(那件事 AI 帮你做了一大半),而是"怎么把系统设计对、怎么判断什么地方会出事"。AI 越强,这种判断力反而越值钱——它能帮你写,但替你担责的还是你自己。
四、架构演进:每一步都在解决一个具体痛点
这是全文的骨架。一个互联网系统的架构,基本都沿着下面这条路长大——而且每一步,都是被一个具体的痛点逼出来的,不是为了"更高级"。
阶段 0 · 单体应用(All-in-One)。 创业初期:一个应用 + 一个数据库,部署在一台服务器上,所有功能(用户、订单、支付)都在一个进程里。优点是简单——开发快、部署快、排查直接。用户不多、团队就几个人时,这反而就是最优解。
痛点 1:用户变多,一台机器扛不住了。 → 先做应用与数据库分离(各占一台);还不够就上应用集群 + 负载均衡:部署多台一样的应用机,前面架一个负载均衡器(Nginx / LVS / 云 SLB)把请求分发下去。 → 新问题:多台机器之间,用户的登录态(session)放哪?(引出 session 共享 / 把状态放 Redis——正好接《缓存》篇讲的"短命数据主存储"。)
痛点 2:读请求太多,数据库先扛不住。 → 上缓存(热点数据放 Redis,挡住大部分读)+ 读写分离(一主多从,写主库、读从库,把读压力摊到多个从库)。 → 新问题:缓存和数据库的一致性、主从同步延迟——这些《缓存》篇和后面的高可用篇会展开。
痛点 3:数据量大到单表 / 单库装不下。 → 分库分表:把一张大表水平切成多张、甚至拆到多个库。 → 新问题:跨库查询怎么办、分布式事务怎么保证——留给"分布式"那个阶段。
痛点 4:单体代码膨胀,改不动、一处挂全挂、团队互相踩脚。 这才是上微服务的真正理由——不是因为微服务高级,而是单体的协作和稳定性成本扛不住了。 → 垂直拆分 / 微服务:按业务边界把单体拆成多个独立服务(用户服务、订单服务、支付服务),各自独立开发、部署、扩容。 → 新问题:服务之间怎么调用、怎么找到对方、一个挂了会不会连环拖垮——引出服务治理。
痛点 5:服务拆了几十个,调用关系乱成一团、部署运维成噩梦。(本来指望拆完更清爽,结果查一个 bug 要顺着调用链翻好几个服务的日志,反而比单体时候更让人头大。) → 服务治理 + 云原生:注册发现(服务自动找到彼此)、API 网关(统一入口)、链路追踪(《可观测性》篇)、容器化与编排(Docker + Kubernetes),再往上是服务网格(Istio)。 → 这一层解决的是"服务多了之后,怎么管得过来"。
这里能看出一个规律:每一步演进 = 解决上一步的痛点 + 引入新的痛点,而新痛点就是下一步(也是这个系列后面每一篇)要搞懂的。架构往往不是一开始设计出来的,是一个痛点一个痛点演进出来的。
五、业界怎么做的
主流演进范式。 上面这条路不是我编的,是几乎所有大型互联网系统都走过的公认路径:
单体 → 垂直拆分 → 分布式服务(SOA)→ 微服务 → 云原生(容器 / K8s / 服务网格)
每一层,业界都有成熟的开源主流方案,选型时大致认这些:
| 能力 | 业界主流方案 / 技术库 |
|---|---|
| 负载均衡 | Nginx、LVS、HAProxy、云厂商 SLB / ALB |
| 缓存 | Redis、Memcached |
| 微服务框架 | Spring Cloud(Java)、Dubbo、gRPC、Go-Zero / Kratos(Go) |
| 服务注册发现 | Nacos、Consul、etcd、Eureka |
| API 网关 | Spring Cloud Gateway、Kong、APISIX、Nginx |
| 配置中心 | Nacos、Apollo |
| 容器与编排 | Docker + Kubernetes |
| 服务网格 | Istio、Linkerd |
| 可观测 | Prometheus + Grafana、OpenTelemetry(见《可观测性》篇) |
但最重要的一条业界共识是:不是每个系统都要走到最后一步。绝大多数业务,单体 + 缓存 + 读写分离就能扛很久;真到了需要微服务的体量,你自然会被痛点推着走。技术大厂走完全程,是因为它们的流量和团队规模真到了那个量级;终点的架构,未必适合起点的业务。
六、注意事项
- 最常见的坑是过度设计。 没到那个体量就上一整套微服务 + K8s,有点像用大炮打蚊子——蚊子没打着,先把自己累趴。近几年业界甚至有"单体优先(Monolith First,Martin Fowler 提出)"的回潮:先用单体快速验证业务,真扛不住了再拆。YAGNI 也是这个意思——以为会用到的扩展性,八成用不到。
- 架构更多是演进出来的,不是一次设计到位的。 开局就想画出完美架构,往往不现实;满足当前阶段 + 预留演进空间,比"一步到位"更实际,也更省钱。
- 每个解法都有代价。 缓存换来快,代价是一致性;微服务换来灵活,代价是分布式复杂度;冗余换来高可用,代价是成本——所以引入一个方案前,值得先想想这笔代价划不划算。架构里没有"只有好处"的选择。
- 康威定律(Conway's Law):系统架构会长得像组织架构——团队怎么划分,服务往往就怎么拆。设计架构时,绕不开团队怎么协作这件事。
- 没有银弹。 脱离具体业务场景谈"哪个架构更好",没有意义。架构的全部功夫,就是针对你这个业务的当前痛点,选代价最划算的那个权衡。
七、一张表:架构演进路线(痛点 → 解法 → 新问题)
把全文收进一张表,这也是整个系列的"地图"——每一行的"新问题",基本就是后面一篇的主题:
| 业务阶段 | 痛点 | 架构解法 | 带来的新问题(后面解决) |
|---|---|---|---|
| 起步 | —— | 单体 + 单库 | —— |
| 用户变多 | 单机扛不住 | 应用集群 + 负载均衡 | 会话 / 状态放哪 |
| 读压力大 | 数据库读扛不住 | 缓存 + 读写分离 | 缓存一致性、主从延迟 |
| 数据量大 | 单表 / 单库装不下 | 分库分表 | 分布式事务、跨库查询 |
| 代码 / 团队膨胀 | 改不动、一处挂全挂 | 微服务拆分 | 服务治理、分布式复杂度 |
| 服务太多 | 调用乱、部署难 | 注册发现 / 网关 + 容器化 | 可观测、运维复杂度 |
名词解释
- 架构(Architecture):系统的骨架——模块怎么划分、怎么协作、数据怎么流动;本质是在多个目标间做权衡。
- 非功能性需求:功能之外、决定系统"扛不扛得住"的指标:性能、可用性、可扩展性、可维护性、安全、成本。
- trade-off(权衡):在互相冲突的目标间取舍——架构设计的核心动作。
- 可用性(几个 9):系统正常运行时间的比例,如 99.99%(全年宕机不超过约 53 分钟)。
- 单体应用(Monolith):所有功能打包在一个进程 / 一个部署单元里的应用。
- 负载均衡(Load Balancing):把请求分发到多台机器,常见 Nginx / LVS / 云 SLB。
- 读写分离:写主库、读从库(一主多从),把读压力摊到多个从库;主从同步有延迟。
- 分库分表:把数据水平拆到多张表 / 多个库,解决单表单库容量瓶颈。
- SOA / 微服务:按业务边界把系统拆成多个独立部署、独立扩容的服务。
- 服务注册与发现:服务启动时注册自己、调用方动态查到对方地址,常见 Nacos / Consul / etcd。
- API 网关:所有外部请求的统一入口,承担路由、鉴权、限流等,常见 Kong / APISIX / Spring Cloud Gateway。
- 容器编排 / Kubernetes(K8s):自动化部署、扩缩容、调度容器的平台。
- 服务网格(Service Mesh):把服务间通信、治理能力下沉到基础设施层(如 Istio)。
- 康威定律(Conway's Law):系统架构倾向于映射组织的沟通结构——团队怎么分,服务就怎么拆。
- YAGNI / 单体优先:别为"以后可能用到"的需求过度设计;先用单体跑通业务,真扛不住再拆。
本文是《研发都要懂的事》·服务端架构设计系列开篇——建立全局地图。后面逐阶段深入:高并发三板斧、高可用、微服务拆分、分布式事务……每一篇都对应上面那张表里的一个"新问题"。完整代码与系列在 GitHub · backend-notes。
评论(0)
登录后参与评论。
还没有评论,来抢沙发吧。

