
拆分的基本原则
单一职责:每个微服务只负责一个单一的业务,这样方便维护,测试和部署
先做单体,再逐步拆分:除非项目非常明确和简单,否则不建议一开始就过度设计。先用清晰的模块化思维构建单体,当遇到瓶颈时再进行拆分
业务驱动优先:拆分应该服务于业务,而不是为了拆分而拆分。业务变化快、独立性强的地方,更适合拆出来
拆分策略
按照业务领域进行拆分
这是DDD(领域驱动设计)的思路。先梳理业务流程,识别子域和限界上下文
- 核心子域:公司的核心竞争力,需要重点投入(如推荐算法)
- 支撑子域:辅助核心业务,但不构成差异化(如认证授权)
- 通用子域:比较通用的能力(如通知服务、日志收集)
例如,电商系统可以拆分为:用户服务、商品服务、订单服务、库存服务、支付服务、物流服务、购物车服务、评价服务
按照业务稳定性进行拆分
区分系统中经常变化的部分和不经常变化的部分,将变的部分和不变的部分拆开后,可以避免不变的部分频繁发布
比如我们之前做的一个im服务,就把服务拆分为网关服务和应用服务。因为网关服务主要维护长链接,协议解析之类的,变动很少。将网关服务拆分出来后,不用频繁上下线,这样用户就不用重新登录

基于可靠性进行拆分
通过微服务架构,我们可以将系统拆分为多个独立的服务,从而将故障隔离在单个服务内,避免故障扩散到整个系统
将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,重点保证核心服务的高可用
比如我们可以将登录拆分为一个服务,做成集群,保障高可用
按照访问频率/资源需求进行拆分
冷热分离:将访问量大,访问频率高的业务,比如秒杀服务。这样既能保证高性能的要求,又能避免影响其他业务
独立扩展:把CPU密集型(图像处理)和IO密集型(消息推送)拆开,以便独立部署和扩容
微服务拆分后会遇到的问题
1.分布式事务和数据一致性问题
问题:在单体应用中,可以通过数据库的 ACID 事务(begin/commit)轻松保证数据一致性。拆分后,每个服务独享数据库,一个业务(如:下单并扣减库存)需要跨越订单服务和库存服务,传统的本地事务失效,极易出现"订单创建成功,但库存没扣"或"库存扣了,订单失败"的情况
| 方案 | 场景 |
|---|---|
| 2PC / 3PC(两阶段/三阶段提交) | 属于强一致性方案,但性能损耗极大,通常只用于金融极高要求场景 |
| TCC 模式(Try-Confirm-Cancel) | 侵入性较强,需要业务代码分别实现准备、确认和取消逻辑 |
| Saga 模式(长事务) | 将一个大事务拆分成多个本地事务,如果其中一步失败,则逆序执行补偿操作(如退款) |
| 本地消息表 / MQ 事务消息 | 利用消息队列(如 RocketMQ)的事务消息,确保本地操作和发送消息同时成功,下游服务异步消费实现最终一致 |
2.服务间调用与网络不稳定
问题:服务的数量爆炸式增长,服务之间通过 HTTP 或 RPC 相互调用。网络是不可靠的,可能会出现延迟、丢包或超时。如果一个底层服务慢,可能会导致上游服务排队,最终引发服务雪崩
解决方案:引入服务治理与容错机制
- 超时与重试: 合理设置接口超时时间,避免无限等待
- 熔断与降级: 当某个服务失败率达到阈值时,自动熔断该服务,直接返回默认友好提示(降级数据),避免拖垮全局。常用工具有 Sentinel 或 Resilience4j
- 限流: 在入口处限制访问频率,保护核心服务不被突发流量冲垮
3.服务发现与动态路由
问题: 在云原生环境下,微服务实例的 IP 地址经常因为扩容、缩容或故障重启而发生变化。硬编码配置文件(如 Nginx 静态配置)根本无法应付。
解决方案: 引入注册中心与服务发现。
- 服务注册与发现: 服务启动时,自动将自己的 IP 和端口注册到注册中心;服务调用方从注册中心拉取可用服务列表。常用组件包括 Nacos、Consul 或 Kubernetes 自带的 DNS/Service。
- 客户端负载均衡: 调用方拿到服务列表后,通过 LoadBalancer(如 Spring Cloud LoadBalancer)在本地进行轮询或随机选择一个实例进行调用
4.分布式链路追踪与运维排查困难
问题: 以前看日志只需要在一个服务器上 tail -f error.log。现在一个请求可能经过了7、8个服务,日志散落在几十台机器或容器中,用户报错时,根本不知道哪一步出了问题,排查故障犹如大海捞针
解决方案: 构建统一的可观测性系统。
- 链路追踪: 使用 SkyWalking、Jaeger 或 Zipkin。在请求入口生成一个唯一的 Trace ID,并透传到所有后续的服务调用中。排查时只需搜索这个 ID,就能看到清晰的调用拓扑图和每一步的耗时。
- 集中式日志: 搭建 ELK / EFK(Elasticsearch, Logstash/Fluentd, Kibana) 堆栈,将所有服务的日志实时收集、清洗并统一存储,支持全文检索。
- 指标监控: 使用 Prometheus + Grafana 监控服务的 CPU、内存、QPS、响应时间等指标
5.跨服务的数据聚合与查询
问题: 在单体应用中,一个简单的 JOIN SQL 语句就能搞定"查询订单以及对应的商品详情和用户信息"。拆分后,这三个数据分别在不同的微服务和数据库中,无法直接使用数据库的 JOIN
解决方案
- 应用层组装: 由前端的网关或 BFF(Backend For Frontend)层分别调用订单、商品、用户服务,然后在内存中把数据拼接好再返回给前端
- 数据异构与读写分离:针对高频、复杂的查询需求,利用 大宽表 或者 ES。通过监听各服务的数据库变更日志(如 Canal 监听 MySQL Binlog),将数据实时同步并聚合到 Elasticsearch 或一个只读的聚合数据库中,查询时直接走 ES 或者 大宽表
最后总结一下
| 面临的挑战 | 核心解决武器 | 常用技术选型 |
|---|---|---|
| 数据一致性 | 分布式事务 / 最终一致性 | Seata, RocketMQ |
| 服务雪崩 | 熔断、降级、限流 | Sentinel, Resilience4j |
| 位置变更 | 服务注册与发现 | Nacos, Kubernetes, Consul |
| 排查困难 | 全链路追踪 + 集中日志 | SkyWalking, ELK, Prometheus |
| 数据聚合 | API 组装 / 数据异构 | GraphQL, Elasticsearch, Canal |