初识后端架构:为什么我们需要架构设计?
2021年618大促前一周,刚入职某电商公司两年的后端开发小周盯着满屏的订单模块代码直挠头。这个原本只支撑日活1万的小程序订单系统,在他手里已经被改了七轮:先加了拼团功能,又加了预售定金膨胀,最近还要接直播带货的订单同步逻辑。所有代码都塞在同一个OrderController里,查商品库存、算优惠折扣、扣减库存、生成订单、调用支付、发送短信通知,近两千行代码嵌套了五六层if-else,上周刚因为改优惠逻辑把库存扣减的代码改崩,导致超卖了200多单,运营团队忙活了三天才安抚完用户,CTO在项目复盘会上扔下句话:“到底是业务太烂,还是你们的架构太烂?”
这样的场景你是不是很熟悉?很多刚入行的开发甚至工作三五年的工程师,都觉得“架构”是架构师才需要考虑的高大上概念,是互联网大厂的专属,和自己每天写的CRUD没关系。但实际上,你写的每一段代码、做的每一个技术选型、甚至每次提交代码的结构,本质上都是架构的一部分——糟糕的架构会让你每天加班改bug,上线前提心吊胆;而合理的架构能让你在业务快速迭代的时候游刃有余,甚至不用加班也能按时交付。
本章将带你从零建立后端架构的认知体系,首先明确架构设计的核心目标,梳理从单体到云原生的完整演进逻辑,澄清你对“架构”的常见误解,最后给出适配不同业务阶段的架构选型方法,帮你建立“没有最好的架构,只有最适合的架构”的核心认知,这也是本书贯穿始终的核心观点。
一、到底什么是架构设计?它的核心目标是什么?
1.1 先澄清一个误区:架构不是“画出来的”,是“做出来的”
很多新手对架构的第一印象是架构师画的各种框图:有业务架构图、技术架构图、数据架构图、部署架构图,觉得架构就是把这些图画得好看、够复杂。但实际上,架构的本质是为了解决特定问题而做出的一系列技术决策的集合,它的最终落地形态就是你每天写的代码、用的框架、部署的服务器、甚至运维的流程。
举个最简单的例子:你要做一个个人博客,如果你用PHP+MySQL把所有逻辑写在一个文件里,部署在一台虚拟主机上,这就是最简单的架构;如果你用Java+Spring Boot把博客拆成用户、文章、评论三个模块,部署在三台服务器上,用Nginx做负载均衡,这就是相对复杂一点的架构。这两种架构没有好坏之分,只要能满足你的需求(比如博客日活只有几百,第一种架构完全够用),就是合理的架构。
> 📌 【侧边栏:架构的三个核心属性】 > 1. 针对性:架构永远是为业务场景服务的,不存在通用的“最优架构” > 2. 权衡性:架构设计本质上是各种 trade-off(权衡),比如要高性能就要牺牲一定的可扩展性,要高可用就要增加成本 > 3. 演进性:架构不是一成不变的,会随着业务的发展不断调整
1.2 架构设计的四大核心目标
不管你是做单体架构还是微服务架构,架构设计的最终目标都可以归纳为四个:高可用、高性能、可扩展、可维护,这四个目标不是孤立存在的,往往需要根据业务场景做权衡。
1.2.1 高可用:系统不能随便挂
高可用(High Availability,简称HA)是架构设计的首要目标,它的核心是保证系统在大部分时间里都能正常对外提供服务。我们通常用“可用性”来衡量系统的高可用程度,计算公式是: $$可用性 = \frac{全年系统正常运行时间}{全年总时间}$$
现在主流互联网系统的可用性要求是99.99%(俗称4个9),也就是全年 downtime(故障时间)不超过52分钟;如果是支付、金融这类核心系统,要求会更高,达到99.999%(5个9),全年 downtime 不超过5分钟。
高可用的实现手段有很多,比如:
- **冗余部署**:把系统部署在多台服务器上,一台挂了其他还能用,就像你家里的电路,一个灯泡坏了其他电器还能正常工作
- **故障转移**:当某台服务器出问题的时候,自动把流量切到正常的服务器上,不用人工干预
- **熔断降级**:当某个服务出问题的时候,自动切断对它的调用,返回降级结果(比如推荐服务挂了,就返回热门商品列表),避免整个系统被拖垮
举个实际的例子:2022年某头部支付平台曾出现持续2小时的故障,导致用户无法付款、商家无法收款,直接损失超过2亿元,还影响了平台的品牌口碑。如果这个平台的可用性只有99%(全年 downtime 超过87小时,相当于3天半不能用),这样的故障每年至少会出现十几次,根本不可能支撑现在的业务规模。
1.2.2 高性能:响应速度要快
高性能的核心是保证系统的响应速度满足用户 expectations(预期)。根据谷歌的统计,移动端页面的加载时间超过2秒,53%的用户会直接关闭页面;如果是电商、内容类产品,用户对响应速度的要求更高,通常要求接口响应时间控制在200ms以内,页面加载时间控制在1秒以内。
高性能的实现手段同样有很多,比如:
- **缓存**:把热点数据存在内存里,不用每次都查数据库,比如淘宝的商品详情页,90%的请求都是走缓存,响应时间从几百ms降到几十ms
- **异步处理**:把非核心逻辑异步化,比如用户下单之后发短信、发通知,不用等这些逻辑执行完就返回结果给用户,响应时间可以从几百ms降到几十ms
- **索引优化**:给数据库的查询字段加索引,把查询时间从几秒降到几ms
再举个例子:抖音的短视频加载时间如果超过1秒,用户的留存率会下降30%以上,所以抖音在性能优化上投入了大量的资源,包括边缘缓存、CDN加速、视频预加载等技术,就是为了保证用户刷视频的时候没有任何卡顿。
1.2.3 可扩展:业务涨了不用推翻重做
可扩展的核心是当业务规模增长、需求变更的时候,不用对系统做推翻性的改造,只需要小范围调整就能满足需求。很多初创公司刚起步的时候觉得“先做出来再说,以后再说扩展的事”,结果业务稍微起色,就要推翻整个系统重写,浪费大量的时间和金钱。
可扩展的实现核心是“解耦”,比如:
- **模块化拆分**:把不同的业务逻辑拆成独立的模块,加新功能的时候只要加新的模块,不用改老的代码
- **接口抽象**:模块之间通过接口通信,不用关心对方的实现细节,比如支付模块要接微信支付还是支付宝,只要改支付模块的实现,不用改订单模块的代码
- **水平扩展**:当服务器扛不住流量的时候,只要加机器就行,不用改代码,比如单体架构可以通过加机器部署多个实例,用负载均衡分担流量
举个反例:某生鲜电商2020年疫情的时候,日活从10万突然涨到1000万,因为原来的架构没有考虑可扩展,只能重新做整个系统,耽误了3个月的业务窗口期,损失了至少2亿元的营收。如果当时做了合理的模块化拆分,只要加机器、做缓存优化就能扛住流量,根本不用重写系统。
1.2.4 可维护:改代码不用提心吊胆
可维护的核心是当系统出现问题、或者需要加新功能的时候,开发人员能快速定位问题、修改代码,不会出现“改一处崩三处”的情况。根据国内某技术社区2023年的调研,超过60%的研发成本是花在系统维护和迭代上的,如果代码可维护性差,改一个功能的时间是合理架构的3倍以上,研发效率会非常低。
可维护的实现手段包括:
- **代码规范**:统一的编码风格、注释规范,新人来了能快速看懂代码
- **自动化测试**:单元测试、集成测试、回归测试,改代码的时候能快速发现有没有引入问题
- **可观测性**:日志、监控、链路追踪,出问题的时候能快速定位是哪个模块出的问题
- **文档完善**:架构文档、接口文档、运维文档,不用靠“老员工口口相传”
举个实际的例子:某电商公司的订单系统,因为历史原因没有文档,也没有测试,核心代码只有一个老员工懂,后来这个老员工离职了,新员工改个小的优惠逻辑,改了3个月还没改完,每次改完都出问题,最后只能花大价钱把这个老员工请回来做顾问,损失了至少上百万元的人力成本。
> 📌 【侧边栏:四大目标的权衡】 > 架构设计不是要把四个目标都做到100分,而是要根据业务场景做权衡。比如个人博客,可维护性要求高一点,高可用、高性能的要求可以低一点;而支付系统,高可用、高性能的要求是第一位的,可扩展、可维护的要求可以适当让步。
二、后端架构的演进历程:业务发展倒逼技术迭代
很多人觉得架构演进是技术潮流推动的,今天流行单体就用单体,明天流行微服务就上微服务,但实际上,架构演进的核心驱动力永远是业务发展的需求,技术只是实现业务目标的工具。我们梳理一下过去20年后端架构的演进历程,你会发现每一次架构变革的背后,都是业务规模扩大、复杂度提升带来的必然结果。
2.1 早期单体架构:业务简单时期的“最优解”
单体架构(Monolithic Architecture)是早期后端架构的主流形态,它的核心特点是把所有业务模块打包成一个应用,部署在一台或者多台相同的服务器上。比如2000年左右的个人站长做论坛,用PHP+MySQL把所有逻辑(用户注册、发帖、评论、后台管理)都写在一个项目里,上传到虚拟主机就能跑,这就是典型的单体架构。
单体架构的优势非常明显:
- **开发简单**:所有代码都在一个项目里,调试、开发都不用跨模块调用,新手也能快速上手
- **部署简单**:只要打包成一个war包或者jar包,上传到服务器就能跑,不用考虑多个模块之间的依赖
- **成本低**:只需要一台服务器就能跑,运维成本几乎为零
在业务规模小、团队人数少的阶段,单体架构是绝对的最优解。比如淘宝2003年刚上线的时候,就是典型的单体架构,用PHP编写,所有功能都打包在一个项目里,部署在一台服务器上,当时日活只有几千,完全够用。
但随着业务规模扩大,单体架构的痛点就会越来越明显:
- **迭代效率低**:所有模块都在一个项目里,每次上线都要重新打包部署整个应用,上线时间从几分钟变成几十分钟,甚至几小时,很容易出现上线故障
- **扩展性差**:当某个模块成为瓶颈的时候,只能把整个应用部署多份,浪费资源,比如订单模块是瓶颈,用户模块没压力,但是也要跟着一起扩容
- **稳定性差**:任何一个模块出bug,都会导致整个系统崩溃,比如商品模块的bug会导致用户连订单都下不了
- **技术栈受限**:所有模块只能用同一种技术栈,比如原来用PHP,后来想用Java做高性能模块,根本做不到
2008年淘宝日活突破1000万的时候,单体架构的痛点已经完全无法支撑业务发展,每次上线都要停机几个小时,故障频发,淘宝才开始了第一次架构变革,从单体架构拆成分布式架构。
2.2 分布式架构:解决单体瓶颈的“分而治之”
分布式架构的核心思想是把单体应用拆成多个独立的模块,每个模块部署在不同的服务器上,模块之间通过网络调用通信。淘宝最早的分布式改造就是把商品、用户、订单、支付这些核心模块从单体应用里拆出来,独立部署在不同的服务器上,每个模块有独立的数据库,这就是典型的分布式架构。
分布式架构的优势是:
- **迭代效率提升**:每个模块可以独立迭代、独立部署,不用再等整个应用打包上线,上线时间从几小时降到几分钟
- **扩展性提升**:哪个模块是瓶颈就扩容哪个模块,不用整个应用一起扩容,节省服务器成本
- **稳定性提升**:某个模块出问题,不会影响其他模块,比如商品模块出问题,用户还是能看订单、付款
- **技术栈灵活**:每个模块可以用适合自己的技术栈,比如订单模块对性能要求高,可以用Java,运营后台对开发效率要求高,可以用Python
但分布式架构也带来了新的问题:
- **调用复杂度提升**:原来下单只需要调用本地方法,现在要调用用户、商品、库存、优惠、支付等多个远程服务,一旦某个服务出问题,整个流程就会卡住
- **数据一致性难保证**:数据分散在不同的数据库里,要保证多个服务之间的数据一致非常困难,比如下单的时候扣了库存,但是订单没生成,就会超卖
- **运维成本提升**:从部署一个应用变成部署几十个应用,监控、排查问题的难度提升了好几个数量级
- **分布式问题频发**:网络延迟、网络分区、服务雪崩这些单体架构下不会出现的问题,现在都要处理
2010年左右,国内互联网公司基本都完成了从单体到分布式的改造,分布式架构成了主流,但随着业务继续发展,分布式架构的痛点也越来越明显:服务数量越来越多,服务之间的依赖关系越来越复杂,一个小问题要排查好几个小时,运维团队天天救火,开发效率不升反降。
2.3 微服务架构:分布式架构的“精细化升级”
微服务架构(Microservices Architecture)是2014年由Martin Fowler和James Lewis正式提出的概念,它的核心是在分布式架构的基础上,把服务拆得更细,每个服务只负责一个独立的业务域,独立开发、独立部署、独立迭代,服务之间通过轻量级的通信机制(比如HTTP、RPC)交互。
比如现在的美团,把外卖业务拆成了商家服务、配送服务、用户服务、订单服务、支付服务、营销服务等几十个微服务,每个服务由独立的小团队负责,团队可以自主决定技术栈、迭代节奏,不用和其他团队协调,开发效率提升了很多。
微服务架构相比分布式架构的优势是:
- **团队协作效率更高**:每个小团队负责一个或几个微服务,不用协调多个团队的排期,迭代速度更快
- **服务更聚焦**:每个微服务只负责一个业务域,代码量更少,逻辑更清晰,维护成本更低
- **弹性更灵活**:可以根据每个服务的压力单独扩缩容,比如大促的时候只扩容订单、支付这些核心服务,不用扩容所有服务
- **故障隔离更好**:某个微服务出问题,只要做熔断降级,不会影响其他服务
但微服务架构也不是“银弹”,它带来的问题比分布式架构更复杂:
- **服务治理难度大**:服务数量从几十个变成几百个,要解决服务注册发现、负载均衡、熔断降级、链路追踪、配置管理等一系列问题,需要专门的团队来做服务治理
- **分布式问题更严重**:服务数量多了之后,分布式事务、数据一致性、网络问题的概率更高,解决成本也更高
- **运维成本指数级上升**:从部署几十个服务变成部署几百个服务,需要容器、K8s、自动化运维等技术的支撑,对运维团队的能力要求非常高
- **开发成本高**:每个服务都要做监控、日志、测试,开发一个微服务的成本是开发一个单体模块的3倍以上
很多中小公司盲目跟风上微服务,结果团队只有十几个人,业务还没起来,就先花了几个月时间搞微服务基础设施,最后开发效率比原来用单体的时候还低,完全得不偿失。根据2023年国内某云厂商的调研,超过60%的微服务落地项目都出现了“过度设计”的问题,完全没有达到预期的效果。
2.4 云原生架构:微服务的“自动化升级”
云原生(Cloud Native)是2015年CNCF(云原生计算基金会)提出的概念,它的核心是基于容器、K8s、服务网格、可观测等云原生技术,让微服务实现自动化部署、自动化扩缩容、自动化运维,进一步提升系统的弹性和研发效率。
云原生架构的核心技术包括:
- **容器化**:把每个微服务打包成容器镜像,保证开发、测试、生产环境的一致性,不会出现“在我电脑上能跑”的问题
- **K8s编排**:用K8s自动化管理容器的部署、扩缩容、故障转移,不用人工干预
- **服务网格**:把服务治理的逻辑(比如熔断、限流、链路追踪)从业务代码里剥离出来,由Sidecar代理处理,业务开发不用关心服务治理的逻辑
- **可观测体系**:统一的日志、监控、链路追踪体系,出问题的时候能快速定位
云原生架构的优势是:
- **弹性能力强**:可以根据流量自动扩缩容,比如大促的时候流量涨10倍,自动加10倍的服务器,流量降了又自动缩回去,不用人工干预,节省大量的服务器成本
- **研发效率高**:容器化保证了环境一致性,CI/CD流水线实现了自动化测试、自动化部署,从代码提交到上线只要几分钟
- **运维成本低**:K8s自动化管理容器,不用人工运维服务器,运维团队可以从繁琐的部署工作中解放出来
但云原生架构的门槛非常高,需要团队具备容器、K8s、服务治理、可观测等多项技术能力,中小公司如果没有足够的研发和运维资源,盲目上云原生反而会拖累业务。
> 📌 【侧边栏:架构演进的本质】 > 从单体到分布式到微服务到云原生,架构演进的核心从来不是技术本身,而是业务发展的需求: > - 业务简单、团队小的时候,单体架构足够 > - 业务变复杂、团队变大的时候,需要分布式架构解决单体瓶颈 > - 业务快速迭代、团队规模更大的时候,需要微服务架构提升协作效率 > - 业务规模很大、对弹性要求高的时候,才需要云原生架构降本增效 > 如果脱离业务谈架构,就是耍流氓。
2.5 架构演进的完整脉络
为了帮你更直观地理解后端架构的演进逻辑,我们可以用下面的流程图梳理每个阶段的驱动力、核心特点、典型痛点和适用场景:
```mermaid graph LR A[早期单体架构<br>驱动力:业务简单、技术栈单一、团队<10人<br>核心特点:所有模块打包部署、单数据库<br>典型痛点:迭代慢、扩展难、稳定性差<br>适用场景:个人项目、创业公司验证期、工具类系统] --> B[分布式架构<br>驱动力:业务复杂度提升、性能瓶颈
```mermaid graph LR A[早期单体架构<br>驱动力:业务简单、技术栈单一、团队<10人<br>核心特点:所有模块打包部署、单数据库<br>典型痛点:迭代慢、扩展难、稳定性差<br>适用场景:个人项目、创业公司验证期、工具类系统] --> B[分布式架构<br>驱动力:业务复杂度提升、性能瓶颈凸显、团队10-50人<br>核心特点:模块拆分独立部署、分库分表<br>典型痛点:调用复杂、数据一致性难保证、运维成本上升<br>适用场景:业务稳定期、中大型互联网公司核心系统] B --> C[微服务架构<br>驱动力:业务快速迭代、团队规模>50人、协作效率需求高<br>核心特点:按业务域拆分、独立迭代部署、轻量级通信<br>典型痛点:服务治理复杂、分布式问题频发、运维成本指数级上升<br>适用场景:大型互联网平台、多业务线并行的公司] C --> D[云原生架构<br>驱动力:业务规模超千万级日活、弹性需求高、降本增效需求强<br>核心特点:容器化、K8s编排、服务网格、可观测体系<br>典型痛点:技术门槛高、人才成本高、转型周期长<br>适用场景:超大规模互联网公司、金融/支付等核心系统] style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#9f9,stroke:#333,stroke-width:2px style C fill:#99f,stroke:#333,stroke-width:2px style D fill:#ff9,stroke:#333,stroke-width:2px ```
2003年淘宝刚上线的时候,全站代码只有不到10万行,用P