day03
微服務保護和分布式事務
微服務保護
微服務雪崩問題:某個微服務出現故障,導致調用鏈上的集群都被阻塞
解決方案:
- 請求限流:限制或控制接口訪問的并發流量,避免服務因流量激增而出現故障。
- 線程隔離:控制業務可用的線程數量,將故障隔離在一定范圍內
- 服務熔斷:將異常比例過高的接口斷開,拒絕所有請求,直接走fallback
- fallback:失敗處理邏輯,讓業務失敗時不拋出異常,返回默認數據或友好提示
常用工具:sentinel
sentinel是阿里云開源的一個微服務保護方案,主要包括核心jar包和控制臺兩個模塊
請求限流
在sentinel中,針對某個
簇點進行流控,限制QPS,簇點就是controller層的一個個請求方法
線程隔離
在sentinel中,針對某個
簇點進行流控,設置并發線程數,這樣就能限制該業務的線程資源由于是對微服務調用,所以我們要配置openFeign整合sentinel:
<!--sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
- openFeign整合sentinel
feign: sentinel: enabled: true # 開啟feign對sentinel的支持
- 默認情況下SpringBoot項目的tomcat最大線程數是200,允許的最大連接是8492,單機測試很難打滿。因此修改tomcat連接配置
server: port: 8082 tomcat: threads: max: 50 # 允許的最大線程數 accept-count: 50 # 最大排隊等待數量 max-connections: 100 # 允許的最大連接
- 在sentinel中設置簇點并發線程數即可實現線程隔離
服務熔斷
由于設置請求限流和線程隔離,這樣會導致接口的QPS較低,對于這些請求,我們不一定要拋出異常,可以進行
降級或熔斷處理
- 降級處理
觸發限流或熔斷后,不一定要直接拋出異常,可以讓該請求走
降級邏輯fallback,返回一些默認數據或友好數據給FeignClient編寫失敗后的降級邏輯有兩種方式:
方式一:FallbackClass,無法對遠程調用的異常做處理
方式二:FallbackFactory,可以對遠程調用的異常做處理,我們一般選擇這種方式。
降級處理實現(針對ItemClient):
- 定義一個類實現
FallbackFactory<ItemClient>,這里指定泛型為<ItemClient>表明是ItemClient的降級處理邏輯- 重寫
create方法,該方法的目的是返回一個新ItemClient對象- 在
return new ItemClient(){}中重寫接口方法,為各個接口添加降級處理- 當觸發限流時,就會走這里的降級邏輯
package com.hmall.api.fallback; import com.hmall.api.client.ItemClient; import com.hmall.api.dto.ItemDTO; import com.hmall.api.dto.OrderDetailDTO; import com.hmall.common.exception.BizIllegalException; import com.hmall.common.utils.CollUtils; import org.springframework.cloud.openfeign.FallbackFactory; import java.util.Collection; import java.util.List; public class ItemFallbckFactory implements FallbackFactory<ItemClient> { /** * 創建并返回一個新的ItemClient類 * @param cause * @return */ @Override public ItemClient create(Throwable cause) { return new ItemClient() { //對queryItemByIds接口做降級處理 @Override public List<ItemDTO> queryItemByIds(Collection<Long> ids) { return CollUtils.emptyList(); } //對deductStock接口做降級處理 @Override public void deductStock(List<OrderDetailDTO> items) { throw new BizIllegalException(cause); } }; } }
- 同時,要將ItemFallbckFactory注冊為一個bean,在配置類中聲明
@Bean public ItemFallbckFactory itemFallbckFactory(){ return new ItemFallbckFactory(); }
- 為ItemClient添加fallback參數
@FeignClient(value = "item-service", fallbackFactory = ItemFallbckFactory.class) public interface ItemClient {...}
- 服務熔斷
在sentinel控制臺中可針對某個簇點配置熔斷策略,配置策略主要有三種:慢調用比例、異常比例、異常數
分布式事務
分布式事務指多個微服務的分支事務關聯形成的全局事務,無法滿足事務的ACID特性,因此需要引入外部服務來解決分布式事務
分布式事務解決方案——Seata
Seata架構
- TC (Transaction Coordinator) -協調者:維護全局和分支事務的狀態,協調全局事務提交或回滾。
- TM (Transaction Manager) - 事務管理器:定義全局事務的范圍、開始全局事務、提交或回滾全局事務。
- RM (Resource Manager) - 資源管理器:管理分支事務,與TC交談以注冊分支事務和報告分支事務的狀態,并驅動分支事務提交或回滾。

Seata服務部署
-
微服務集成seata
為了方便集成seata,將配置文件上傳到nacos
- 在微服務中引入相關依賴和seata依賴
<!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency>
- nacos添加seata配置文件.yaml,微服務拉取該配置文件
seata: registry: # TC服務注冊中心的配置,微服務根據這些信息去注冊中心獲取tc服務地址 type: nacos # 注冊中心類型 nacos nacos: server-addr: 192.168.48.100: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"
- 將
@Transactional注解改為seata提供的@GlobalTransactional注解,即開啟分布式事務的入口
seata的分布式事務解決方案
seata提供了四種解決方案:
- XA:當一個分支事務執行完畢后,不立刻提交,持有鎖,報告狀態,等所有分支事務完成后,由TC來通知提交/回滾
![]()
- TCC
- AT:記錄undo.log快照,分支事務執行成功后直接提交,釋放鎖,報告狀態
![]()
- SAGA
簡述
AT模式與XA模式最大的區別是什么?
XA模式一階段不提交事務,鎖定資源;AT模式一階段直接提交,不鎖定資源。XA模式依賴數據庫機制實現回滾;AT模式利用數據快照實現數據回滾。XA模式強一致;AT模式最終一致
RabbitMQ
RabbitMQ是基于Erlang語言開發的開源消息通信中間件,官網地址
RabbitMQ的docker部署
- 15672:RabbitMQ提供的管理控制臺的端口
- 5672:RabbitMQ的消息發送處理接口
docker run \
-e RABBITMQ_DEFAULT_USER=skywalker \
-e RABBITMQ_DEFAULT_PASS=123321 \
-v mq-plugins:/plugins \
--name mq \
--hostname mq \
-p 15672:15672 \
-p 5672:5672 \
--network hm-net\
-d \
rabbitmq:3.8-management
RabbitMQ相關概念和原理
可將消息直接發給隊列,或發給交換機,再由交換機轉發給綁定的隊列
publisher:生產者,也就是發送消息的一方consumer:消費者,也就是消費消息的一方queue:隊列,存儲消息。生產者投遞的消息會暫存在消息隊列中,等待消費者處理exchange:交換機,負責消息路由。生產者發送的消息由交換機決定投遞到哪個隊列。virtual host:虛擬主機,起到數據隔離的作用。每個虛擬主機相互獨立,有各自的exchange、queue
Spring集成RabbitMQ
RabbitMQ基于AMQP協議通信,Spring官方基于RabbitMQ提供了SpringAMQP消息收發模板工具,只需引入依賴并配置rabbitmq即可
- 引入依賴
<!--AMQP依賴,包含RabbitMQ--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
- 配置rabbitmq
spring: rabbitmq: host: 192.168.150.101 # 你的虛擬機IP port: 5672 # 端口 virtual-host: /hmall # 虛擬主機 username: hmall # 用戶名 password: 123 # 密碼
- 發送消息
注入
SpringAMQP中的RabbitTemplate對象,調用convertAndSend(args[])方法發送消息
- 接收消息
在方法上聲明
@RabbitListener注解,指定交換機、隊列等參數,即可通過形參接收到對應隊列的消息
交換機類型
交換機的類型有四種:
- Fanout:廣播,將消息交給所有綁定到交換機的隊列。我們最早在控制臺使用的正是Fanout交換機
- Direct:訂閱,基于RoutingKey(路由key)發送給訂閱了消息的隊列
- Topic:通配符訂閱,與Direct類似,只不過RoutingKey可以使用通配符
- Headers:頭匹配,基于MQ的消息頭匹配,用的較少。
聲明隊列和交換機
- 方式一:基于Bean來聲明
- 方式二:基于
@RabbitListener注解聲明
配置JSON消息轉換器
在生產者和消費者都要配置
//導入依賴
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.10</version>
</dependency>
@Bean
public MessageConverter messageConverter(){
// 1.定義消息轉換器
Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
// 2.配置自動創建消息id,用于識別不同消息,也可以在業務中基于ID判斷是否是重復消息
jackson2JsonMessageConverter.setCreateMessageIds(true);
return jackson2JsonMessageConverter;
}

浙公網安備 33010602011771號