3、服务拆分原则:业务领域拆分原则、技术维度拆分原则、数据维度拆分原则

服务拆分这件事,说起来简单,做起来全是坑。

我记得刚带团队做微服务改造那会儿,大家一上来就撸起袖子干,结果拆了三个月,系统比原来还乱。后来我总结了一句话:拆分不是目的,让系统好维护才是

那到底怎么拆?我个人的习惯是,从三个维度去思考:业务领域技术维度数据维度。这三个维度缺一不可,咱们一个一个说。

3.1 业务领域拆分原则

这是最核心的拆分方式。说白了,就是按业务边界切分

你想想看,一个电商系统,有商品、订单、用户、支付、库存……这些天然就是不同的业务领域。把它们拆成独立的服务,每个服务只干一件事,这就是领域驱动设计(DDD)里说的“限界上下文”。

核心原则:一个服务只负责一个完整的业务能力,不要跨领域。

我在项目中遇到过这样一个案例:有个团队把“订单服务”和“支付服务”合并了,理由是“订单和支付关系紧密”。结果呢?每次支付接口升级,订单服务也得跟着重启。后来我让他们拆开,订单只管订单状态,支付只管资金流转,中间通过消息队列异步通信。问题一下子就解决了。

业务领域拆分,我建议你遵循这几点:

  • 高内聚低耦合:一个服务内部的逻辑要完整,服务之间依赖要少。
  • 按职责划分:每个服务只对它的业务领域负责,别越界。
  • 考虑团队结构:康威定律告诉我们,系统架构会复制组织沟通结构。所以,一个服务最好由一个团队维护。

我的小技巧:画一张业务领域地图,把每个业务模块标出来,然后看哪些模块之间的交互最频繁。交互频繁的,要么合并,要么用异步解耦。

3.2 技术维度拆分原则

业务领域拆分是“做什么”,技术维度拆分是“怎么做”。

有时候,同一个业务领域里,不同功能的技术栈差异很大。比如,一个服务里既有高并发的读操作,又有复杂的计算任务。这时候,按技术维度拆分就很有必要。

我举个例子:

  • 读写分离:把读服务和写服务拆开。读服务可以加缓存、做CDN,写服务保证数据一致性。
  • 计算密集型 vs IO密集型:计算密集型的服务可以多分配CPU资源,IO密集型的服务可以多分配内存。
  • 实时 vs 离线:实时服务要求低延迟,离线服务可以接受批量处理。拆开之后,各自优化。

注意:技术维度拆分不能喧宾夺主。我见过有人为了用新技术而强行拆分,结果服务拆了十几个,业务逻辑却散得到处都是。记住,技术是为业务服务的。

我曾经踩过一个坑:有个项目把“用户登录”和“用户信息查询”拆成了两个服务,理由是“登录用JWT,查询用Redis”。结果呢?每次用户修改密码,两个服务都得同步更新。后来我把它俩合并了,反而更简单。

所以,技术维度拆分的原则是:

  • 只在必要时拆分:如果技术差异不大,别硬拆。
  • 保持接口稳定:拆完之后,服务之间的接口要尽量稳定,别频繁变动。
  • 考虑运维成本:每多一个服务,就多一份部署、监控、日志的负担。

3.3 数据维度拆分原则

这个维度最容易被忽略,但恰恰是最要命的。

你想想看,业务拆开了,服务拆开了,但数据还混在一个库里,那跟没拆有什么区别?

数据维度拆分,核心就是每个服务拥有自己的数据库。这就是微服务里常说的“数据库 per 服务”模式。

核心原则:服务之间不能直接访问对方的数据库,只能通过API调用。

我在项目中遇到过这样一个场景:订单服务和库存服务,一开始共享一个数据库。结果订单服务的一次慢查询,直接把库存服务的数据库拖垮了。后来我们把数据库拆开,订单用MySQL,库存用Redis+MySQL,各自独立部署,问题再也没出现过。

数据维度拆分,我建议你注意这几点:

  • 数据所有权:每个服务只操作自己的数据,别越权。
  • 数据一致性:跨服务的数据一致性,别用分布式事务,尽量用最终一致性。比如,用事件驱动、Saga模式。
  • 数据冗余:有时候,为了性能,可以允许数据冗余。比如,订单服务里存一份用户的基本信息,避免每次查询都去调用户服务。
拆分维度 核心关注点 常见误区
业务领域 限界上下文、高内聚低耦合 过度拆分、跨领域耦合
技术维度 读写分离、计算/IO分离 为技术而技术、增加运维成本
数据维度 数据库 per 服务、数据所有权 共享数据库、强一致性陷阱

避坑指南:我曾经把一个用户服务的数据拆成了三个库——用户基本信息库、用户行为库、用户权限库。结果每次查询都要跨三个库,性能反而下降了。后来我合并成两个库,一个高频访问的,一个低频归档的,效果好了很多。所以,数据拆分也要适度,别走极端。

嗯,总结一下。服务拆分没有银弹,三个维度要综合考虑。业务领域是骨架,技术维度是肌肉,数据维度是血液。三者配合好了,系统才能跑得稳、跑得快。

下一章,我会聊聊具体的拆分流程和实战案例。到时候咱们再细聊。