文章目录
- 前言
- 一、微服务保护
- 二、Sentinel
- 2.1 微服务整合
- 2.2 簇点链路
- 2.3 请求限流
- 2.4 线程隔离
- 2.5 服务熔断
- 三、分布式事务
- 3.1 Seata
- 3.1.1 Seata架构
- 3.1.2 部署TC服务
- 3.1.3 微服务集成Seata
- 3.2 XA模式
- 3.3 AT模式
前言
微服务之间为什么会雪崩?怎么解决雪崩问题?
如何采用Sentiel整合微服务实现请求限流、线程隔离以及服务熔断问题。
怎么集成Seata解决微服务之间引发的分布式事务问题?
一、微服务保护
1、请求限流
限制访问微服务的请求的并发量,避免服务因流量激增出现故障。
2、线程隔离
舱壁模式,模拟船舱隔板的防水原理。通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散。
例如:查询购物车的时候需要查询商品,为了避免因商品服务出现故障导致购物车服务级联失败,我们可以把购物车业务中查询商品的部分隔离起来,限制可用的线程资源,即便商品服务出现故障,最多导致查询购物车业务故障,并且可用的线程资源也被限定在一定范围,不会导致整个购物车服务崩溃。
3、服务熔断
由断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,则拦截该接口的请求。
熔断期间,所有请求快速失败,全都走fallback逻辑。
4、失败处理
给业务编写一个调用失败时的处理的逻辑,称为fallback。当调用出现故障(比如无线程可用)时,按照失败处理逻辑执行业务并返回,而不是直接抛出异常。
二、Sentinel
Sentinel是阿里巴巴开源的一款服务保护框架。
2.1 微服务整合
1、引入sentinel依赖
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、配置控制台。
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090 #访问地址
3、访问微服务块的任意断点,如访问查询购物车接口,sentinel的客户端就会将服务访问的信息提交到sentinel-dashboard控制台
2.2 簇点链路
单机调用链路。是一次请求进入服务后经过的每一个被Sentinel监控的资源链。默认Sentinel会监控SpringMVC的每一个Endpoint(http接口)。限流、熔断等都是针对簇点链路中的资源设置的。而资源名默认就是接口的请求路径。
打开Sentinel的请求方式前缀,把请求方式 + 请求路径作为簇点资源名。
2.3 请求限流
在簇点链路后面点击流控按钮,即可对其做限流配置。
簇点资源的流量限制在了每秒6个,也就是最大QPS为6.
2.4 线程隔离
解决服务故障
实现步骤
1、OpenFeign整合Sentinel,为了开启远程调用feignclient作为簇点,可以被流量监控。
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
2、配置线程隔离
2.5 服务熔断
请求失败不应该抛异常,为了让用户体验更好,可以返回一些默认数据或者友好提示,查询失败设置一个降级处理逻辑。
对于这种不太健康的接口,应该直接停止调用,避免影响到当前服务。也就是将接口熔断。
实现步骤
1、编写降级逻辑
给FeignClient编写失败后的降级逻辑两种方式:
- 方式一:FallbackClass,无法对远程调用的异常做处理
- 方式二:FallbackFactory,可以对远程调用的异常做处理,我们一般选择这种方式。
步骤1:定义一个降级处理类ItemClientFallback,实现FallbackFactory。
@Slf4j
public class ItemClientFallback implements FallbackFactory<ItemClient> {
@Override
public ItemClient create(Throwable cause) {
return new ItemClient() {
@Override
public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause);
// 查询购物车允许失败,查询失败,返回空集合
return CollUtils.emptyList();
}
@Override
public void deductStock(List<OrderDetailDTO> items) {
// 库存扣减业务需要触发事务回滚,查询失败,抛出异常
throw new BizIllegalException(cause);
}
};
}
}
步骤2:编写一个配置类,在配置类中将ItemClientFallback注册为一个Bean。
public class DefaultFeignConfig {
@Bean
public Logger.Level feginLogLevel(){
return Logger.Level.FULL;
}
@Bean
public ItemClientFallbackFactory itemClientFallbackFactory(){
return new ItemClientFallbackFactory();
}
}
步骤3:在ItemClient接口中使用ItemClientFallbackFactory
@FeignClient(value = "item-service",
fallbackFactory = ItemClientFallbackFactory.class)
public interface ItemClient {...}
2、服务熔断
由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。
断路器的工作状态切换有一个状态机来控制
- closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
- open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态持续一段时间后会进入half-open状态
- half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
- 请求成功:则切换到closed状态
- 请求失败:则切换到open状态
点击控制台中簇点资源后的熔断按钮,即可配置熔断策略
- RT超过200毫秒的请求调用就是慢调用
- 统计最近1000ms内的最少5次请求,如果慢调用比例不低于0.5,则触发熔断
- 熔断持续时长20s
三、分布式事务
如果一个业务需要多个服务合作完成,而且每一个服务都有事务,多个事务必须同时成功或失败,这样的事务就是分布式事务。其中的每个服务的事务就是一个分支事务。整个业务称为全局事务。
3.1 Seata
参与事务的多个分支事务互相无感知,不知道彼此的执行状态。找一个统一的事务协调者,与多个分支事务通信,检测每个分支事务的执行状态,保证全局事务下的每一个分支事务同时成功或失败即可。
3.1.1 Seata架构
- TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
- TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) - 资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
3.1.2 部署TC服务
TC服务是事务协调中心,是一个独立的微服务,需要单独部署。
基于数据库持久化存储,采用docker部署seata
具体部署不做说明。
3.1.3 微服务集成Seata
参与分布式事务的每一个微服务都需要集成Seata
实现步骤
1、引入依赖
为了方便各个微服务集成seata,需要把seata配置共享到nacos
<!--统一配置管理-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--读取bootstrap文件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
2、在nacos中配置seata
3、在微服务中添加bootstrap.yaml文件,定义nacos配置信息。
4、添加数据库表。seata的客户端在解决分布式事务的时候需要记录一些中间数据,保存在数据库中。要讲数据库表分别导入不同的微服务当中。
5、测试分布式事务
在订单业务方法上的@Transactional注解改为Seata提供的**@GlobalTransactional**
@GlobalTransactional注解就是在标记事务的起点,将来TM就会基于这个方法判断全局事务范围,初始化全局事务。
3.2 XA模式
Seata支持四种不同的分布式事务解决方案: XA、TCC、 AT、SAGA
XA 规范描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范提供了支持。
A是规范,目前主流数据库都实现了这种规范,实现的原理都是基于两阶段提交。
优点
- 事务的强一致性,满足ACID原则
- 常用数据库都支持,实现简单,并且没有代码侵入
缺点:
- 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
- 依赖关系型数据库实现事务
seata中实现XA
1、Nacos中的共享shared-seata.yaml配置文件中设置
seata:
data-source-proxy-mode: XA
2、@GlobalTransactional标记分布式事务的入口方法
3.3 AT模式
Seata主推的是AT模式,AT模式同样是分阶段提交的事务模型,不过缺弥补了XA模型中资源锁定周期过长的缺陷。
流程图
AT模式与XA模式最大的区别是什么?
XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
XA模式强一致;AT模式最终一致