文章目录
- 一、开篇:第30课留下的“同步之痛”
- 二、消息异步解耦的核心价值
- 2.1 同步调用的三大痛点
- 2.2 异步解耦架构设计
- 2.3 Spring Cloud Stream统一编程模型
- 三、RocketMQ核心概念与部署
- 3.1 RocketMQ 5.x架构
- 3.2 消息模型:集群消费 vs 广播消费
- 四、可靠消息投递:RocketMQ事务消息实战
- 4.1 普通消息的“一致性缺口”
- 4.2 事务消息的两阶段提交原理
- 4.3 Spring Cloud Stream集成事务消息
- 4.4 生产者端可靠投递保障
- 4.5 Broker端可靠投递保障
- 五、消费幂等实战
- 5.1 为什么消费端必须幂等
- 5.2 四种幂等方案
- 5.3 基于Redis SETNX的消费幂等
- 六、死信队列实战
- 6.1 死信队列的核心概念
- 6.2 死信队列配置
- 6.3 死信消费者独立部署
- 6.4 死信队列监控
- 七、RabbitMQ与RocketMQ选型对比
- 7.1 核心差异对照
- 7.2 选型决策框架
- 八、生产环境关键配置与踩坑指南
- 8.1 消费者端可靠消费配置
- 8.2 踩坑指南
- 九、课后作业
- 十、阶段总结与下节预告
- 🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航
适配版本:RocketMQ 5.3.1、Spring Cloud Stream 4.x、Spring Cloud Alibaba 2025.1.0.0、Spring Cloud 2025.1.3(Oakwood)、Spring Boot 4.0.8、JDK 21
课程定位:微服务高阶阶段收官,从消息异步解耦到可靠投递,从消费幂等到死信队列,构建完整的消息驱动架构
一、开篇:第30课留下的“同步之痛”
第30课我们完成了Seata AT模式分布式事务的完整实战。@GlobalTransactional注解让跨服务的数据库操作实现了强一致性回滚——库存不足时订单自动回滚,数据不会“飘”。但Seata有一个明确的适用边界:它解决的是“短事务”的一致性问题,事务周期通常在秒级以内。
考虑一个更长的事务场景:用户下单成功后,需要扣减库存、生成物流单、发放积分、发送短信通知。这四个操作分布在四个不同的服务中,如果全部纳入Seata全局事务,会带来两个问题:性能急剧下降(全局锁持有时间过长),以及可用性降低(任何一个服务不可用,整个全局事务都会阻塞)。
更关键的是,这些操作之间并不需要强一致性。积分晚到几秒、短信晚发几秒,对用户来说完全可以接受。真正重要的是:订单创建成功后,这些后续操作最终一定要执行——这就是最终一致性。
消息队列正是实现最终一致性的核心方案。第29课的Spring事件是单JVM内的解耦,消息队列则是跨服务的解耦。两者的关系是互补的:Spring事件处理服务内的模块解耦,消息队列处理服务间的异步通信。
Spring Cloud Alibaba 2025.1.0.0正式适配了RocketMQ 5.3.1,而Spring Cloud Stream 4.x提供了统一的消息编程模型。本课将从消息异步解耦的痛点讲起,深入RocketMQ事务消息的可靠投递机制,实战消费幂等和死信队列,最后对比RabbitMQ与RocketMQ的选型标准。
二、消息异步解耦的核心价值
2.1 同步调用的三大痛点
回顾第16课的订单创建场景,我们用Seata保证了强一致性。但在真实的大促场景中,同步调用还会暴露出三个更深层的痛点:
痛点一:吞吐量受限于最慢的环节。订单服务同步调用库存、积分、短信三个服务,总耗时等于三者之和。即使库存和积分只需100ms,短信服务需要300ms,整个下单接口的响应时间就至少是500ms。根据2025年的行业数据,采用异步消息队列后,订单系统的吞吐量可提升3-5倍。
痛点二:级联故障无法隔离。短信服务如果因运营商网关故障而不可用,订单服务调用短信的超时会导致线程池被占满,进而拖垮库存和积分的调用——这就是第21课讲过的雪崩。
痛点三:流量峰值无法缓冲。秒杀场景下瞬时流量可能是日常的100倍。同步调用无法“存储”请求,请求到来时必须立即处理,否则就丢失。消息队列天然具备削峰填谷能力——将瞬时洪峰写入队列,消费者按自己的处理能力匀速消费。
2.2 异步解耦架构设计
基于消息队列的订单创建流程如下:
用户请求 → 订单服务 │ ├─ ① 创建订单(本地事务) ├─ ② 发送"订单已创建"消息到MQ │ ▼ 返回响应(用户立即得到结果,无需等待下游) │ ▼ ┌─────────────────────────────────────┐ │ RocketMQ Topic │ │ "order-created" │ └──────────┬──────────┬───────────────┘ │ │ ┌──────┴──┐ ┌────┴────┐ ┌────┴────┐ │库存服务 │ │积分服务 │ │短信服务 │ │消费者 │ │消费者 │ │消费者 │ └─────────┘ └─────────┘ └─────────┘核心变化:订单服务只负责“创建订单”和“发送消息”,下游服务各自独立消费。订单服务的响应时间从500ms降至50ms(仅本地事务+发送消息),下游服务的故障不会影响订单创建。
2.3 Spring Cloud Stream统一编程模型
Spring Cloud Stream的核心价值在于提供了统一的消息编程模型。开发者无需关心底层使用的是RocketMQ、Kafka还是RabbitMQ,通过简单的配置和注解就能实现消息的发布和订阅。当企业需要更换消息中间件时,只需更换Binder依赖和少量配置,业务代码无需修改。
函数式编程模型(Spring Cloud Stream 4.x推荐):
@ConfigurationpublicclassOrderMessageConfig{// 生产者:将订单创建消息发送到 output 通道@BeanpublicSupplier<OrderCreatedEvent>orderCreated(){return()->null;// 由业务代码通过 StreamBridge 触发}// 消费者:从 input 通道接收订单创建消息@BeanpublicConsumer<OrderCreatedEvent>handleOrderCreated(){returnevent->{log.info("处理订单创建事件: orderNo={}",event.getOrderNo());// 库存扣减、积分发放等业务逻辑};}}传统注解模型(兼容旧项目):
@EnableBinding(OrderProcessor.class)publicclassOrderMessageListener{@StreamListener(OrderProcessor.INPUT)publicvoidhandleOrderCreated(OrderCreatedEventevent){// 业务逻辑}}publicinterfaceOrderProcessor{StringINPUT="order-input";StringOUTPUT="order-output";@Input(INPUT)SubscribableChannelinput();@Output(OUTPUT)MessageChanneloutput();}三、RocketMQ核心概念与部署
3.1 RocketMQ 5.x架构
RocketMQ 5.x相比4.x最大的架构变化是引入了Proxy层(gRPC + HTTP双协议)和无状态Broker部署,真正实现了云原生化。Proxy层的关键创新在于:生产者/消费者只与Proxy通信,Broker内部实现对客户端透明,扩缩容不影响业务。
核心概念:
| 概念 | 含义 | 类比 |
|---|---|---|
| NameServer | 注册中心,维护Topic和Broker的路由信息 | Nacos的注册中心角色 |
| Broker | 消息存储和转发节点 | 数据库服务器 |
| Topic | 消息的逻辑分类 | 数据库的表 |
| Tag | 消息的二级分类,用于过滤 | 表中的标签列 |
| ConsumerGroup | 消费者组,同组内消费者分担消息 | 线程池中的工作线程 |
| Offset | 消费进度,标识消费者消费到哪条消息 | 书签 |
3.2 消息模型:集群消费 vs 广播消费
| 消费模式 | 行为 | 适用场景 |
|---|---|---|
| 集群消费(默认) | 同组消费者分担消息,每条消息只被组内一个消费者消费 | 订单处理、库存扣减 |
| 广播消费 | 同组每个消费者都收到全量消息 | 配置刷新、缓存更新 |
关键理解:集群消费模式下,如果订单服务部署了3个实例,3个实例属于同一个ConsumerGroup,那么一条订单消息只会被其中一个实例消费。这天然实现了消费端的负载均衡。
四、可靠消息投递:RocketMQ事务消息实战
4.1 普通消息的“一致性缺口”
使用普通消息时,存在一个经典的一致性缺口:本地事务和消息发送不是原子的。如果本地事务提交成功,但消息发送失败,下游服务收不到消息,数据不一致;如果消息发送成功,但本地事务回滚,下游服务收到了不该存在的消息,同样不一致。
第16课我们学过“本地消息表”方案来解决这个问题。但RocketMQ提供了更优雅的原生方案——事务消息。
4.2 事务消息的两阶段提交原理
RocketMQ事务消息基于二阶段提交实现,流程分为两个阶段:
阶段一:发送半事务消息并执行本地事务。
① 生产者发送半事务消息(Half Message)到 Broker │ 此时消息对消费者不可见 ▼ ② Broker 持久化半事务消息,返回 Ack 确认 │ ▼ ③ 生产者执行本地事务(如:写订单库) │ ▼ ④ 生产者根据本地事务结果,向 Broker 发送二次确认 │ Commit → 消息可投递,消费者可见 │ Rollback → 消息删除,消费者不可见 │ Unknown → 等待回查阶段二:消息回查(容错机制)。
如果生产者发送二次确认时网络中断,或生产者应用重启,Broker 未收到确认结果,会触发消息回查:Broker 端会通过扫描发现某条消息长期处于“半事务消息”状态,主动向生产者询问该消息的最终状态。生产者检查本地事务的最终结果后,再次提交二次确认。
完整交互流程:
生产者 Broker 消费者 │ │ │ │──① 半事务消息─────────►│ │ │◄──② Ack───────────────│ │ │ │ │ │──③ 执行本地事务 │ │ │ │ │ │──④ Commit/Rollback───►│ │ │ │──⑤ 投递消息──────────►│ │ │ │ │◄──⑥ 消息回查───────────│ (若④丢失) │ │──⑦ 回查结果───────────►│ │4.3 Spring Cloud Stream集成事务消息
生产者端配置:
@ConfigurationpublicclassTransactionalProducerConfig{@BeanpublicTransactionMQProducertransactionMQProducer()throwsMQClientException{TransactionMQProducerproducer=newTransactionMQProducer("order-producer-group");producer.setNamesrvAddr("127.0.0.1:9876");producer.setTransactionListener(newOrderTransactionListener());producer.start();returnproducer;}}publicclassOrderTransactionListenerimplementsTransactionListener{@OverridepublicLocalTransactionStateexecuteLocalTransaction(Messagemsg,Objectarg){try{// 解析消息体,执行本地事务OrderCreatedEventevent=JSON.parseObject(newString(msg.getBody()),OrderCreatedEvent.class);orderMapper.insert(event.getOrder());returnLocalTransactionState.COMMIT_MESSAGE;}catch(Exceptione){log.error("本地事务执行失败",e);returnLocalTransactionState.ROLLBACK_MESSAGE;}}@OverridepublicLocalTransactionStatecheckLocalTransaction(MessageExtmsg){// Broker 回查:检查本地事务是否执行成功StringorderNo=msg.getUserProperty("orderNo");Orderorder=orderMapper.selectByOrderNo(orderNo);returnorder!=null?LocalTransactionState.COMMIT_MESSAGE:LocalTransactionState.ROLLBACK_MESSAGE;}}发送事务消息:
@ServicepublicclassOrderService{@AutowiredprivateTransactionMQProducertransactionMQProducer;publicvoidcreateOrder(OrderCreateRequestrequest)throwsException{OrderCreatedEventevent=newOrderCreatedEvent();event.setOrderNo(IdUtils.generateOrderNo());event.setProductId(request.getProductId());event.setQuantity(request.getQuantity());Messagemsg=newMessage("order-created","CREATE",event.getOrderNo(),JSON.toJSONBytes(event));msg.putUserProperty("orderNo",event.getOrderNo());// 发送事务消息:Broker 会等待本地事务结果transactionMQProducer.sendMessageInTransaction(msg,null);}}4.4 生产者端可靠投递保障
除了事务消息,生产者端还需要配置同步发送和重试机制:
spring:cloud:stream:rocketmq:binder:name-server:127.0.0.1:9876bindings:order-created-out-0:producer:group:order-producer-groupsend-message-timeout:3000# 发送超时3秒retry-times-when-send-failed:2# 失败重试2次retry-next-server:true# 重试时切换Broker同步发送:send()方法会阻塞直到收到Broker的ACK。重试机制:默认重试2次,可通过retry-times-when-send-failed调整。
4.5 Broker端可靠投递保障
Broker端的可靠性配置(broker.conf):
# 同步刷盘:消息写入磁盘后才返回 ACK flushDiskType = SYNC_FLUSH # 同步双写:主从同步,从节点确认写入后才返回 ACK brokerRole = SYNC_MASTER同步刷盘保证了消息在Broker重启后不丢失;同步双写保证了主节点宕机后消息不丢失。两者的代价是性能下降——异步刷盘(ASYNC_FLUSH)性能更高但可能丢消息。生产环境建议:核心业务使用同步刷盘+同步双写,非核心业务使用异步刷盘。
五、消费幂等实战
5.1 为什么消费端必须幂等
RocketMQ的消息投递保证是“至少一次(At Least Once)”——消息不会丢失,但可能重复。重复的来源有三种:
| 来源 | 原因 |
|---|---|
| 生产者重试 | 发送超时后重试,但第一次实际已成功 |
| Broker重投 | 消费者处理成功但ACK丢失,Broker重新投递 |
| 消费者重启 | 消费进度未及时提交,重启后从旧Offset重新消费 |
结论:消费端必须实现幂等,无论消息投递几次,业务结果都一致。
5.2 四种幂等方案
| 方案 | 实现 | 适用场景 |
|---|---|---|
| 唯一索引 | 数据库唯一约束,重复插入抛异常 | 低频关键业务 |
| 状态机 | UPDATE ... WHERE status = '前置状态' | 订单、支付等有状态业务 |
| Redis SETNX | SETNX bizKey判断是否已处理 | MQ消费、事务补偿 |
| Token机制 | 消息携带唯一Token,处理前校验 | 跨服务调用 |
第16课已详细讲解过这四种方案,本课重点演示在RocketMQ消费场景中的实战应用。
5.3 基于Redis SETNX的消费幂等
@Component@RocketMQMessageListener(topic="order-created",consumerGroup="order-consumer-group",consumeMode=ConsumeMode.CONCURRENTLY)publicclassOrderCreatedConsumerimplementsRocketMQListener<OrderCreatedEvent>{@AutowiredprivateStringRedisTemplateredisTemplate;@AutowiredprivateStockServicestockService;privatestaticfinalStringIDEMPOTENT_KEY="mq:idempotent:order:";@OverridepublicvoidonMessage(OrderCreatedEventevent){StringbizKey=IDEMPOTENT_KEY+event.getOrderNo();// 1. 幂等校验:SETNX 原子操作Booleansuccess=redisTemplate.opsForValue().setIfAbsent(bizKey,"processing",24,TimeUnit.HOURS);if(Boolean.FALSE.equals(success)){log.info("消息重复消费,已忽略: orderNo={}",event.getOrderNo());return;}try{// 2. 执行业务逻辑stockService.decreaseStock(event.getProductId(),event.getQuantity());// 3. 标记处理成功redisTemplate.opsForValue().set(bizKey,"success",24,TimeUnit.HOURS);}catch(Exceptione){// 4. 处理失败,删除Key允许重试redisTemplate.delete(bizKey);throwe;}}}为什么用SETNX而非“先GET再SET”?第16课详细解释过:SETNX是原子操作,在高并发下不会出现两个线程同时通过校验的竞态条件。
六、死信队列实战
6.1 死信队列的核心概念
死信队列(Dead Letter Queue, DLQ)用于存储那些消费失败且达到最大重试次数的消息。关键特性包括:
| 特性 | 说明 |
|---|---|
| 命名规则 | %DLQ%{consumerGroup},按消费者组自动创建 |
| 触发条件 | 消息消费失败次数达到最大重试阈值(默认16次) |
| 消费者隔离 | 死信消息不会被原消费者组再次消费,需新建消费者组单独订阅DLQ |
| 保留时间 | 默认保留3天,超时自动清理 |
为什么需要死信队列?当一条消息因数据格式错误、依赖服务不可用等原因反复消费失败时,无限重试会阻塞后续消息的消费,形成“毒丸消息”。死信队列将这类消息“隔离”出来,让正常消息继续流动,同时保留失败消息供后续人工排查或自动补偿。
6.2 死信队列配置
消费者配置:
spring:rocketmq:consumer:group:order-consumer-groupconsume-mode:CLUSTERINGconsume-thread-min:5consume-thread-max:20pull-batch-size:32max-reconsume-times:3# 最大重试3次,超过进入死信队列max-reconsume-times配置建议:
| 业务类型 | 重试次数 | 原因 |
|---|---|---|
| 非核心业务 | 3次 | 快速失败,避免阻塞 |
| 核心业务(如支付) | 5次 | 给依赖服务更多的恢复时间 |
| 避免使用默认值 | 默认16次 | 会导致消息长时间阻塞 |
6.3 死信消费者独立部署
关键规则:死信队列的消费者组必须独立于原消费者组,否则无法消费DLQ中的消息。
@Component@RocketMQMessageListener(topic="%DLQ%order-consumer-group",// 死信队列TopicconsumerGroup="dlq-handler-group"// 独立的消费者组)publicclassDlqHandlerConsumerimplementsRocketMQListener<String>{@AutowiredprivateAlertServicealertService;@OverridepublicvoidonMessage(Stringmessage){log.error("收到死信消息,需要人工介入: {}",message);// 策略一:自动补偿(需保证幂等)try{compensateService.retry(message);}catch(Exceptione){// 策略二:补偿失败,发送告警alertService.sendAlert("死信消息补偿失败",message);}}}死信消息的处理策略:优先选择“自动补偿(幂等)+ 人工介入兜底”的组合策略,并配置监控告警避免消息堆积。
6.4 死信队列监控
@Component@Slf4jpublicclassDlqMonitor{@AutowiredprivateAlertServicealertService;@Scheduled(fixedDelay=60000)// 每分钟检查一次publicvoidcheckDlqSize(){// 通过 RocketMQ 管理API 查询死信队列的消息数longdlqSize=rocketMQAdmin.getDlqMessageCount("order-consumer-group");if(dlqSize>100){alertService.sendAlert("死信队列堆积告警","当前死信消息数: "+dlqSize);}}}七、RabbitMQ与RocketMQ选型对比
7.1 核心差异对照
| 维度 | RocketMQ | RabbitMQ | Kafka |
|---|---|---|---|
| 语言 | Java | Erlang | Scala/Java |
| 单机吞吐量 | 10万+ TPS | 万级 TPS | 10万+ TPS |
| 延迟 | <1ms | 微秒级 | 2-5ms |
| 事务消息 | ✅ 完整支持 | ❌ 需自己实现 | ❌ 有限支持 |
| 顺序消息 | ✅ 分区有序 | ❌ | ✅ 分区有序 |
| 延迟消息 | ✅ 任意精度 | 需插件 | ❌ |
| 路由灵活性 | 中等 | ✅ 极强 | 弱 |
| 运维复杂度 | 中等 | 低 | 高 |
7.2 选型决策框架
| 场景 | 推荐 | 原因 |
|---|---|---|
| 分布式事务(订单→库存) | RocketMQ | 原生事务消息支持 |
| 延迟消息(支付超时取消) | RocketMQ | 任意时间精度 |
| 复杂路由(多条件分发) | RabbitMQ | 交换机类型丰富 |
| 中小规模业务解耦 | RabbitMQ | 轻量、易运维 |
| 大数据流处理 | Kafka | 高吞吐、持久化日志 |
本专栏选型:使用RocketMQ作为消息驱动的主力方案,原因是它在事务消息、延迟消息、顺序消息三个维度上的原生支持,完美覆盖了微服务场景的核心需求。
八、生产环境关键配置与踩坑指南
8.1 消费者端可靠消费配置
spring:rocketmq:consumer:group:order-consumer-groupconsume-mode:CLUSTERING# 集群消费consume-thread-min:10# 最小消费线程consume-thread-max:50# 最大消费线程pull-batch-size:32# 批量拉取条数max-reconsume-times:3# 最大重试次数consume-timeout:15# 消费超时(分钟)suspend-current-queue-millis:2000# 消费失败后暂停拉取时间核心参数解读:
| 参数 | 作用 | 建议值 |
|---|---|---|
consume-thread-min/max | 消费线程池大小 | 根据消费耗时调整 |
pull-batch-size | 每次拉取的消息条数 | 32~64 |
max-reconsume-times | 进入死信队列前的重试次数 | 3~5 |
consume-timeout | 消息消费超时时间 | 15分钟 |
8.2 踩坑指南
坑一:消费线程池被打满。现象:消息堆积但消费者不消费。原因:某条消息的消费逻辑中执行了耗时操作(如HTTP调用),占满了消费线程。解决:将耗时操作异步化(第29课的@Async),或增加消费线程数。
坑二:死信队列无人处理。现象:死信队列消息数持续增长,无人感知。原因:未配置死信队列监控和告警。解决:配置定期检查死信队列大小的定时任务,超过阈值触发告警。
坑三:消息顺序错乱。现象:订单状态流转出现“已支付→待支付”的逆序。原因:使用了并发消费(ConsumeMode.CONCURRENTLY),但业务需要顺序保证。解决:对于需要顺序的场景,使用ConsumeMode.ORDERLY,并确保生产端将同一业务Key的消息发送到同一个队列。
坑四:Spring Cloud Stream绑定不生效。现象:消息发送成功但消费者未收到。原因:spring.cloud.stream.bindings.<binding-name>.destination与@RocketMQMessageListener的topic配置不一致。解决:确保两者使用相同的Topic名称。
坑五:事务消息回查失败。现象:事务消息长期处于“半事务消息”状态,最终被强制回滚。原因:checkLocalTransaction方法未正确实现,或本地事务状态未持久化。解决:确保回查方法能通过唯一业务Key(如订单号)查到本地事务的最终状态。
坑六:消息体过大导致发送失败。现象:发送大消息时报MQClientException: message body size exceeded。原因:RocketMQ默认单条消息最大4MB。解决:大消息存储到OSS/S3,消息体中只携带文件的URL。
九、课后作业
作业一:部署RocketMQ 5.3.1(NameServer + Broker + Proxy),在service-order中配置Spring Cloud Stream的RocketMQ Binder,实现订单创建消息的发送。在service-product中实现消费者,验证消息接收成功。
作业二:实现RocketMQ事务消息。在service-order中配置TransactionMQProducer和TransactionListener,验证:本地事务成功时消息被投递,本地事务失败时消息被回滚。
作业三:在OrderCreatedConsumer中实现基于Redis SETNX的幂等校验。模拟消息重复投递(通过手动重发消息),验证第二次消费被幂等拦截。
作业四:配置死信队列。将max-reconsume-times设为3,在消费者中人为抛出异常。验证:消息重试3次后进入%DLQ%order-consumer-group,创建独立的死信消费者组并消费该消息。
作业五(进阶):对比RabbitMQ和RocketMQ在相同业务场景(订单通知)下的开发体验和性能表现。使用JMeter压测两种方案的消息发送吞吐量和消费延迟,记录对比数据。
十、阶段总结与下节预告
至此,微服务高阶特性 & 分布式核心能力阶段(第29-31课)全部完成:
| 课程 | 核心能力 | 关键产出 |
|---|---|---|
| 第29课 | 异步调用与事件驱动 | @Async、线程池调优、Spring事件 |
| 第30课 | 分布式事务与Seata | AT模式、全局锁、@GlobalTransactional |
| 第31课 | 消息驱动与解耦 | 事务消息、消费幂等、死信队列 |
三课串联的核心逻辑:第29课解决了单服务内的异步与解耦,第30课解决了跨服务的强一致性,第31课解决了跨服务的最终一致性与异步解耦。三者构成了微服务数据一致性的完整方案体系:Spring事件处理模块解耦,Seata处理强一致场景,RocketMQ处理最终一致场景。
第32课将进入企业级完整项目实战 & 架构复盘阶段——企业级微服务项目架构设计 & 全模块搭建。我们将基于前31课的所有技术栈,从零搭建一个完整的电商微服务项目(用户服务、订单服务、商品服务、支付服务、网关服务),完成业务拆分设计、领域驱动简易落地、统一返回体、统一异常处理和完整项目初始化。前31课是“造零件”,第32课是“组装整车”。
🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航
去订阅
第一部分:微服务前置基础 & 新版环境搭建(第1-5课)
第二部分:注册中心核心(Nacos 最新版)(第6-9课)
第三部分:配置中心核心(Nacos配置中心)(第10-12课)
第四部分:服务通信核心(OpenFeign + LoadBalancer)(第13-16课)
第五部分:网关核心(SpringCloud Gateway 新版)(第17-20课)
第六部分:熔断、限流、降级(Sentinel 新版)(第21-24课)
第七部分:微服务监控、链路追踪、日志体系(第25-28课)
第八部分:微服务高阶特性 & 分布式核心能力(第29-31课)
第九部分:企业级完整项目实战 & 架构复盘(第32-35课)