news 2026/8/6 14:11:38

微服务拆分踩坑实录:从单体到微服务,我后悔的5个决定

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微服务拆分踩坑实录:从单体到微服务,我后悔的5个决定

本文记录了我在实际项目中将单体应用拆分为微服务架构时踩过的坑,希望能帮你少走弯路。

前言

2024年初,我们团队接到一个任务:把一个运行了3年的单体Spring Boot项目拆分成微服务。当时我信心满满,觉得"不就是拆几个服务嘛"。结果三个月后,我深刻体会到了什么叫"拆分一时爽,维护火葬场"。

今天这篇文章,我不讲理论,只讲我真实踩过的坑。


一、后悔决定1:按技术层拆分而不是按业务域拆分

我当时怎么想的

刚开始拆分时,我按照技术层来拆:

  • user-service:所有用户相关
  • common-service:公共逻辑
  • gateway-service:网关
  • data-service:所有数据库操作

出了什么问题

很快我发现,一个"下单"操作需要调用user-service(查用户信息)→data-service(写订单数据)→common-service(发通知),链路又长又脆弱。

更要命的是,data-service成了上帝服务,所有业务都往里塞,跟单体有什么区别?

正确做法

按业务领域(DDD)拆分:

order-service → 负责订单生命周期 payment-service → 负责支付结算 user-service → 负责用户注册/认证 notification-service → 负责消息推送

每个服务拥有自己的数据库,自己管自己的事。

核心原则

高内聚、低耦合 一个服务对应一个业务能力(Business Capability) 服务之间通过API或事件通信,不共享数据库

二、后悔决定2:一开始就上全套Spring Cloud

我当时怎么想的

“既然要做微服务,那Eureka、Config Server、Zuul、Hystrix全上吧!”

出了什么问题

  1. Eureka集群搭了3个节点,开发环境根本用不到,白白占资源
  2. Config Server每次改配置要重启服务,不如Nacos好用
  3. Zuul 1.x性能堪忧,后来换Gateway又改了一遍
  4. Hystrix已经停更,结果项目上线后发现官方推荐Resilience4j

我的建议

# 技术选型建议(2024版本)注册中心:Nacos(兼顾注册+配置)网关:Spring Cloud Gateway熔断:Resilience4j 或 Sentinel链路追踪:SkyWalking 或 Jaeger配置中心:Nacos Config

不要一次性上全套,按需引入。先把服务跑起来,遇到问题再加组件。


三、后悔决定3:分布式事务用了2PC

我当时怎么想的

“跨服务事务一致性很重要,用Seata的AT模式应该没问题吧。”

出了什么问题

// 下单流程:扣库存 + 创建订单 + 扣余额@GlobalTransactionalpublicvoidcreateOrder(OrderDTOdto){inventoryService.deduct(dto.getSkuId(),dto.getQuantity());orderService.create(dto);accountService.debit(dto.getUserId(),dto.getAmount());}

问题来了:

  1. 性能急剧下降:加了全局事务后,TPS从1200降到300
  2. 锁等待超时:高并发下频繁出现全局锁冲突
  3. Seata Server单点故障:挂了一次,全部订单卡住

正确做法:最终一致性

大多数业务场景不需要强一致性,最终一致性就够了:

// 方案1:本地消息表 + MQpublicvoidcreateOrder(OrderDTOdto){// 1. 本地事务:创建订单 + 写消息表orderMapper.insert(order);messageMapper.insert(newMessage("deduct_inventory",dto));// 2. 定时任务扫描消息表,发送MQ// 3. 库存服务消费MQ,扣减库存// 4. 扣减成功后回调确认}// 方案2:Saga模式(推荐)// 每个步骤有对应的补偿操作// 扣库存失败 → 补偿:回滚订单

我的总结

场景推荐方案
强一致性(转账)Seata AT/TCC
最终一致性(下单)本地消息表 + MQ
长事务Saga模式
简单场景重试 + 幂等

四、后悔决定4:服务间通信全用同步HTTP

我当时怎么想的

“用Feign调一下就行了,多简单。”

出了什么问题

// 订单服务调用链OrderServiceUserServiceAddressServiceLogisticsService

某天LogisticsService响应变慢(P99从50ms飙到3s),导致整条链路全部超时,引发雪崩效应

OrderService 线程池打满 → 拒绝所有请求 → 前端504 → 用户疯狂重试 → 更多请求涌入 → 彻底崩溃

正确做法:异步化 + 事件驱动

// 改造前:同步调用@FeignClient("logistics-service")publicinterfaceLogisticsClient{@PostMapping("/api/shipment")ShipmentResultcreateShipment(ShipmentRequestrequest);}// 改造后:事件驱动@ServicepublicclassOrderService{@AutowiredprivateRocketMQTemplatemqTemplate;publicvoidonOrderPaid(Orderorder){// 发事件,不等结果mqTemplate.asyncSend("order-paid-topic",newOrderPaidEvent(order.getId(),order.getAddress()));}}// 物流服务订阅事件@RocketMQMessageListener(topic="order-paid-topic")publicclassShipmentListenerimplementsRocketMQListener<OrderPaidEvent>{@OverridepublicvoidonMessage(OrderPaidEventevent){// 异步创建物流单shipmentService.create(event);}}

通信方式选择指南

场景推荐方式
需要实时返回结果同步HTTP/gRPC
不关心结果/允许延迟MQ异步
广播通知事件驱动
高性能内部调用gRPC

五、后悔决定5:没有做好服务可观测性

我当时怎么想的

“先把功能做出来,监控以后再加。”

出了什么问题

上线一周后,用户反馈"下单有时候很慢"。我们排查了两天:

  • 看了Nginx日志:请求确实慢
  • 看了各服务日志:单个服务都不慢
  • 最后发现:是服务之间的网络调用慢,但没有链路追踪,根本定位不到是哪一跳的问题

正确做法:Day 1就要有三板斧

# 可观测性三板斧Metrics(指标):Prometheus + GrafanaLogging(日志):ELK / LokiTracing(链路追踪):SkyWalking / Jaeger

最小化接入方案(SkyWalking为例):

<!-- 只需加一个agent,零代码侵入 --><!-- 启动参数 -->-javaagent:/path/to/skywalking-agent.jar -Dskywalking.agent.service_name=order-service -Dskywalking.collector.backend_service=localhost:11800

接入后你能看到:

  1. 每个请求经过了哪些服务
  2. 每一跳耗时多少
  3. 哪个服务是瓶颈
  4. 异常发生在哪个节点

六、拆分微服务的正确姿势(总结)

经过这些坑,我总结了一套微服务拆分的决策框架

拆分前的灵魂三问

  1. 你的团队有几个人?3-5人的团队搞微服务就是自找麻烦
  2. 你的业务复杂度到了吗?如果单体还能hold住,别急着拆
  3. 你的基础设施Ready了吗?CI/CD、容器化、监控缺一不可

拆分节奏建议

阶段1:单体内模块化(Package by Feature) 阶段2:识别核心域,抽出1-2个独立服务 阶段3:基础设施补齐(注册中心、网关、配置中心) 阶段4:逐步拆分更多服务 阶段5:引入Service Mesh(可选)

我的避坑清单

  • 不要为了微服务而微服务
  • 先定义好服务边界(推荐Event Storming)
  • 每个服务独立数据库
  • 优先选择最终一致性
  • 异步优于同步
  • Day 1就接入可观测性
  • CI/CD必须自动化
  • 做好服务降级和熔断

写在最后

微服务不是银弹,它解决了一些问题,也引入了大量新问题。如果你的团队还小、业务还简单,好的单体远胜于烂的微服务

但如果你确定要拆,希望我踩的这些坑能帮你少走一些弯路。有问题欢迎评论区交流!


如果这篇文章对你有帮助,别忘了点赞收藏,你的支持是我持续输出的动力!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/6 14:10:57

MongoDB地理空间数据处理与GeoJSON应用详解

1. 为什么需要地理位置数据处理&#xff1f;在现代应用开发中&#xff0c;地理位置数据处理已经成为刚需。从外卖App的配送路线规划&#xff0c;到社交软件的附近好友推荐&#xff0c;再到共享单车的智能调度&#xff0c;这些场景都离不开高效的地理位置数据处理能力。MongoDB作…

作者头像 李华
网站建设 2026/8/6 14:10:54

小米智能家居终极接入方案:Xiaomi Miot For HomeAssistant 完整指南

小米智能家居终极接入方案&#xff1a;Xiaomi Miot For HomeAssistant 完整指南 【免费下载链接】hass-xiaomi-miot Automatic integrate all Xiaomi devices to HomeAssistant via miot-spec, support Wi-Fi, BLE, ZigBee devices. 小米米家智能家居设备接入Hass集成 项目地…

作者头像 李华
网站建设 2026/8/6 14:09:55

Flutter+OpenHarmony开发家具保修管理App实战

1. 项目背景与核心需求在智能家居和移动互联网快速发展的今天&#xff0c;家具购买后的保修管理一直是用户痛点。传统纸质保修卡易丢失、电子保修单分散在各个平台&#xff0c;导致真正需要保修时用户往往找不到有效凭证。这个项目正是为了解决这一实际问题——通过Flutter框架…

作者头像 李华
网站建设 2026/8/6 14:09:47

Spring Cloud Gateway微服务网关实战与JWT校验

1. 微服务网关的核心价值与演进方向 在分布式系统架构中&#xff0c;API网关扮演着流量守门人的关键角色。随着微服务架构的普及&#xff0c;Spring Cloud Gateway作为Spring Cloud生态的二代网关组件&#xff0c;相比早期的Zuul在性能、功能扩展性方面都有显著提升。根据实际项…

作者头像 李华
网站建设 2026/8/6 14:09:42

电动汽车电池测试参数详解:从OCV、DCR到HPPC,构建BMS精准管理基础

1. 从“测不准”到“测得准”&#xff1a;为什么EV电池测试参数是行业命门 最近和几个做动力电池系统集成的朋友聊天&#xff0c;话题总绕不开一个词&#xff1a;一致性。他们最头疼的不是电芯的绝对性能有多高&#xff0c;而是同一批电芯&#xff0c;装到车上后&#xff0c;有…

作者头像 李华
网站建设 2026/8/6 14:09:32

Unity 2025开发实战:性能优化与ECS迁移指南

1. 项目概述&#xff1a;UWA问答精选的价值定位 作为Unity开发者社区的技术风向标&#xff0c;UWA年度问答精选已经连续多年成为行业开发者必读的技术沉淀。2025年度的精选集延续了往年的深度挖掘传统&#xff0c;从全年数万条技术问答中筛选出最具代表性的问题解决方案&#x…

作者头像 李华