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的事务管理中有三个重要的角色:
TM和RM为Seata的客户端部分
TM和RM就会协助微服务,实现本地分支事务与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一阶段的工作:
注册分支事务到
TC执行分支业务sql但不提交
报告执行状态到
TC
TC二阶段的工作:
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事务注解






















1160

被折叠的 条评论
为什么被折叠?



