服务保护和分布式事务
雪崩问题
原因分析
微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩
产生原因:
- 微服务相互调用,服务提供者出现故障或阻塞
- 服务调用者没有做好异常处理,导致自身故障
- 调用链中的所有服务级联失败,导致整个集群故障
解决思路:
- 尽量避免服务出现故障或者阻塞。
√ 保证代码的健壮性;
√ 保证网络通畅;
√ 能应对较高的并发请求; - 服务调用者做好远程调用异常的后备方案,避免故障扩散
服务保护方案
- 请求限流:限制访问微服务的请求的并发量,避免服务因流量激增出现故障
- 线程隔离:也叫做舱壁模式,模拟船舱隔板的防水原理。通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散
- 服务熔断:由断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,则拦截该接口的请求
- 失败处理: 定义fallback逻辑,让业务失败时不再抛出异常,而是返回默认数据或友好提示
常见的服务保护技术有:Sentinel和Hystrix,毫无疑问这里主要讲述Sentinel
Sentinel
官方网址->home | Sentinel
微服务整合
引入sentinel依赖
1
2
3
4
5<!--sentinel-->
<deependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</deependency>配置控制台
修改application.yaml文件,添加下面内容:1
2
3
4
5spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090访问任意接口后,就可以在sentinel的控制台中看见
簇点链路
- 就是单机调用链路。是一次请求进入服务后经过的每一个被Sentinel监控的资源链。默认Sentinel会监控SpringMVC的每一个Endpoint(http接口)。限流、熔断等都是针对簇点链路中的资源设置的。而资源名默认就是接口的请求路径。
- Restful风格的API请求路径一般都相同,这会导致簇点资源名称重复。因此我们要修改配置,把请求方式+请求路径作为簇点资源名称:
1
2
3
4
5
6spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
http--method-specify: true # 开启请求方式前缀
请求限流
在簇点链路后面点击流控按钮,即可对其做限流配置
QPS:每秒钟限制请求的数量
单机阈值:每秒并发数
线程隔离
与请求限流相同,但选择并发线程数
分析:五个并发线程数的话,如果单线程QPS为2,则5线程QPS为10
Fallback
将FeignClient作为Sentinel的簇点资源:
1
2
3feign:
sentinel:
enabled: trueFeignClient的Fallback有两种配置方式
- 方式一:FallbackClass,无法对远程调用的异常做处理
- 方式二:FallbackFactory,可以对远程调用的异常做处理,通常都会选择这种
添加步骤
- 自定义类,实现FallbackFactory,编写对某个FeignClient的fallback逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UserClientFallbackFactory implements FallbackFactory<UserClient>{
public UserClient create(Throwable throwable){
//创建UserClient接口实现类,实现其中的方法,编写失败降级的处理逻辑
return new UserClient(){
public User findById(Long id){
//记录异常信息,可以返回空或者抛出异常
log.error("查询用户失败", throwable);
return null;
}
};
}
} - 将刚刚定义的UserClientFallbackFactory注册为一个Bean:
1
2
3
4
public UserClientFallbackFactory userClientFallback(){
return new UserClientFallbackFactory();
} - 在UserClient接口中使用UserClientFallbackFactory:
1
2
3
4
5
6
public interface UserClient{
User findById( Long id);
}
服务熔断
点击控制台中簇点资源后的熔断按钮,即可配置熔断策略
分布式事务
在分布式系统中,如果一个业务需要多个服务合作完成,而且每一个服务都有事务,多个事物必须同时成功或失败,这样的事物就是分布式事务。其中的每个服务的事务就是一个分支事务。整个业务称为全局事务
为了解决分布式事务,各个子事务之间必须能感知到彼此的事务状态,才能保证状态一致->事务协调者
Seata架构
Seata事务管理中有三个重要的角色:
- TC(Transaction Coordinator)-事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚
- TM(Transaction Manager)-事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM(Resource Manager)-资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态
部署TC服务
- 准备数据库表
- Seata支持多种存储模式,但考虑到持久化的需要,我们一般选择基于数据库存储。
- global_table:全局表
- branch_table:分支表
- distributed_lock:分布式锁
- lock_table:锁
- Seata支持多种存储模式,但考虑到持久化的需要,我们一般选择基于数据库存储。
- 准备配置文件
- docker部署
微服务集成Seata
- 引入依赖:
1
2
3
4<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency> - 添加配置,让微服务找到TC服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15seata:
registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
# 参考tc服务自己的registry.conf中的配置
type: nacos
nacos: # tc
server-addr: 127.0.0.1:8848
namespace: ""
group: DEFAULT_GROUP
application: seata-tc-server # tc服务在nacos中的服务名称
usernamne: nacos
password: nacos
tx-service-group: seata-demo # 事务组名称
service:
vgroup-mapping: # 事务组与TC服务cluster的映射关系
seata-demo: "default" # 集群的名称
XA模式
XA规范是X/Open组织定义的分布式事务管理(DTP)标准,XA规范描述了全局的TM与局部的RM之间的接口,几乎所有主流的关系型数据库都对XA规范提供了支持。
一阶段的工作:
- RM注册分支事务到TC
- RM执行分支业务sql但不提交
- RM报告执行状态到TC
二阶段工作:
- TC检测各分支事务执行状态
- 如果都成功,通知所有RM提交事务
- 如果有失败,通知所有RM回滚事务
- RM接收TC指令,提交或回滚事务
优点:
- 事务的强一致性,满足ACID原则
- 常用数据库都支持,实现简单,并且没有代码入侵
缺点
- 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
- 依赖关系型数据库实现事务
实现XA模式
Seata的starter已经完成了XA模式的自动装配,实现非常简单,步骤如下:
- 修改application.yaml 文件(每个参与事务的微服务),开启XA模式
1
2seata:
data-source-proxy-mode: XA # 开启数据源代理的XA模式 - 给发起全局事务的入口方法添加
@GlobalTransactional注解,eg:1
2
3
4
5
6
public Long CreateOrder(OrderFromDTO oder){
// 业务逻辑...略
return order.getId();
} - 重启服务测试
AT模式
Seata主推的是AT模式,AT模式同样是分阶段提交的事务模型,不过却弥补了XA模型中资源锁定周期过长的缺陷。
- 阶段一RM的工作:
- 注册分支事务
- 记录undo-log(数据快照)
- 执行业务sql并提交
- 报告事务状态
- 阶段二提交时RM的工作:
- 删除undo-log即可
- 阶段二回滚时RM的工作:
- 根据undo-log恢复数据到更新前
- XA依赖数据机制实现回滚,AT通过快照回滚
- XA强一致,AT最终一致
实现AT模式
- 添加sql数据表到微服务对应的数据库中 (undo_log)
- 修改application.yaml文件,改为AT模式
1
2seata:
data-source-proxy-mode: AT # 开启数据源代理的AT模式
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Blog of Sof!
评论






