微服务架构设计实战:从单体到分布式
北京地铁14号线,晚高峰。我一边被挤在门边啃着冷掉的煎饼果子,一边刷着手机里的微服务文章——这大概就是当代安全工程师的真实写照。
大家好,我是小安,一个在北京某中型互联网公司“搬砖”的安全工程师。平时主要和漏洞、渗透测试、WAF规则打交道,但去年因为公司业务暴涨(老板说这是“幸福的烦恼”),我们不得不把那个运行了五年的单体应用拆成微服务。说实话,一开始我是拒绝的——毕竟我的K8s知识还停留在kubectl get pods阶段,但领导一句“你不是天天吹云原生吗?正好练练手”,直接把我推上了火线。
更扎心的是,那会儿我正偷偷准备跳槽,简历上写了“熟悉微服务架构”,结果连Spring Cloud Config都没配过……为了不被打脸,只能硬着头皮上。今天这篇文章,就是我在血泪教训中总结出的微服务拆分实战经验,希望能帮到正在求职或被迫重构的兄弟们。
起因:那个压垮我们的“巨石”
故事要从去年双11说起。
我们的核心系统是一个基于 Spring Boot 的单体应用,用的是经典的三层架构:Controller → Service → Mapper。数据库是 MySQL 主从,缓存 Redis,部署在几台物理机上。平日里跑得还挺稳,但一到大促,用户量一上来,整个系统就“优雅地”崩了。
最惨的一次,凌晨2点,报警电话把我从梦中拽醒:“支付模块挂了!” 我打开监控一看,CPU 100%,GC 停顿长达5秒,线程池打满。运维老王在群里咆哮:“又是那个破订单查询接口!谁写的全表扫描?!” —— 那个接口,其实是我三年前手抖写的,现在想改?动一发而牵全身。
产品经理还在群里补刀:“能不能只让支付模块扩容?其他模块不用啊。”
我内心OS:大哥,这是个单体啊!你让我怎么单独扩?
那一刻,我知道,单体架构已经成了业务增长的瓶颈,也成了我简历上的“技术债”。于是,微服务改造,提上日程。
拆!但别乱拆
很多人一听到微服务,第一反应是“按功能模块拆”。听起来很对,但实际操作起来,坑比代码还多。
我们最初也犯了这个错:把用户、商品、订单、支付全拆成独立服务。结果上线第一天,一个简单的下单流程要调用5个服务,网络延迟叠加,用户体验直接变“PPT”。测试小姐姐怒吼:“这比单体还慢!你们是不是在摸鱼?”
后来我们重新梳理业务边界,遵循 DDD(领域驱动设计) 的思想,以业务能力而非技术模块为单位拆分:
- 用户中心:注册、登录、个人信息
- 商品服务:商品管理、库存
- 交易服务:下单、支付、状态流转(注意:这里把订单和支付合并在一个上下文,避免跨服务事务)
- 通知服务:短信、邮件、站内信
📌 关键原则:高内聚、低耦合。同一个业务流程尽量在一个服务内闭环,减少跨服务调用。
我们甚至画了一张“依赖图”,用不同颜色标记强依赖和弱依赖。结果发现,原来的“订单服务”居然依赖了7个其他模块——怪不得一改就崩!
技术栈选型:Spring Boot 是底线
既然是 Java 系,Spring Boot 自然是首选。但微服务不只是换个框架那么简单,配套生态才是难点。
我们最终定下的技术栈如下:
| 组件 | 选型 | 理由 |
|---|---|---|
| 服务框架 | Spring Boot 2.7 + Spring Cloud 2021.0.5 | 社区成熟,文档丰富,团队熟悉 |
| 服务注册发现 | Nacos | 支持配置中心+服务发现,比 Eureka 功能更全 |
| 服务调用 | OpenFeign + Ribbon | 声明式调用,配合熔断更优雅 |
| 熔断限流 | Sentinel | 阿里开源,支持实时监控和动态规则 |
| 分布式追踪 | SkyWalking | 无侵入,APM 能力强 |
| 配置中心 | Nacos Config | 和注册中心一体化,减少运维负担 |
| 容器化 | Docker + K8s | 运维要求,也是简历加分项 |
💡 求职小贴士:如果你在准备面试,Spring Boot + Spring Cloud + Nacos 这套组合拳一定要会。大厂不一定用,但中小厂基本是标配。
数据库拆分:最难啃的骨头
代码拆了,服务拆了,但数据库还是一个——这叫“伪微服务”。
真正的挑战在于数据一致性。比如下单时,要扣库存、创建订单、记录日志,原来在一个事务里搞定,现在分散在三个服务,怎么办?
我们试过几种方案:
1. 分布式事务(Seata)
理论很美,实践很痛。Seata 的 AT 模式要求所有表有 undo_log,而且性能损耗不小。压测时 TPS 直接掉30%。果断放弃。
2. 最终一致性(消息队列)
这才是生产环境的“亲儿子”。我们用 RabbitMQ + 本地事务表:
// 下单服务
@Transactional
public void createOrder(Order order) {
// 1. 本地事务:扣库存(调用商品服务API,失败则抛异常)
inventoryClient.decrease(order.getProductId(), order.getCount());
// 2. 保存订单
orderRepository.save(order);
// 3. 发送MQ消息(异步)
rabbitTemplate.convertAndSend("order.created", order.getId());
}
商品服务收到消息后,再做后续处理(如更新销量)。如果失败,MQ 会重试,配合死信队列兜底。
⚠️ 注意:MQ 消息必须幂等!我们给每条消息加了唯一 ID,消费前先查 DB 是否已处理。
3. 数据库垂直拆分
每个服务拥有自己的数据库,彻底解耦。但带来了新问题:跨库查询。比如“用户订单列表”,既要用户信息又要订单信息。
解决方案:
- 应用层聚合(简单但性能差)
- 冗余字段(订单表冗余用户名,用 MQ 同步)
- CQRS 架构(读写分离,复杂但灵活)
我们选择了冗余+MQ同步。虽然牺牲了一点一致性(最终一致),但换来了查询性能的大幅提升。
安全不能忘:微服务的“暗坑”
作为安全工程师,我必须吐槽:很多团队拆微服务时,完全忽略了安全边界!
以前单体时代,一个 WAF 就能挡住所有攻击。现在几十个服务暴露在外,攻击面指数级增长。
我们踩过的坑:
- 服务间未鉴权:A 服务直接调 B 服务,没做身份校验。黑客一旦攻破 A,就能横向移动。
- 敏感信息泄露:Nacos 配置中心默认没开权限,导致数据库密码被实习生看到。
- 日志脱敏缺失:用户手机号、身份证号直接打到日志,合规风险拉满。
解决方案:
- 服务网格层鉴权:我们在 K8s 上用了 Istio,通过 mTLS 实现服务间双向认证。
- 配置加密:Nacos 开启权限,并用 Jasypt 对敏感配置加密:
spring: datasource: password: ENC(abc123...) # 加密后的密码 - 全局日志脱敏:自定义 Logback 的
Converter,自动过滤手机号、身份证等字段。
🛡️ 记住:微服务不是“拆完就完”,安全左移才是王道。
运维与可观测性:别让服务“失联”
上周五晚上,我正准备下班,突然收到告警:“交易服务500错误率飙升!”
打开日志一看,全是 FeignException: Read timed out。
查了半天,原来是商品服务的某个接口慢了,导致 Feign 调用超时,连锁反应炸了整个链路。
这就是微服务的经典问题:雪崩效应。
我们赶紧上了三板斧:
- Sentinel 熔断:当错误率超过50%,自动熔断,返回兜底数据。
@SentinelResource(value = "createOrder", fallback = "createOrderFallback") public String createOrder(...) { ... } - 全链路追踪:SkyWalking 一眼看出瓶颈在商品服务的 DB 查询。
- 健康检查:K8s 的
livenessProbe和readinessProbe必须配,避免流量打到“假活”实例。
📊 另外,我们做了个“服务依赖拓扑图”,每次发布前看一眼,避免不小心删了被依赖的服务——这种事真发生过,运维差点和开发打起来。
性能对比:值不值得?
改造花了3个月,团队熬了无数个夜,但效果是显著的:
| 指标 | 单体架构 | 微服务架构 |
|---|---|---|
| 平均响应时间 | 420ms | 180ms |
| 故障隔离能力 | 无(一挂全挂) | 高(单服务故障不影响全局) |
| 发布频率 | 每周1次 | 每天多次 |
| 扩容粒度 | 整体扩容 | 按服务独立扩缩容 |
| 新人上手难度 | 低(代码集中) | 高(需理解架构) |
最爽的是,大促期间,我们只给交易服务加了5个Pod,其他服务纹丝不动——产品经理终于闭嘴了。
给求职者的真心话
如果你正在准备跳槽,简历上写“参与微服务改造”绝对是个亮点。但别光写名词,要讲清楚你解决了什么问题:
- 是性能瓶颈?数据一致性?还是部署效率?
- 用了什么技术?为什么选它而不是别的?
- 踩了什么坑?怎么复盘的?
我在面试时就被问:“你们怎么保证分布式事务?”
我直接掏出上面的 MQ + 本地事务表方案,还画了个流程图,面试官眼睛都亮了。
记住:微服务不是银弹,而是权衡的艺术。小团队、低并发的项目,强行上微服务,只会增加复杂度。但在高并发、快速迭代的场景下,它确实是“续命神器”。
最后
从单体到微服务,就像从自行车换到高铁——速度是快了,但维护成本也高了。过程中有崩溃,有争吵,也有深夜搞定 Bug 后的击掌庆祝。
上周团建,运维老王拍着我肩膀说:“小安,现在系统稳多了,你小子行啊!”
我笑了笑,心里想:稳?这才哪到哪,明天说不定又有新需求……
但至少,我的简历可以安心写上“微服务架构设计与落地”了。
毕竟,在北京这个卷成麻花的城市,技术,永远是最好的护城河。
共勉。
作者:小安,北京某厂安全工程师,白天挖洞,晚上写码。欢迎关注我的 GitHub:@an-security

评论 0