25、MVC中的微服务架构:从单体到分布式

聊到微服务,很多同学第一反应是「拆」。但怎么拆?拆了之后 MVC 还管用吗?

我这些年见过不少团队,一上来就把系统拆成几十个服务,结果接口调用乱成一锅粥,比原来还难维护。说白了,微服务不是银弹,它只是把 MVC 的「层」变成了「服务」。

单体 MVC 的痛点

先说说单体应用。一个典型的 Spring MVC 项目,Controller、Service、DAO 都在一个进程里。开发初期很爽,但一旦业务复杂起来,问题就来了:

  • 部署耦合:改一行代码,整个应用要重新部署
  • 团队冲突:多人改同一个模块,合并代码像打仗
  • 扩展困难:某个功能流量大,却要扩容整个应用

我记得有个电商项目,订单模块和用户模块耦合在一起。双十一那天订单量暴增,结果用户登录也跟着卡。你说冤不冤?

微服务架构下的 MVC 变形

微服务不是把 MVC 扔掉,而是把每一层「服务化」。我习惯这样理解:

  • Controller → 网关层(API Gateway)
  • Service → 业务微服务
  • Model → 数据服务 + 领域模型

每个微服务内部,依然遵循 MVC 的分层思想。只不过服务之间通过 RPC 或消息队列通信。

核心原则:微服务是「水平拆分」,MVC 是「垂直分层」。两者不冲突,而是互补。

如何拆分?一个实战案例

假设我们有一个电商单体应用,包含用户、商品、订单、支付四个模块。怎么拆?

我建议按「业务边界」来拆,而不是按「技术层」来拆。什么意思?

  • 用户服务:注册、登录、个人信息
  • 商品服务:商品列表、详情、库存
  • 订单服务:下单、订单状态
  • 支付服务:支付、退款

每个服务内部,都有自己的 Controller、Service、DAO。服务之间通过 API 调用。

// 订单服务调用用户服务(伪代码)
@RestController
public class OrderController {
    
    @Autowired
    private UserServiceClient userClient; // 远程调用
    
    @PostMapping("/order/create")
    public Result createOrder(@RequestBody OrderDTO order) {
        // 1. 调用用户服务验证用户
        User user = userClient.getUser(order.getUserId());
        if (user == null) {
            return Result.error("用户不存在");
        }
        
        // 2. 调用商品服务扣减库存
        boolean stockOk = stockClient.deduct(order.getProductId(), order.getQuantity());
        if (!stockOk) {
            return Result.error("库存不足");
        }
        
        // 3. 创建订单(本地逻辑)
        orderService.create(order);
        return Result.success();
    }
}

你看,Controller 里依然做参数校验和路由,Service 里做业务逻辑。只不过 Service 里调用了其他服务的接口。

避坑指南:我曾经把一个服务拆得太细,用户服务拆成了「登录服务」「注册服务」「信息查询服务」。结果一个简单的用户页面要调三个接口,延迟翻了三倍。后来我合并成「用户域服务」,一个服务搞定所有用户相关操作。

服务间通信:RPC vs 消息队列

微服务之间怎么通信?我常用的两种方式:

方式 适用场景 优点 缺点
RPC(如 Dubbo、gRPC) 同步调用,实时性要求高 调用简单,像本地方法 耦合度高,服务依赖强
消息队列(如 RabbitMQ、Kafka) 异步处理,削峰填谷 解耦,容错性好 最终一致性,调试困难

我个人习惯:核心链路用 RPC,非核心链路用消息队列。比如下单必须实时扣库存,用 RPC;下单成功后发短信通知,用消息队列。

数据一致性:分布式事务

单体应用里,事务很简单:一个 @Transactional 搞定。但微服务里,每个服务有自己的数据库,怎么保证一致性?

嗯,这里要注意。分布式事务没有银弹。我常用的方案:

  • TCC(Try-Confirm-Cancel):适合强一致性场景,比如支付
  • Saga 模式:适合长事务,比如下单流程
  • 最终一致性:适合非关键数据,比如用户积分

我曾经在一个支付项目里用 TCC,代码量翻了一倍。但没办法,钱的事不能含糊。

警告:不要为了微服务而微服务。如果你的团队不到 10 人,业务复杂度不高,单体应用 + 良好分层完全够用。微服务带来的运维成本,可能比收益还高。

SVG:单体 MVC → 微服务架构演进图

单体 MVC → 微服务架构演进 单体 MVC 应用 Controller 层 接收请求,参数校验 Service 层 业务逻辑,事务管理 DAO / Model 层 数据访问,ORM 单体数据库 拆分 微服务架构 API 网关(Controller 层) 用户服务 Controller Service 商品服务 Controller Service 订单服务 Controller Service 用户 DB 商品 DB 订单 DB 消息队列(异步通信) 服务注册中心(Nacos/Eureka)

总结一下

微服务架构下的 MVC,本质上是把「层」变成了「服务」。每个服务内部依然保持 MVC 的分层结构,但服务之间通过 RPC 或消息队列通信。

拆分的核心是「业务边界」,不是「技术层」。我见过太多人把 Service 层拆成独立服务,结果 Controller 层还在单体里,搞得四不像。

最后说一句:微服务是手段,不是目的。如果你的业务还没复杂到需要拆,老老实实用单体 MVC。等流量来了、团队大了,再考虑演进。

一句话记住:单体 MVC 是「三层一库」,微服务 MVC 是「多服务多库,每服务三层」。


公众号:蓝海资料掘金营,微信deep3321