后端架构演进:从单体到云原生的实战历程
我是一个后端开发出身的架构师,从业十多年,经历过多个大型系统的搭建和重构。今天想跟大家聊聊一个我们团队过去几年亲历的一次架构大迁徙——从传统的单体架构一步步演化到如今成熟的云原生体系。
这不是一次“高大上”的纸上谈兵,而是一场真实发生在某电商平台项目中的技术跃迁。在这个过程中,我们踩过不少坑,也收获了宝贵的经验。希望这篇文章能让你少走弯路。
起点:单体架构的甜蜜与痛苦

2017年,我加入一家初创电商公司。当时整个平台是典型的单体结构,前端、订单系统、支付模块、库存逻辑全部打包在一个Spring Boot应用中。MySQL作为唯一数据库,Redis做缓存,部署在两台阿里云ECS实例上。
一开始一切都很好,开发效率高,调试方便,上线流程简单。但随着用户量增长和功能迭代加速,这套架构开始暴露出一系列问题:
- 版本更新风险高:每次发布一个小功能都要重新编译部署整个服务,一旦出错影响全站。
- 性能瓶颈突出:高峰期订单服务一慢,整个应用都卡住。
- 数据库压力巨大:所有读写都集中在同一张数据库表上,分库分表成为当务之急。
- 团队协作困难:多个小组并行开发,代码频繁冲突,上线排期混乱。
最严重的一次事故是因为支付接口出现偶发延迟,导致整个服务雪崩式瘫痪。那次故障整整持续了3小时,损失惨重。也正是从那以后,我们意识到架构改造势在必行。
微服务拆分:从“全家桶”到“模块化”

我们决定采用微服务架构。第一步是根据业务边界进行服务拆分:
- 订单系统独立出来(Order Service)
- 支付抽象为单独服务(Payment Service)
- 用户、权限、积分整合为User Center
- 商品信息、类目管理拆成Product Service
- 新增API网关统一入口
- 数据库按照服务边界进行物理隔离
这个阶段我们使用了Spring Cloud生态的技术栈:
- Spring Cloud Gateway 做网关路由
- Nacos 做注册中心和服务发现
- Feign + Ribbon 实现服务间通信
- Sentinel 控制熔断降级
- Zipkin 做分布式链路追踪
拆完之后最大的感受就是两个字:清爽。
每个服务可以独立部署、独立升级,团队之间也不再相互牵制。而且数据库隔离后,SQL优化工作变得清晰有重点了。比如我们在订单服务中将冷热数据分离,把半年前的历史订单迁移到单独的从库,大幅提升主库查询速度。
不过这里也有一个教训要分享给大家:初期我们拆得太细,有些服务之间的调用非常频繁,反而带来了额外的网络开销和复杂度。后来我们进行了服务合并调整,控制服务数量在可控范围内,保持服务边界的合理性。
服务治理:让微服务不再“野蛮生长”

微服务多了以后,新的挑战又来了。
服务注册/发现经常不稳定,有时候一个节点宕机,Nacos没能及时感知,请求还在往故障节点转发;服务间调用链太长,排查问题需要查很多日志;还有突发流量导致某个服务突然被压垮,其他依赖它的服务跟着崩溃。
于是我们逐步引入了一系列服务治理机制:
1. 熔断限流(Sentinel)
我们在各个关键接口上配置了QPS限流规则,比如订单创建接口每秒不超过5000次。同时设置了基于错误率的自动熔断机制,当某接口失败率达到一定阈值时自动拒绝后续请求,防止雪崩效应。
有一段时间促销活动期间,优惠券服务因为数据库锁表响应变慢,订单服务调用它的地方就触发了熔断保护,保证了订单核心流程不受影响。
2. 链路追踪(SkyWalking + ELK)
我们集成了SkyWalking来做分布式链路追踪,通过Trace ID串联起整个调用过程。结合ELK收集日志,遇到问题可以直接定位到哪一层出了异常。
有一次支付回调接口异常,原本需要十几分钟排查,用了链路追踪之后三分钟就知道是下游回调通知超时引起的。
3. 配置中心(Alibaba ACM)
之前我们的配置都是写在application.yml里,环境切换、参数修改特别麻烦。引入ACM之后,可以动态推送配置变更,不需要重启服务就能生效。
举个例子:在一次灰度上线中,我们只需要在配置中心临时打开新特性开关,只对部分用户开放测试,极大降低了上线风险。
这些工具的应用让我们对微服务有了更强的掌控力,也为后续向云原生迁移打下了基础。
拥抱云原生:走向弹性与自动化

2021年前后,我们开始全面拥抱云原生架构。
之所以这么做,主要是出于以下几个考虑:
- 业务需求变化快,传统运维跟不上节奏
- 资源利用率低,闲置浪费严重
- 缺乏弹性伸缩能力,大促时常有资源告急
- 多云管理复杂,缺乏统一标准
我们采用了以下方案:
容器化 & K8s 集群
我们将所有服务镜像化,并通过阿里云ACK(Kubernetes)集群进行编排部署。这一步其实最难的是CI/CD流程的打通。
我们最终采用Jenkins+ArgoCD的组合,实现从代码提交到自动构建、自动部署流水线。现在基本可以做到每天多次发布的频率,稳定性还比以前手动发布更高。
服务网格(Istio)
虽然我们没有一开始就上Istio,但在服务数量超过30个之后,为了更好地做流量管理和安全策略控制,我们选择了Istio作为服务网格解决方案。
通过VirtualService做蓝绿发布、金丝雀发布变得轻松许多。我们可以先让5%的流量进入新版本,观察一段时间没问题后再逐步扩大比例。
另外,我们也在Istio中集成了JWT鉴权插件,在网关层统一处理身份认证,减少了服务内部的安全校验负担。
Serverless 探索
对于一些偶发任务型的服务,比如异步通知、数据统计等,我们也尝试了一些Serverless方案,比如阿里云函数计算FC。
这部分还在试验阶段,但我们已经尝到了按需付费、免运维的好处。未来会考虑将更多轻量服务迁移到Serverless平台上。
数据库设计与演变
在架构演进过程中,数据库的变化同样重要。
早期单体架构时期,我们只有一套主从MySQL,随着数据量增大,逐步做了以下调整:
分库分表
我们使用了ShardingSphere来实现水平切分。将订单按用户ID哈希分布到4个物理库,每个库下又有多个分表。这样既提升了读写性能,又避免了单表过大带来的查询延迟。
有个小故事:当年我们刚开始做分库的时候,有个服务忘了改查询逻辑,结果同一个查询语句跑了8个库才找到正确的数据……后来我们就强制要求所有查询必须带上分片键,否则直接报错。
异构数据同步
为了减轻主库压力,我们将部分非实时性的报表分析逻辑转移到ClickHouse,使用DataX定时同步数据。同时借助Canal订阅MySQL Binlog,实现了订单数据的准实时搜索支持。
数据一致性保障
在分布式场景下,数据一致性是个大问题。我们采用了本地事务消息表+事务补偿的方案,在订单创建成功后发送一条消息,由下游服务消费并确认状态。如果确认失败,会有定时任务进行对账补偿。
这一块我们走过不少弯路,后来总结下来:
“强一致性很难,但合理设计+良好的监控机制=最终一致性。”
上线后的效果
到现在整个系统已经稳定运行近两年,支撑了上百个服务、百万级并发访问。主要收益如下:
| 维度 | 效果 |
|---|---|
| 系统可用性 | 平均99.95%,相比之前提升3个点 |
| 发布效率 | 日常变更平均耗时从40分钟降至5分钟以内 |
| 故障隔离 | 单服务异常不会影响其他服务 |
| 成本控制 | 基于K8s的弹性伸缩使服务器成本下降约35% |
| 技术债务 | 架构清晰,便于后续扩展和维护 |
我的一些心得体会
如果你也正准备或者正在经历类似的架构演进,我想分享几点亲身经验:
不要追求最新技术,适合的才是最好的
我见过太多人为了炫技而引入一堆新技术,最后根本无法驾驭。选型前一定要评估团队的能力匹配度。做好监控和可观测性
不管是Prometheus还是SkyWalking,建立完善的监控体系至关重要。别等到出了问题才发现没埋点。先搭骨架,再填细节
架构演进不能一口吃成胖子。建议先完成核心服务拆分,跑通CI/CD流程,再逐步完善周边设施。文档一定要跟上
微服务多了以后如果没有清晰的服务目录和技术文档,新人进来根本无从下手。重视团队培训和知识共享
每周组织一次“微服务共读”,大家一起分析线上问题,共同成长。永远保留回滚能力
每一次重大变更我们都至少保留两种版本的部署包,确保能快速回退。这是血泪教训换来的。关注生产运维体验
我们专门搞了一个“运维工具箱”项目,集成一键重启、日志下载、指标查看等功能,极大提高了问题排查效率。
写在最后

这几年的经历让我深刻理解了一句话:架构不是设计出来的,而是进化出来的。
每一个架构选择的背后,都是现实世界的问题驱动。从最初的单体焦虑,到微服务的“兴奋期”,再到冷静下来的云原生实践,这条路走得不容易,但也充满收获。
如果你问我:“现在的架构是不是最优?”我会说:“它只是目前最适合我们业务发展的阶段解。”
技术和业务始终在变化,唯有不断学习、保持灵活的心态,才能走得更远。
欢迎你在评论区交流你的架构经验和想法,也希望这篇真实的分享能给你带来启发。

评论 0