From 376e78117c12ab4a39a95878d8724763c24bc75d Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Tue, 27 May 2025 20:43:37 +0800 Subject: [PATCH] =?UTF-8?q?Commit=20on=202025/05/27=20=E5=91=A8=E4=BA=8C?= =?UTF-8?q?=2020:43:37.87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 自学/微服务.md | 211 ++++++++++++++++++++++++++++++++++++++++++++- 自学/消息队列MQ.md | 64 ++++++++++++++ 2 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 自学/消息队列MQ.md diff --git a/自学/微服务.md b/自学/微服务.md index 4fff51a..f605d09 100644 --- a/自学/微服务.md +++ b/自学/微服务.md @@ -977,7 +977,7 @@ hm: 示例:购物车中的商品上限数量需动态调整。 -1)在nacos中添加配置 +**1)在nacos中添加配置** 在nacos中添加一个配置文件,将购物车的上限数量添加到配置中: @@ -1001,7 +1001,7 @@ hm: maxAmount: 1 # 购物车商品数量上限 ``` -2)在微服务中配置 +**2)在微服务中配置** ```java @Data @@ -1012,7 +1012,7 @@ public class CartProperties { } ``` -3)下次,只需改nacos中的配置文件=》发布,即可实现热更新。 +**3)下次,只需改nacos中的配置文件 =》发布,即可实现热更新。** @@ -1156,7 +1156,7 @@ public class DynamicRouteLoader { -## 服务保护与分布式事务 +## 服务保护 ### 服务保护方案 @@ -1295,6 +1295,10 @@ feign: 触发限流或熔断后的请求不一定要直接报错,也可以返回一些默认数据或者友好提示,采用FallbackFactory,可以对远程调用的异常做处理。 +业务场景:购物车服务需要同时**openFeign**调用服务B和商品服务,现在对商务服务做了线程隔离,在高并发的时候,会疯狂抛异常,现在做个fallback让它返回默认值。 + +image-20250526210626857 + **步骤一**:在hm-api模块中给`ItemClient`定义降级处理类,实现`FallbackFactory`: image-20250526200028905 @@ -1343,3 +1347,202 @@ public interface ItemClient { ``` 重启后,再次测试 + + + +#### 熔断器 + +![image-20250527101557002](https://pic.bitday.top/i/2025/05/27/gswod2-0.png) + +image-20250527101856284 + + + +## 分布式事务 + +场景:订单服务依次调用了购物车服务和库存服务,它们各自操作不同的数据库。当清空购物车操作成功、库存扣减失败时,订单服务能捕获到异常,却无法通知已完成操作的购物车服务,导致数据不一致。虽然每个微服务内部都能保证本地事务的 ACID 特性,但跨服务调用**缺乏全局协调**,无法实现端到端的一致性。 + +image-20250527104713275 + +### Seeta + +要解决这个问题,只需引入一个统一的**事务协调者**,负责跟每个分支通信,检测状态,并统一决定全局提交或回滚。 + +在 Seata 中,对应三大角色: + +- **TC(Transaction Coordinator)事务协调者** + 维护全局事务和各分支事务的状态,负责发起全局提交或回滚指令。 +- **TM(Transaction Manager)事务管理器** + 定义并启动全局事务,最后根据应用调用决定调用提交或回滚。 +- **RM(Resource Manager)资源管理器** + 嵌入到各微服务中,负责注册分支事务、上报执行结果,并在接到 TC 指令后执行本地提交或回滚。 + +![image-20250527111935499](https://pic.bitday.top/i/2025/05/27/iif6pd-0.png) + +其中,TM 和 RM 作为客户端依赖,**直接集成到业务服务里**;TC 则是一个**独立部署的微服务**,承担全局协调的职责。这样,无论有多少分支参与,都能保证“要么都成功、要么都回滚”的一致性。 + + + +### 部署TC服务 + +1)准备数据库表 + +seata-tc.sql 运行初始化脚本 + +![image-20250527113529459](https://pic.bitday.top/i/2025/05/27/irwv9m-0.png) + +2)准备配置文件 + +![image-20250527114751539](https://pic.bitday.top/i/2025/05/27/iz6r92-0.png) + +3)Docker部署 + +```yml +seeta-server: + image: seataio/seata-server:1.5.2 + container_name: seata-server + restart: unless-stopped + depends_on: + - mysql + - nacos + environment: + # 指定 Seata 注册中心和配置中心地址 + - SEATA_IP=192.168.0.107 # IDEA 可以访问到的宿主机 IP + - SEATA_SERVICE_PORT=17099 + - SEATA_CONFIG_TYPE=file + # 可视情况再加:SEATA_NACOS_SERVER_ADDR=nacos:8848 + networks: + - hmall-net + ports: + - "17099:7099" # TC 服务端口 + - "8099:8099" # 服务管理端口(Console) + volumes: + - ./seata:/seata-server/resources +``` + + + +### 微服务集成Seata + +1)引入依赖 + +```xml + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + org.springframework.cloud + spring-cloud-starter-bootstrap + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-seata + +``` + +2)在nacos上添加一个共享的seata配置,命名为`shared-seata.yaml`,你在bootstrap中引入该配置即可: + +```yaml +seata: + registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址 + type: nacos # 注册中心类型 nacos + nacos: + server-addr: 192.168.0.107:8848 # 替换为自己的nacos地址 + namespace: "" # namespace,默认为空 + group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP + application: seata-server # seata服务名称 + username: nacos + password: nacos + tx-service-group: hmall # 事务组名称 + service: + vgroup-mapping: # 事务组与tc集群的映射关系 + hmall: "default" +``` + +这段配置是告诉你的微服务如何去「找到并使用」Seata 的 TC(Transaction Coordinator)服务,以便在本地发起、提交或回滚分布式事务。 + + + +### XA模式 + +![image-20250527140420062](https://pic.bitday.top/i/2025/05/27/n80a47-0.png) + +`XA`模式的优点是什么? + +- 事务的**强一致性**,满足ACID原则 +- 常用数据库都支持,实现简单,并且没有代码侵入 + +`XA`模式的缺点是什么? + +- 因为**一阶段需要锁定数据库资源,等待二阶段结束才释放**,性能较差 +- 依赖关系型数据库实现事务 + + + +**实现方式** + +1)在Nacos中的共享shared-seata.yaml配置文件中设置: + +```yaml +seata: + data-source-proxy-mode: XA +``` + +2)利用`@GlobalTransactional`标记分布式事务的入口方法 + +```java +@GlobalTransactional +public Long createOrder(OrderFormDTO orderFormDTO) { + ... +} +``` + +3)子事务中方法前添加`@Transactional` ,方便回滚 + + + +### AT模式 + +![image-20250527162315431](https://pic.bitday.top/i/2025/05/27/qudips-0.png) + +简述`AT`模式与`XA`模式最大的区别是什么? + +- `XA`模式一阶段不提交事务,锁定资源;`AT`模式一阶段直接提交,不锁定资源。 +- `XA`模式依赖数据库机制实现回滚;`AT`模式利用数据快照实现数据回滚。 +- `XA`模式强一致;`AT`模式最终一致(存在短暂不一致) + + + +实现方式: + +1)为需要的微服务数据库中**创建undo_log表** + +```mysql +-- for AT mode you must to init this sql for you business database. the seata server not need it. +CREATE TABLE IF NOT EXISTS `undo_log` +( + `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id', + `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id', + `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization', + `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info', + `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status', + `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime', + `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime', + UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table'; + +``` + +2)微服务的配置中设置(其实不设置,默认也是AT模式) + +``` +seata: + data-source-proxy-mode: AT +``` + diff --git a/自学/消息队列MQ.md b/自学/消息队列MQ.md new file mode 100644 index 0000000..bc6a39f --- /dev/null +++ b/自学/消息队列MQ.md @@ -0,0 +1,64 @@ +# 消息队列MQ + +## 初识MQ + +### **同步调用** + +image-20250527173401081 + +同步调用有3个问题: + +- **拓展性差**,每次有新的需求,现有支付逻辑都要跟着变化,代码经常变动 +- **性能下降**,每次远程调用,调用者都是阻塞等待状态。最终整个业务的响应时长就是每次远程调用的执行时长之和 +- **级联失败**,当交易服务、通知服务出现故障时,整个事务都会回滚,交易失败。 + + + +### 异步调用 + +![image-20250527175753038](https://pic.bitday.top/i/2025/05/27/t2dfdb-0.png) + + + +### 技术选型 + +![image-20250527190824767](https://pic.bitday.top/i/2025/05/27/vk3zfw-0.png) + + + +## RabbitMQ + +### 部署 + +```yml +mq: + image: rabbitmq:3.8-management + container_name: mq + restart: unless-stopped + hostname: mq + environment: + RABBITMQ_DEFAULT_USER: admin + RABBITMQ_DEFAULT_PASS: "admin" + RABBITMQ_PLUGINS_DIR: "/plugins:/custom-plugins" + ports: + - "15672:15672" + - "5672:5672" + volumes: + - ./mq-plugins:/custom-plugins + networks: + - hmall-net +``` + +http://localhost:15672/ 访问控制台 + + + +### 架构图 + +![image-20250527200935901](https://pic.bitday.top/i/2025/05/27/x8b2ej-0.png) + +- **`publisher`**:生产者,发送消息的一方 +- **`consumer`**:消费者,消费消息的一方 +- **`queue`**:队列,存储消息。生产者投递的消息会暂存在消息队列中,等待消费者处理 +- **`exchange`**:交换机,负责消息路由。生产者发送的消息由交换机决定投递到哪个队列。**不存储** +- **`virtual host`**:虚拟主机,起到数据隔离的作用。每个虚拟主机相互独立,有各自的exchange、queue \ No newline at end of file