第 217 章:微服务入门
学习目标
- 理解微服务与单体的差异
- 掌握服务拆分原则
- 学会服务通信方式
- 了解微服务治理基础
一、单体 vs 微服务
1.1 单体架构
所有功能打包成一个应用,共享一个数据库。
优点:简单、调试容易、部署简单
缺点:
- 团队耦合,代码冲突多
- 扩展必须整体扩(浪费资源)
- 一个 bug 让整个系统挂
- 技术栈绑定
1.2 微服务架构
按业务拆分为独立服务,各自部署。
优点:
- 独立部署、独立扩缩
- 故障隔离
- 技术异构(每个服务可用不同语言)
- 团队自治
缺点:
- 分布式复杂性(网络、事务、监控)
- 运维成本高
- 数据一致性难
二、服务拆分
2.1 拆分原则
| 原则 | 说明 |
|---|---|
| 单一职责 | 一个服务只做一件事 |
| 业务边界 | 按 DDD 限界上下文 |
| 高内聚低耦合 | 服务内部紧,服务之间松 |
| 可独立部署 | 不影响其他服务 |
| 团队规模 | "两个披萨原则"(< 8 人) |
2.2 拆分方式
方式一:按业务能力
电商系统
├── 用户中心
├── 商品中心
├── 订单中心
├── 支付中心
└── 库存中心方式二:按 DDD 限界上下文
├── 销售上下文(下单)
├── 商品上下文(SPU/SKU)
├── 库存上下文(扣减/锁定)
└── 支付上下文(交易/退款)2.3 反例:拆错的微服务
❌ 拆得过细(纳米服务 / 分布式单体):
订单服务拆为:
├── 创建订单
├── 修改订单
├── 查询订单
├── 取消订单
└── 订单状态
→ 简单 CRUD 拆成 5 个服务,纯运维灾难✅ 合理粒度:按业务价值切分,服务数 = 子域数
三、服务通信
3.1 同步 vs 异步
| 维度 | 同步 | 异步 |
|---|---|---|
| 一致性 | 强 | 弱(最终一致) |
| 性能 | 受限于最慢 | 高吞吐 |
| 耦合 | 高(知道对方地址) | 低(只发事件) |
| 失败处理 | 即时失败 | 重试 / DLQ |
| 适用 | 关键路径 | 副作用、通知 |
3.2 RESTful
最常见的同步通信方式。
java
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@PostMapping
public Result<Order> create(@RequestBody OrderRequest req) {
return orderService.create(req);
}
}调用方:
java
@Service
public class OrderApplicationService {
@Autowired
@LoadBalanced
private RestTemplate restTemplate;
public Order create(OrderRequest req) {
// 调用库存服务同步扣减
String stockUrl = "http://inventory-service/api/inventory/deduct";
InventoryResponse resp = restTemplate.postForObject(stockUrl, req, InventoryResponse.class);
// ...
}
}3.3 OpenFeign
声明式 HTTP 客户端,Spring Cloud 标配。
java
@FeignClient(name = "inventory-service")
public interface InventoryClient {
@PostMapping("/api/inventory/deduct")
Result<InventoryResponse> deduct(@RequestBody DeductRequest req);
@GetMapping("/api/inventory/check/{skuId}")
Result<Boolean> checkStock(@PathVariable String skuId);
}java
@Service
@RequiredArgsConstructor
public class OrderService {
private final InventoryClient inventoryClient;
public void createOrder() {
Result<InventoryResponse> result = inventoryClient.deduct(...);
if (!result.isSuccess()) {
throw new BizException("库存不足");
}
}
}3.4 gRPC
高性能 RPC,基于 HTTP/2 + Protobuf。
inventory.proto:
protobuf
syntax = "proto3";
service InventoryService {
rpc Deduct(DeductRequest) returns (DeductResponse);
rpc CheckStock(CheckRequest) returns (CheckResponse);
}
message DeductRequest {
string sku_id = 1;
int32 quantity = 2;
}
message DeductResponse {
bool success = 1;
string message = 2;
}java
// Stub 调用
@GrpcClient("inventory-service")
private InventoryServiceGrpc.InventoryServiceBlockingStub stub;
public void deduct(String skuId, int qty) {
DeductResponse resp = stub.deduct(
DeductRequest.newBuilder()
.setSkuId(skuId)
.setQuantity(qty)
.build()
);
}3.5 消息队列异步
java
// 发布者:订单服务
@Service
public class OrderService {
@Autowired
private KafkaTemplate<String, OrderEvent> kafka;
public void createOrder() {
Order order = ...;
orderRepo.save(order);
// 异步通知库存
kafka.send("order-events", new OrderCreatedEvent(order));
}
}
// 消费者:库存服务
@KafkaListener(topics = "order-events")
public void onOrderCreated(OrderCreatedEvent event) {
inventoryService.lockStock(event.orderId(), event.items());
}四、服务注册与发现
4.1 原理
4.2 Nacos
yaml
# application.yml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 192.168.1.10:8848注册后:
bash
curl http://192.168.1.10:8848/nacos/v1/ns/catalog/instances?serviceName=order-service调用方:
java
@FeignClient(name = "inventory-service")
public interface InventoryClient { ... }五、API 网关
所有外部请求经网关统一入口。
5.1 Spring Cloud Gateway
yaml
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- id: payment-service
uri: lb://payment-service
predicates:
- Path=/api/payments/**5.2 Kong / APISIX
生产级网关,支持:
- 路由、鉴权
- 限流、熔断
- 日志、监控
- 插件生态
六、配置中心
集中管理配置,支持动态刷新。
yaml
# Nacos / Apollo / Consul
spring:
cloud:
nacos:
config:
server-addr: 192.168.1.10:8848
file-extension: yaml
refresh-enabled: truejava
@RefreshScope
@RestController
public class ConfigController {
@Value("${order.timeout:3000}")
private int timeout;
}七、容错与熔断
7.1 服务雪崩
A 调用 B,B 调用 C,C 挂 → B 累积线程 → A 也挂
7.2 熔断器模式
| 状态 | 行为 |
|---|---|
| Closed | 正常调用,统计失败率 |
| Open | 直接拒绝,降级 |
| HalfOpen | 放行少量请求试探 |
7.3 Resilience4j
java
@Service
public class OrderService {
@CircuitBreaker(name = "inventory", fallbackMethod = "fallback")
public InventoryResponse checkStock(String skuId) {
return inventoryClient.check(skuId);
}
// 降级方法
public InventoryResponse fallback(String skuId, Throwable t) {
log.warn("库存服务不可用,降级处理", t);
return InventoryResponse.okWithCache(skuId);
}
}7.4 Sentinel(阿里)
java
@SentinelResource(value = "checkStock", blockHandler = "blockHandler")
public InventoryResponse checkStock(String skuId) {
return inventoryClient.check(skuId);
}
public InventoryResponse blockHandler(String skuId, BlockException ex) {
return InventoryResponse.busy();
}八、分布式事务
8.1 问题
订单 + 库存 + 支付三个服务,无法用本地事务保证一致。
8.2 CAP 理论
分布式系统 P 必选,只能在 C 和 A 之间权衡。
8.3 BASE 理论
放弃强一致,追求基本可用 + 最终一致。
| 原则 | 含义 |
|---|---|
| BA(Basically Available) | 基本可用,允许降级 |
| S(Soft State) | 软状态,允许中间态 |
| E(Eventually Consistent) | 最终一致 |
8.4 Saga 模式
长事务拆成多个本地事务 + 补偿动作。
实现:
- Seata(阿里,Saga + AT + TCC)
- Apache ServiceComb Saga
九、链路追踪
9.1 概念
用户请求
├─ 网关 (10ms)
├─ 订单 (20ms)
│ ├─ 库存 RPC (15ms) ← 慢!
│ └─ 支付 RPC (5ms)
└─ 响应 (30ms)9.2 Trace + Span
- Trace:一次完整调用链
- Span:每个调用节点
- 通过
traceId串联所有服务
9.3 Sleuth + Zipkin
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>yaml
spring:
zipkin:
base-url: http://zipkin:9411
sleuth:
sampler:
probability: 1.0十、微服务架构图
十一、本章小结
| 组件 | 作用 |
|---|---|
| 服务注册中心 | 服务发现 |
| API 网关 | 统一入口、鉴权、限流 |
| 配置中心 | 配置统一管理 |
| 熔断器 | 容错、降级 |
| 消息队列 | 异步解耦 |
| 链路追踪 | 调用链可视化 |
| 监控 | 指标采集与告警 |
动手练习
- 用 Spring Boot 实现 2 个简单微服务(用户、商品),用 RestTemplate 通信
- 用 Nacos 做服务注册与发现
- 用 OpenFeign 替换 RestTemplate,体验声明式调用
- 配置 Sentinel 熔断,模拟下游故障,观察降级行为
推荐阅读
下一章:第 218 章:微服务设计原则