🚀 微服务架构:从入门到进阶完全指南
一、为什么需要微服务?
1.1 从一个真实痛点说起
想象一个电商系统,所有功能都写在一个项目里:用户模块、订单模块、商品模块、支付模块......
随着业务增长,问题开始浮现:
- 🔴 部署风险极高:改一个支付 Bug,整个系统都要重新部署
- 🔴 扩展困难:订单模块压力大,但没法单独扩容,只能整体扩
- 🔴 技术栈被锁死:想在某个模块用 Go 提升性能?不可能
- 🔴 团队协作灾难:100人同时改同一个项目,合并代码就是噩梦
- 🔴 启动慢如蜗牛:本地跑个项目要等 3 分钟
这就是单体架构的天花板,而微服务正是为了打破这个天花板而生。
二、什么是微服务?
2.1 官方定义
微服务 (Microservices)是一种将单一应用程序拆分为一组小型、独立、可独立部署的服务的架构风格。每个服务运行在自己的进程中,通过轻量级通信机制(通常是 HTTP/REST 或消息队列)进行交互。
2.2 用人话解释
把大象切成小块,每块独立运作:
电商系统(单体) 电商系统(微服务)
┌─────────────────────┐ ┌──────────┐ ┌──────────┐
│ │ │ 用户服务 │ │ 订单服务 │
│ 用户 + 订单 + 商品 │ → └──────────┘ └──────────┘
│ + 支付 + 物流 + ... │ ┌──────────┐ ┌──────────┐
│ │ │ 商品服务 │ │ 支付服务 │
└─────────────────────┘ └──────────┘ └──────────┘
每个服务:
- 有独立的代码仓库
- 有独立的数据库
- 可以独立部署、独立扩容
- 可以用不同的技术栈开发
2.3 微服务的核心原则
| 原则 | 说明 |
|---|---|
| 单一职责 | 每个服务只做一件事,做好一件事 |
| 自治性 | 服务间松耦合,独立开发、独立部署 |
| 去中心化 | 数据管理去中心化,每服务拥有自己的数据 |
| 容错设计 | 任何服务都可能失败,系统必须能优雅降级 |
| 可观测性 | 日志、指标、链路追踪缺一不可 |
三、单体 vs 微服务对比
| 维度 | 单体架构 | 微服务架构 |
|---|---|---|
| 开发效率 | 初期快,后期慢 | 初期慢,后期快 |
| 部署 | 整体部署,风险高 | 独立部署,风险低 |
| 扩展性 | 整体水平扩展 | 按需精准扩展 |
| 技术栈 | 统一技术栈 | 自由选择 |
| 故障影响 | 一点崩溃,全体崩溃 | 故障隔离,影响范围小 |
| 运维复杂度 | 低 | 高(需要完善的基础设施) |
| 适用场景 | 初创、业务简单 | 大型、复杂、高并发业务 |
⚠️ 重要认知:微服务不是银弹!小团队、简单业务用微服务是过度设计,会带来巨大的运维负担。
四、微服务核心组件全景图
┌─────────────────────────────────────────────┐
│ 客户端 │
└─────────────────────┬───────────────────────┘
│
┌─────────────────────▼───────────────────────┐
│ API 网关 (Gateway) │
│ 路由 / 鉴权 / 限流 / 熔断 / 灰度发布 │
└──────┬──────────────┬──────────────┬────────┘
│ │ │
┌───────────────▼──┐ ┌────────▼─────┐ ┌───▼───────────┐
│ 用户服务 │ │ 订单服务 │ │ 商品服务 │
│ (user-service) │ │(order-service)│ │(goods-service)│
└───────┬──────────┘ └──────┬────────┘ └───┬───────────┘
│ │ │
┌───────▼────────────────────▼───────────────▼───────────┐
│ 基础设施层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ 注册中心 │ │ 配置中心 │ │ 消息队列 │ │ 链路 │ │
│ │ (Nacos) │ │ (Nacos) │ │(RabbitMQ)│ │追踪 │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────┘ │
└────────────────────────────────────────────────────────┘
五、服务注册与发现(Nacos)
5.1 为什么需要注册中心?
微服务部署后,服务 A 怎么知道服务 B 的 IP 和端口?
- 硬编码 IP?------ 服务重启 IP 就变了
- 配置文件写死?------ 集群部署有多个实例,写哪个?
注册中心就是微服务世界的"通讯录":
服务启动 → 向 Nacos 注册自己(IP + 端口 + 服务名)
服务调用 → 从 Nacos 查询目标服务的地址列表
Nacos → 持续心跳检测,自动剔除宕机实例
5.2 Nacos 快速集成
引入依赖:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置文件:
yaml
spring:
application:
name: order-service # 服务名,注册到 Nacos 的唯一标识
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos 地址
namespace: dev # 命名空间(环境隔离)
group: DEFAULT_GROUP
启动类开启注册:
java
@SpringBootApplication
@EnableDiscoveryClient // 开启服务注册发现
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
5.3 Nacos 核心机制
┌─────────────────────────────────────────────┐
│ Nacos Server │
│ │
│ 服务注册表: │
│ ┌─────────────┬──────────────────────────┐ │
│ │ 服务名 │ 实例列表 │ │
│ ├─────────────┼──────────────────────────┤ │
│ │ order-svc │ 192.168.1.1:8080 ✅ │ │
│ │ │ 192.168.1.2:8080 ✅ │ │
│ │ user-svc │ 192.168.1.3:8090 ✅ │ │
│ └─────────────┴──────────────────────────┘ │
│ │
│ 心跳机制:每5秒上报,15秒未收到则标记不健康 │
└─────────────────────────────────────────────┘
💡 Nacos vs Eureka:Nacos 支持 AP + CP 两种模式切换,且自带配置中心功能,是目前国内主流选择。
六、远程调用(OpenFeign)
6.1 服务间如何调用?
订单服务需要查询用户信息,怎么调用用户服务?
原始方式(RestTemplate):
java
// 繁琐,需要手动拼接 URL,不优雅
String url = "http://user-service/api/user/" + userId;
User user = restTemplate.getForObject(url, User.class);
OpenFeign 方式(声明式,优雅):
java
// 像调用本地方法一样调用远程服务 ✨
User user = userClient.getUserById(userId);
6.2 OpenFeign 完整示例
依赖:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类开启 Feign:
java
@SpringBootApplication
@EnableFeignClients // 扫描所有 FeignClient
public class OrderServiceApplication { ... }
定义 FeignClient 接口:
java
@FeignClient(
name = "user-service", // 对应 Nacos 中注册的服务名
path = "/api/user", // 服务的基础路径
fallback = UserClientFallback.class // 降级类
)
public interface UserClient {
@GetMapping("/{id}")
User getUserById(@PathVariable Long id);
@PostMapping("/batch")
List<User> batchGetUsers(@RequestBody List<Long> ids);
}
使用:
java
@Service
@RequiredArgsConstructor
public class OrderService {
private final UserClient userClient;
public OrderVO getOrderDetail(Long orderId) {
Order order = orderMapper.selectById(orderId);
// 远程调用用户服务,就像调本地方法
User user = userClient.getUserById(order.getUserId());
return OrderVO.build(order, user);
}
}
6.3 Feign 性能调优
yaml
feign:
client:
config:
default:
connect-timeout: 2000 # 连接超时 2s
read-timeout: 5000 # 读取超时 5s
httpclient:
enabled: false
okhttp:
enabled: true # 使用 OkHttp 替换默认 URLConnection,支持连接池
💡 生产建议:务必替换为 OkHttp 或 HttpClient,默认的 URLConnection 性能差且不支持连接池。
七、负载均衡(LoadBalancer)
7.1 负载均衡原理
当用户服务有 3 个实例时,Feign 调用时如何选择?这就是客户端负载均衡的职责。
订单服务发起调用
│
▼
Spring Cloud LoadBalancer
│
├── 从 Nacos 获取 user-service 实例列表
│ [192.168.1.1:8090, 192.168.1.2:8090, 192.168.1.3:8090]
│
├── 按照负载策略选择一个实例(默认轮询)
│
└── 发起实际请求
7.2 自定义负载均衡策略
java
/**
* 自定义:优先调用同机房实例(降低跨机房延迟)
*/
@Bean
public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RoundRobinLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
name
);
}
7.3 常见负载策略对比
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 轮询(Round Robin) | 依次轮流,默认策略 | 服务器配置相同 |
| 随机(Random) | 随机选择 | 简单均衡 |
| 加权轮询 | 根据权重分配流量 | 服务器配置不同 |
| 最少连接 | 选择当前连接数最少的 | 请求处理时间差异大 |
八、API 网关(Gateway)
8.1 为什么需要网关?
没有网关时的问题:
- 客户端需要知道所有服务地址 → 耦合严重
- 每个服务都要做鉴权 → 重复代码
- 跨域处理分散在各服务 → 难以维护
网关是微服务的统一入口,承担:
┌─────────┐
│ 客户端 │
└────┬────┘
│ 所有请求统一走网关
▼
┌──────────────────────────────────┐
│ API Gateway │
│ ✅ 路由转发 ✅ JWT 鉴权 │
│ ✅ 限流熔断 ✅ 日志记录 │
│ ✅ 跨域处理 ✅ 灰度发布 │
└──────┬──────┬──────┬─────────────┘
│ │ │
用户服务 订单服务 商品服务
8.2 Gateway 路由配置
yaml
spring:
cloud:
gateway:
routes:
# 订单服务路由
- id: order-service
uri: lb://order-service # lb:// 表示从注册中心负载均衡
predicates:
- Path=/api/order/** # 匹配路径
filters:
- StripPrefix=1 # 去掉前缀 /api
# 用户服务路由
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
- Header=X-Request-Source, app # 只接受 app 来源
filters:
- AddRequestHeader=X-From-Gateway, true
8.3 自定义全局过滤器(JWT 鉴权)
java
/**
* 全局 JWT 鉴权过滤器
* 所有请求在转发前都经过此过滤器
*/
@Component
@Order(-1) // 优先级最高
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter {
private final JwtUtil jwtUtil;
// 白名单:无需鉴权的路径
private static final Set<String> WHITE_LIST = Set.of(
"/api/user/login",
"/api/user/register"
);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getPath().value();
// 白名单直接放行
if (WHITE_LIST.contains(path)) {
return chain.filter(exchange);
}
// 获取并校验 Token
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange);
}
try {
Claims claims = jwtUtil.parseToken(token.substring(7));
// 将用户信息透传给下游服务
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Role", claims.get("role", String.class))
.build();
return chain.filter(exchange.mutate().request(request).build());
} catch (JwtException e) {
return unauthorized(exchange);
}
}
private Mono<Void> unauthorized(ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
8.4 网关限流配置
yaml
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100 # 令牌桶每秒填充速率
redis-rate-limiter.burstCapacity: 200 # 令牌桶容量
key-resolver: "#{@ipKeyResolver}" # 按 IP 限流
java
@Bean
public KeyResolver ipKeyResolver() {
// 按客户端 IP 进行限流
return exchange -> Mono.just(
Objects.requireNonNull(exchange.getRequest().getRemoteAddress())
.getAddress().getHostAddress()
);
}
九、配置中心(Nacos Config)
9.1 配置中心解决什么问题?
微服务有几十个服务,每个服务都有配置文件:
- 修改数据库密码 → 需要改几十个配置文件并重新部署?❌
- 不同环境(dev/test/prod)配置不同 → 怎么管理?
配置中心让配置集中管理、动态刷新,无需重启服务。
9.2 集成 Nacos Config
依赖:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
bootstrap.yaml(优先级高于 application.yaml):
yaml
spring:
application:
name: order-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml # 配置文件格式
namespace: dev
# 读取的配置文件:${spring.application.name}-${spring.profiles.active}.${file-extension}
# 即:order-service-dev.yaml
9.3 动态刷新配置
java
@RestController
@RefreshScope // 关键注解:配置变更时自动刷新 Bean
public class OrderController {
@Value("${order.timeout:30}") // 从 Nacos 读取,默认30
private Integer orderTimeout;
@Value("${order.max-quantity:99}")
private Integer maxQuantity;
@GetMapping("/config")
public String getConfig() {
return "超时: " + orderTimeout + "s, 最大数量: " + maxQuantity;
}
}
💡 在 Nacos 控制台修改配置后,无需重启服务,
@RefreshScope注解的 Bean 会自动更新!
十、熔断与限流(Sentinel)
10.1 为什么需要熔断?
微服务调用链:A → B → C → D
如果 D 服务响应慢,会导致:
- C 等待 D → C 的线程被耗尽
- B 等待 C → B 的线程被耗尽
- A 等待 B → A 崩溃
- 雪崩效应!整个链路崩溃
熔断器(Circuit Breaker)就是保险丝:当下游服务故障时,自动切断调用,快速失败,保护上游。
状态机:
┌─────────┐ 失败率超阈值 ┌─────────┐
│ CLOSED │─────────────▶│ OPEN │
│(正常) │ │(熔断) │
└─────────┘ └────┬────┘
▲ │ 等待恢复窗口
│ 成功 ▼
│ ┌───────────────────────┐
└────────│ HALF_OPEN │
│(半开,放少量请求探测)│
└───────────────────────┘
10.2 Sentinel 集成
依赖:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置:
yaml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台地址
eager: true # 立即初始化
feign:
sentinel:
enabled: true # 开启 Feign 的 Sentinel 支持
10.3 FeignClient 降级实现
java
/**
* UserClient 的降级实现
* 当 user-service 不可用时,返回兜底数据
*/
@Component
public class UserClientFallback implements UserClient {
@Override
public User getUserById(Long id) {
// 返回一个默认用户,而不是抛出异常
return User.builder()
.id(id)
.username("未知用户")
.build();
}
@Override
public List<User> batchGetUsers(List<Long> ids) {
return Collections.emptyList();
}
}
// FeignClient 指定 fallback
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient { ... }
10.4 @SentinelResource 注解
java
@Service
public class OrderService {
@SentinelResource(
value = "createOrder", // 资源名
blockHandler = "createOrderBlockHandler", // 限流/熔断时的处理方法
fallback = "createOrderFallback" // 异常时的降级方法
)
public OrderVO createOrder(CreateOrderDTO dto) {
// 正常业务逻辑
return doCreateOrder(dto);
}
// 限流处理:必须是 public,参数列表加 BlockException
public OrderVO createOrderBlockHandler(CreateOrderDTO dto, BlockException ex) {
throw new BusinessException("系统繁忙,请稍后重试");
}
// 降级处理:必须是 public,参数列表加 Throwable
public OrderVO createOrderFallback(CreateOrderDTO dto, Throwable t) {
log.error("创建订单失败,进入降级", t);
return OrderVO.failed("服务暂时不可用");
}
}
十一、分布式事务(Seata)
11.1 分布式事务的难题
下单流程涉及三个服务:
用户下单
├── 订单服务:创建订单
├── 库存服务:扣减库存
└── 账户服务:扣减余额
如果库存扣减成功,但账户扣减失败 → 数据不一致!
本地事务无法跨服务,这就是分布式事务的难题。
11.2 Seata AT 模式原理
Seata AT 模式通过自动补偿实现分布式事务:
┌──────────────────────────────────────────────────┐
│ 第一阶段(执行) │
│ 1. 解析 SQL,生成前镜像(before image) │
│ 2. 执行业务 SQL │
│ 3. 生成后镜像(after image),写入 undo_log 表 │
│ 4. 向 TC(事务协调者)注册分支事务 │
└──────────────────────────────────────────────────┘
✅ 所有分支成功 → 第二阶段提交(清理 undo_log)
❌ 任意分支失败 → 第二阶段回滚(根据 undo_log 还原数据)
11.3 Seata 使用示例
java
/**
* 全局事务:@GlobalTransactional 注解
* Seata 会自动协调所有参与者的提交和回滚
*/
@Service
@RequiredArgsConstructor
public class OrderService {
private final StockClient stockClient;
private final AccountClient accountClient;
private final OrderMapper orderMapper;
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public void createOrder(CreateOrderDTO dto) {
// 1. 创建订单(本地事务)
Order order = Order.from(dto);
orderMapper.insert(order);
// 2. 扣减库存(远程调用,Seata 自动管理)
stockClient.deduct(dto.getProductId(), dto.getQuantity());
// 3. 扣减账户余额(远程调用,Seata 自动管理)
accountClient.deduct(dto.getUserId(), dto.getTotalAmount());
// 任意步骤抛出异常,Seata 自动回滚所有已执行的操作
}
}
11.4 四种分布式事务方案对比
| 方案 | 一致性 | 性能 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| Seata AT | 强一致 | 中 | 低(侵入少) | 大多数场景 |
| Seata TCC | 强一致 | 高 | 高(手写补偿) | 高并发、高性能 |
| 本地消息表 | 最终一致 | 高 | 中 | 允许延迟一致 |
| Saga | 最终一致 | 高 | 高 | 长事务、跨组织 |
十二、链路追踪(SkyWalking)
12.1 为什么需要链路追踪?
一个请求经过:Gateway → 订单服务 → 用户服务 → 商品服务
某次请求响应慢,是哪个环节慢?没有链路追踪完全抓瞎。
SkyWalking 提供:
- 完整调用链可视化
- 每个服务的耗时分析
- 慢请求、错误请求告警
12.2 核心概念
Trace(一次完整请求)
└── Span(一个操作单元)
├── Span: Gateway 路由 [0ms - 5ms]
├── Span: OrderService.createOrder [5ms - 150ms]
│ ├── Span: DB query orders [5ms - 20ms]
│ ├── Span: Feign -> user-service [20ms - 80ms]
│ └── Span: Feign -> stock-service [80ms - 145ms]
└── Span: 返回响应 [150ms - 152ms]
12.3 接入方式
SkyWalking 采用 Java Agent 方式,完全无代码侵入:
bash
# 启动服务时添加 javaagent 参数
java -javaagent:/path/to/skywalking-agent.jar \
-Dskywalking.agent.service_name=order-service \
-Dskywalking.collector.backend_service=127.0.0.1:11800 \
-jar order-service.jar
十三、消息驱动(RabbitMQ / Kafka)
13.1 消息队列在微服务中的价值
场景:用户下单后,需要:发短信通知、更新积分、推送优惠券......
同步调用的问题:
下单 → 发短信 → 更新积分 → 推送优惠券
每步都要等待,总耗时 = 各步之和,且任一失败影响下单
消息队列的解法:
下单 → 发送消息 → 立即返回(异步)
│
├── 短信服务(消费消息)
├── 积分服务(消费消息)
└── 优惠券服务(消费消息)
优点:异步解耦、削峰填谷、提升吞吐
13.2 Spring AMQP 实战(RabbitMQ)
生产者(订单服务):
java
@Service
@RequiredArgsConstructor
public class OrderService {
private final RabbitTemplate rabbitTemplate;
@Transactional
public void createOrder(CreateOrderDTO dto) {
// 1. 创建订单
Order order = doCreateOrder(dto);
// 2. 发送消息(异步通知其他服务)
OrderCreatedEvent event = OrderCreatedEvent.from(order);
rabbitTemplate.convertAndSend(
"order.exchange", // Exchange 名
"order.created", // Routing Key
event // 消息体(会被序列化为 JSON)
);
log.info("订单创建成功,事件已发送: orderId={}", order.getId());
}
}
消费者(短信服务):
java
@Component
@Slf4j
public class SmsConsumer {
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(name = "sms.order.created", durable = "true"),
exchange = @Exchange(name = "order.exchange", type = "topic"),
key = "order.created"
)
)
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("收到订单创建事件,发送短信: userId={}", event.getUserId());
try {
smsService.sendOrderConfirmation(event.getUserId(), event.getOrderNo());
} catch (Exception e) {
// 异常后会进入重试,超过重试次数进入死信队列
log.error("短信发送失败", e);
throw e;
}
}
}
13.3 消息可靠性保障
生产者可靠性:
├── Publisher Confirms:消息到达 Exchange 后 ack
└── Publisher Returns:消息无法路由时回调
Broker 可靠性:
├── 队列持久化:durable = true
└── 消息持久化:deliveryMode = 2
消费者可靠性:
├── 手动 ACK:消费成功后才确认
├── 重试机制:失败后延迟重试(指数退避)
└── 死信队列:超过重试次数后转入 DLQ,人工介入
十四、微服务最佳实践与避坑指南
14.1 服务拆分原则
✅ 正确姿势:
- 按业务领域拆分(DDD 限界上下文)
- 每个服务可由 2-3 人独立维护
- 高内聚、低耦合
❌ 错误姿势:
- 按技术层次拆分(Controller层、Service层各一个服务)
- 拆分粒度过细(每个方法一个服务)
- 两个服务之间循环依赖
14.2 接口版本管理
java
// 使用 URL 版本号,避免接口升级导致调用方崩溃
@RestController
@RequestMapping("/api/v1/order")
public class OrderControllerV1 { ... }
@RestController
@RequestMapping("/api/v2/order")
public class OrderControllerV2 { ... }
14.3 超时设计规范
yaml
# 超时链:网关超时 > Feign 超时 > 业务超时
# 保证超时能从最底层传播到最上层
gateway:
timeout: 10s # 网关最长等待 10s
feign:
read-timeout: 8s # Feign 调用超时 8s(小于网关)
service:
business-timeout: 5s # 业务操作超时 5s(小于 Feign)
14.4 生产必备 Checklist
部署前检查:
✅ 每个服务配置了健康检查接口 /actuator/health
✅ 数据库连接池大小合理(不要用默认值)
✅ 日志级别配置正确(生产不要 DEBUG)
✅ 所有 Feign 调用配置了超时和降级
✅ 敏感配置通过配置中心管理,不 hardcode
✅ 接口幂等性处理(防止重复消费/重复提交)
✅ 分布式锁防止并发问题
监控告警:
✅ 接入链路追踪(SkyWalking)
✅ 关键指标监控(Prometheus + Grafana)
✅ 错误日志告警(ELK + 告警规则)
✅ 服务可用性告警(低于 99.9% 立即通知)
14.5 常见踩坑记录
坑1:Feign 不配置超时导致线程池耗尽
yaml
# 一定要配!默认超时是无限等待!
feign:
client:
config:
default:
connect-timeout: 2000
read-timeout: 5000
坑2:Nacos 实例心跳失效被剔除
yaml
# 延长心跳间隔,防止 GC 暂停导致误判下线
spring:
cloud:
nacos:
discovery:
heart-beat-interval: 5000 # 心跳间隔 5s
heart-beat-timeout: 15000 # 超时时间 15s
ip-delete-timeout: 30000 # 删除超时 30s
坑3:@GlobalTransactional 和本地事务冲突
java
// ❌ 错误:不要在 @GlobalTransactional 方法上同时用 @Transactional
@GlobalTransactional
@Transactional // 会产生嵌套事务问题
public void createOrder() { ... }
// ✅ 正确:只用 @GlobalTransactional,Seata 会自动管理本地事务
@GlobalTransactional(rollbackFor = Exception.class)
public void createOrder() { ... }
十五、总结:微服务架构全貌
┌─────────────────────────────────────────────────────┐
│ 微服务技术栈全景 │
└─────────────────────────────────────────────────────┘
流量入口层 [客户端] ──► [API Gateway(路由/鉴权/限流)]
服务治理层 [Nacos 注册中心] + [Nacos 配置中心]
业务服务层 [用户服务] [订单服务] [商品服务] [支付服务] ...
通信层 [OpenFeign 同步调用] + [RabbitMQ/Kafka 异步消息]
稳定性保障 [Sentinel 熔断限流] + [Seata 分布式事务]
可观测性 [SkyWalking 链路追踪] + [Prometheus 监控] + [ELK 日志]
容器化部署 [Docker] + [Kubernetes] + [Helm]
学习路径建议
阶段一(入门): Spring Boot → Nacos 注册发现 → OpenFeign 调用
阶段二(基础): Gateway 网关 → Nacos 配置中心 → Sentinel 熔断
阶段三(进阶): Seata 分布式事务 → MQ 异步解耦 → SkyWalking 追踪
阶段四(深入): DDD 领域驱动设计 → 服务网格(Istio) → K8s 编排
💬 写在最后
微服务不是目的,解决业务问题才是。理解每个组件解决的核心痛点 ,比记住配置更重要。
建议从搭建一个完整的 demo 项目开始,把所有组件串联起来,在实战中加深理解。
如有问题或建议,欢迎在评论区交流!🚀