微服务day5

1.服务保护和分布式事务

业务健壮性

例如在之前的查询购物车列表业务中,购物车服务需要查询最新的商品信息,与购物车数据做对比,提醒用户。大家设想一下,如果商品服务查询时发生故障,查询购物车列表在调用商品服务时,是不是也会异常?从而导致购物车查询失败。

但从业务角度来说,即便是商品查询失败,购物车列表也应该正确展示出来,哪怕是不包含最新的商品信息。

级联失败

商品服务业务并发较高,占用过多Tomcat连接。可能会导致商品服务所有接口响应时间增加,延迟变高,长时间阻塞,雪崩问题

跨服务的事务问题  

  • 商品服务:扣减库存

  • 订单服务:保存订单

  • 购物车服务:清理购物车

这些业务全部都是数据库的写操作,确保所有操作的同时成功或失败。但是这些操作在不同微服务,也就是不同的Tomcat,如何确保事务特性

  • 知道雪崩问题产生原因及常见解决方案

  • 能使用Sentinel实现服务保护

  • 理解分布式事务产生的原因

  • 能使用Seata解决分布式事务问题

  • 理解AT模式基本原理

2.微服务保护方案

请求限流

限制或控制接口访问的并发流量,避免服务因流量激增而出现故障。

线程隔离

当一个业务接口响应时间长,而且并发高时,就可能耗尽服务器的线程资源,导致服务内的其它接口收到影响。

轮船的船舱会被隔板分割为N个相互隔离的密闭舱,假如轮船触礁进水,只有损坏的部分密闭舱会进水,而其他舱由于相互隔离,并不会进水。这样就把进水控制在部分船体,避免了整个船舱进水而沉没。

为了避免某个接口故障或压力过大导致整个服务不可用限定每个接口可以使用的资源范围,也就是将其“隔离”起来

给查询购物车业务限定可用线程数量上限为20,这样即便查询购物车的请求因为查询商品服务而出现故障,也不会导致服务器的线程资源被耗尽,不会影响到其它接口。

服务熔断

线程隔离虽然避免了雪崩问题,但故障服务(商品服务)依然会拖慢购物车服务(服务调用方)的接口响应速度。而且商品查询的故障依然会导致查询购物车功能出现故障,购物车业务也变的不可用了。

所以,我们要做两件事情:

  • 编写服务降级逻辑:就是服务调用失败后的处理逻辑,根据业务场景,可以抛出异常,也可以返回友好提示或默认数据

  • 异常统计和熔断:统计服务提供方的异常比例,当比例过高表明该接口会影响到其它服务,应该拒绝调用该接口,而是直接走降级逻辑。

3.Sentinel

服务保护框架,目前已经加入SpringCloudAlibaba中

安装

微服务整合

cart-service  

 

重启cart-service并启动其它几个服务;通过浏览器访问购物车接口或者商城页面中操作购物车  

簇点链路,单机调用链路,是一次请求进入服务后经过的每一个被Sentinel监控的资源。

默认情况Sentinel会监控SpringMVC每一个Endpoint(接口)

/carts这个接口路径是其中一个簇点,对其进行限流、熔断、隔离等保护措施。

默认情况Sentinel会把路径作为簇点资源的名称,无法区分路径相同但请求方式不同的接口,查询、删除、修改等都被识别为一个簇点资源,这显然是不合适的。  

配置

请求限流

 查询购物车列表这个簇点资源的流量限制在了每秒6个,也就是最大QPS为6

线程隔离

OpenFeign整合Sentinel

cart-service

配置线程隔离

勾选的是并发线程数限制,查询功能最多使用5个线程,而不是5QPS。如果查询商品的接口每秒处理2个请求,则5个线程的实际QPS在10左右,而超出的请求自然会被拒绝。

 

服务熔断

利用线程隔离对查询购物车业务进行隔离,保护了购物车服务的其它接口。由于查询商品的功能耗时较高(我们模拟了500毫秒延时),再加上线程隔离限定了线程数为5,导致接口吞吐能力有限,最终QPS只有10左右。这就导致了几个问题:

第一,超出的QPS上限的请求就只能抛出异常,从而导致购物车的查询失败。但从业务角度来说,即便没有查询到最新的商品信息,购物车也应该展示给用户,用户体验更好。给查询失败设置一个降级处理逻辑

第二,由于查询商品的延迟较高(模拟的500ms),从而导致查询购物车的响应时间也变的很长。这样不仅拖慢了购物车服务,消耗了购物车服务的更多资源,而且用户体验也很差。对于商品服务这种不太健康的接口,我们应该直接停止调用,直接走降级逻辑,避免影响到当前服务。也就是将商品查询接口熔断

服务降级

触发限流或熔断后的请求不一定要直接报错,也可以返回一些默认数据或者友好提示,也被称为服务降级,用户体验会更好。

给FeignClient编写失败后的降级逻辑有两种方式:

  • 方式一:FallbackClass,无法对远程调用的异常做处理

  • 方式二:FallbackFactory,可以对远程调用的异常做处理,我们一般选择这种方式。

编写降级处理类

注册降级处理类

应用降级处理类

configuration = DefaultFeignConfig.class

此属性用于提供自定义的 Feign 客户端配置。当你需要对 Feign 客户端进行特定的配置时,

  • 当你想要为 Feign 客户端配置特殊的 HTTP 客户端或调整超时设置时。

  • 当你需要对所有 Feign 请求进行统一的编码或解码处理时。

fallbackFactory = ItemClientFallback.class

此属性用于指定一个回退工厂类,该工厂类负责在服务调用失败时提供备选逻辑。这在服务降级和熔断场景中非常有用

  • 当依赖的服务暂时不可用或响应时间过长时,使用回退逻辑来返回一些默认信息或缓存数据。

  • 在促销活动等高流量场景下,为了防止服务雪崩,主动使用回退逻辑来保护系统。

服务熔断

查询商品的RT较高(模拟的500ms),从而导致查询购物车的RT也变的很长。这样不仅拖慢了购物车服务,消耗了购物车服务的更多资源,

对于商品服务这种不太健康的接口,我们应该停止调用,直接走降级逻辑,避免影响到当前服务。将商品查询接口熔断当商品服务接口恢复正常后,再允许调用。这其实就是断路器的工作模式

Sentinel中的断路器不仅可以统计某个接口的慢请求比例,还可以统计异常请求比例。当这些比例超出阈值时,就会熔断该接口,即拦截访问该接口的一切请求,降级处理;当该接口恢复正常时,再放行对于该接口的请求。

这种是按照慢调用比例来做熔断,上述配置的含义是:

  • RT超过200毫秒的请求调用就是慢调用

  • 统计最近1000ms内的最少5次请求,如果慢调用比例不低于0.5,则触发熔断

  • 熔断持续时长20s  

 在一开始一段时间是允许访问的,后来触发熔断后,查询商品服务的接口通过QPS直接为0,所有请求都被熔断了。而查询购物车的本身并没有受到影响。

4.分布式事务

由于订单、购物车、商品分别在三个不同的微服务,而每个微服务都有自己独立的数据库,因此下单过程中就会跨多个数据库完成业务。而每个微服务都会执行自己的本地事务

每个微服务的本地事务,也可以称为分支事务。多个有关联的分支事务一起就组成了全局事务

保证整个全局事务同时成功或失败。  

每个单独的业务都能在本地遵循ACID,但是它们互相之间没有感知,不知道有人失败了,无法保证最终结果的统一,也就无法遵循ACID的事务特性了。  

Seata开源的分布式事务问题框架

 找统一的事务协调者,与多个分支事务通信,检测每个分支事务的执行状态,保证全局事务下的每一个分支事务同时成功或失败即可。

Seata也不例外,在Seata的事务管理中有三个重要的角色:

TMRM为Seata的客户端部分

TMRM就会协助微服务,实现本地分支事务与TC之间交互,实现事务的提交或回滚。

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

部署TC服务

准备数据库表seata-tc.sql

配置文件,将整个seata文件夹拷贝到虚拟机的/root目录

微服务集成Seata

trade-service引入seata依赖,还要引入nacos依赖

 

cart-service引入seata依赖

item-service引入seata依赖,还要引入nacos依赖,bootstrap

 

改造配置

在nacos上添加一个共享的seata配置,命名为shared-seata.yaml

trade-service

创建 hmall\trade-service\src\main\resources\bootstrap.yml

trade-service  

cart-service   新增 shared-seata.yaml 共享配置文件

 item-service

添加数据库表

 seata的客户端在解决分布式事务的时候需要记录一些中间数据,保存在数据库中。因此我们要先准备这样的表。

seata-at.sql分别文件导入hm-trade、hm-cart、hm-item三个数据库中

 测试的分布式事务

 

 @GlobalTransactional注解就是在标记事务的起点,将来TM就会基于这个方法判断全局事务范围,初始化全局事务

5.Seata支持四种不同的分布式事务解决方案  

  • XA

  • TCC

  • AT (默认)

  • SAGA

XA 规范 是分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范描述了全局的TM与局部的RM之间的接口

XA是规范,实现的原理都是基于两阶段提交

一阶段:

  • 事务协调者通知每个事务参与者执行本地事务

  • 本地事务执行完成后报告事务执行状态给事务协调者,此时事务不提交,继续持有数据库锁

二阶段:

  • 事务协调者基于一阶段的报告来判断下一步操作

  • 如果一阶段都成功,则通知所有事务参与者,提交事务

  • 如果一阶段任意一个参与者失败,则通知所有事务参与者回滚事务

6.Seata对原始的XA模式做了简单的封装和改造

RM一阶段的工作:

  1. 注册分支事务到TC

  2. 执行分支业务sql不提交

  3. 报告执行状态到TC

TC二阶段的工作:

  1. TC检测各分支事务执行状态

    • 如果都成功,通知所有RM提交事务

    • 如果有失败,通知所有RM回滚事务

RM二阶段的工作:

  • 接收TC指令,提交或回滚事务

XA模式的优点是什么?

  • 事务的强一致性,满足ACID原则

  • 常用数据库都支持,实现简单,并且没有代码侵入

XA模式的缺点是什么?

  • 一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差

  • 依赖关系型数据库实现事务

7.AT模式

AT模式同样是分阶段提交的事务模型,弥补了XA模型中资源锁定周期过长的缺陷  

阶段一RM的工作:

  • 注册分支事务

  • 记录undo-log(数据快照)

  • 执行业务sql并提交

  • 报告事务状态

阶段二提交时RM的工作:

  • 删除undo-log即可

阶段二回滚时RM的工作:

  • 根据undo-log恢复数据到更新前

XA  

AT模式 

简述AT模式与XA模式最大的区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。

  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。

  • XA模式强一致;AT模式最终一致

可见,AT模式使用起来更加简单,无业务侵入,性能更好。因此企业90%的分布式事务都可以用AT模式来解决。

8.编写降级逻辑

给黑马商城中现有的FeignClient编写对应的降级逻辑

改造项目中每一个微服务,将OpenFeign与Sentinel整合

编写Fallback

com.hmall.api.fallback.CartClientFallback

com.hmall.api.fallback.TradeClientFallback

com.hmall.api.fallback.UserClientFallback

注册上述3个Fallback

 com.hmall.api.config.DefaultFeignConfig

 分别在CartClient、TradeClient、UserClient中应用Fallback熔断降级类

 

pom配置Sentinel

item-service、trade-service、pay-service、user-servic添加了配置共享与Sentinel依赖坐标

修改item-service---pay-service---trade-service---user-service .yml配置

item-service

pay-service

trade-service

user-service

 

 9.解决分布式事务

用户如果选择余额支付,前端会将请求发送到pay-service模块。而这个模块要做三件事情:

  • 直接从user-service模块调用接口,扣除余额付款

  • 更新本地(pay-service)交易流水表状态

  • 通知交易服务(trade-service)更新其中的业务订单状态

创建数据库表

添加seata事务注解

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值