什么是微服务?它带来哪些挑战?
结论先行:微服务是把一个单体应用按业务能力拆成一组可独立部署、独立演进的小服务,服务间通过轻量协议(HTTP/RPC/消息)通信。它换来的是「局部可扩展、技术异构、故障隔离」,代价是分布式系统固有的复杂度:服务发现、配置管理、调用治理、数据一致性、链路追踪、运维与测试成本。
1. 从单体到微服务
单体 微服务
┌──────────────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ 用户 / 订单 / 支付 │ │ 用户 │ │ 订单 │ │ 支付 │
│ 同一个进程、同一个库│ ──▶ │ 独立库 │ │ 独立库 │ │ 独立库 │
└──────────────────┘ └────┬───┘ └───┬────┘ └───┬────┘
└────── 网关 / 注册中心 ──────┘
拆分不是目的。判断是否该拆,通常看三个信号:业务边界清晰、团队规模超过一个敏捷小组、模块的伸缩需求差异大(例如秒杀流量只压订单服务)。
2. 单体 vs 微服务
| 维度 | 单体 | 微服务 |
|---|---|---|
| 部署 | 一个包整体发布 | 每个服务独立发布 |
| 扩展 | 整体扩容,浪费资源 | 按服务扩容 |
| 技术栈 | 统一 | 可异构 |
| 故障影响 | 一个 bug 可能拖垮全部 | 可隔离、可降级 |
| 事务 | 本地事务,简单 | 分布式事务,复杂 |
| 调用 | 进程内方法调用 | 网络调用,可能超时/重试/重复 |
| 数据 | 一个库,join 自由 | 每服务独立库,跨库 join 消失 |
| 排查 | 单机日志 | 需要链路追踪、日志聚合 |
| 团队 | 共享代码库 | 按服务划分 ownership |
3. 拆完之后新增的六类问题
| 问题 | 表现 | 典型解法 |
|---|---|---|
| 服务发现 | 实例 IP 变化,调用方如何找到 | Nacos / Eureka / Consul |
| 配置管理 | 几十个服务的配置分散 | Nacos Config / Apollo |
| 流量入口 | 鉴权、限流、跨域无处安放 | Spring Cloud Gateway |
| 服务调用 | 超时、重试、负载均衡 | OpenFeign + LoadBalancer |
| 容错 | 一个服务雪崩拖垮全站 | Sentinel / 熔断降级 |
| 可观测性 | 一次请求跨 8 个服务 | TraceId + 日志聚合 + 指标 |
4. 代码:一个最小服务
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@RestController
public static class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@GetMapping("/orders/{id}")
public OrderVO detail(@PathVariable Long id) {
return orderService.detail(id);
}
}
}
server:
port: 8082
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
spring.application.name 就是服务在注册中心里的唯一标识,调用方用这个名字做负载均衡。
5. 一个必须谈的点:数据一致性
拆库后 order 与 inventory 不在同一个事务里,只能:
- TCC / Seata AT:强一致但性能与侵入性高;
- 本地消息表 + 最终一致:订单落库同时写消息表,由定时任务投递,失败重试;
- Saga:长事务拆成多个本地事务 + 补偿动作。
绝大多数业务选最终一致:允许短暂不一致,用对账兜底,而不是硬上分布式事务。
6. 常见追问
追问一:微服务一定比单体好吗? 不是。小团队、业务未稳定时,单体开发效率更高。微服务的收益要在「团队规模、流量规模、迭代频率」达到一定程度后才显现,否则只是把复杂度提前。
追问二:服务拆分的粒度怎么定? 按领域驱动设计(DDD)的限界上下文(Bounded Context)拆,一个上下文一个服务;不要按技术分层拆(controller 服务、dao 服务),那样只会增加调用次数。
追问三:微服务网关和 Nginx 是什么关系? Nginx 做四/七层反向代理与静态资源,负责接入层;网关负责业务级的路由、鉴权、限流。常见拓扑是「公网 → Nginx/LB → Gateway → 各服务」。
追问四:服务间调用用 HTTP 还是 RPC? 内部高性能、强类型、跨语言场景用 gRPC/Dubbo;对外开放、调试友好、生态成熟用 HTTP + JSON。两者常在同一个系统里共存。
追问五:怎么防止一个服务拖垮全站? 三道防线:调用方设超时(禁止无限等待)、熔断降级(Sentinel/Hystrix)、资源隔离(线程池/信号量)。再加限流保护入口。
小结
微服务的本质是用分布式的复杂度换组织的伸缩性与业务的独立性。技术选型(Spring Cloud Alibaba 也好,Kubernetes 也罢)只是把复杂度工具化,真正决定成败的是服务边界划分、数据一致性策略与可观测性建设。