建设网站模板,企业邮箱怎么写,网站建设公司的企业特色有哪些,北京aso优化本文研究微服务架构的服务保护与分布式事务。服务保护方面#xff0c;提出限流、隔离、熔断三种策略#xff0c;搭配使用 Sentinel 服务降级技术。分布式事务方面#xff0c;列举使用 Seata 的 XA 和 AT 模式#xff0c;为微服务稳定性提供解决方案。 在微服务架构中#… 本文研究微服务架构的服务保护与分布式事务。服务保护方面提出限流、隔离、熔断三种策略搭配使用 Sentinel 服务降级技术。分布式事务方面列举使用 Seata 的 XA 和 AT 模式为微服务稳定性提供解决方案。 在微服务架构中远程调用面临业务健壮性和级联失败问题。
例如购物车服务依赖商品服务查询信息一旦商品服务故障或响应延迟可能导致购物车服务调用失败、响应变慢甚至阻塞进而影响用户体验和整个服务的可用性甚至引发级联故障拖累整个微服务集群性能。 缓存雪崩产生原因 级联失败导致的资源耗尽 问题描述当某个服务如商品服务的并发请求过高时可能会导致其资源被耗尽。这使得商品服务的响应时间显著增加甚至出现超时或阻塞的情况。 影响 服务响应延迟依赖商品服务的购物车服务需要等待商品服务的响应这会导致购物车服务的响应时间也大幅增加。 资源耗尽如果购物车服务的请求量较大它会占用更多的连接资源来等待商品服务的响应从而导致购物车服务自身的资源如Tomcat连接池也被耗尽。 级联阻塞购物车服务的阻塞可能会进一步影响其他依赖购物车服务的服务最终导致整个微服务集群的性能急剧下降甚至不可用。 1.微服务保护
保证服务运行的健壮性避免级联失败导致的雪崩问题就属于微服务保护。这章我们就一起来学习一下微服务保护的常见方案以及对应的技术。 1.1.服务保护方案
微服务保护的方案有很多比如 请求限流 线程隔离 服务熔断
这些方案或多或少都会导致服务的体验上略有下降比如请求限流降低了并发上限线程隔离降低了可用资源数量服务熔断降低了服务的完整度部分服务变的不可用或弱可用。因此这些方案都属于服务降级的方案。但通过这些方案服务的健壮性得到了提升。 1.1.1.请求限流 控制流量 1.1.2.线程隔离 1.1.3.服务熔断
线程隔离虽然避免了雪崩问题但故障服务商品服务依然会拖慢购物车服务服务调用方的接口响应速度。而且商品查询的故障依然会导致查询购物车功能出现故障购物车业务也变的不可用了。 所以我们要做两件事情 编写服务降级逻辑就是服务调用失败后的处理逻辑根据业务场景可以抛出异常也可以返回友好提示或默认数据。 异常统计和熔断统计服务提供方的异常比例当比例过高表明该接口会影响到其它服务应该拒绝调用该接口而是直接走降级逻辑。 1.2.Sentinel
微服务保护的技术有很多但在目前国内使用较多的还是Sentinel所以接下来我们学习Sentinel的使用。 1.2.1.安装Sentinel
1.解压jar包 2.登录localhost:8090 3.访问cart-service的任意端点 重启cart-service然后访问查询购物车接口sentinel的客户端就会将服务访问的信息提交到sentinel-dashboard控制台。并展示出统计信息 点击簇点链路菜单会看到下面的页面 在微服务架构中簇点链路是指一次请求进入服务后经过的所有被Sentinel监控的资源节点所形成的调用路径。默认情况下Sentinel会自动监控Spring MVC中的每一个Endpoint接口。 例如/carts接口路径就是一个典型的簇点。通过Sentinel我们可以针对该接口实施限流、熔断、隔离等保护措施从而有效保障服务的稳定性和可靠性。 默认情况下Sentinel会把路径作为簇点资源的名称无法区分路径相同但请求方式不同的接口查询、删除、修改等都被识别为一个簇点资源这显然是不合适的。 所以我们可以选择打开Sentinel的请求方式前缀把请求方式 请求路径作为簇点资源名
1.在cart-service的application.yml中添加下面的配置
spring:cloud:sentinel:transport:dashboard: localhost:8090http-method-specify: true # 开启请求方式前缀
2.重启服务通过页面访问购物车的相关接口可以看到sentinel控制台的簇点链路发生了变化 1.3.请求限流
1.在簇点链路后面点击流控按钮即可对其做限流配置 2.我们利用Jemeter做限流测试我们每秒发出10个请求QPS最终监控结果如下 3.查看Sentinel控制台 可以看出这个接口的通过QPS稳定在6附近而拒绝的QPS在4附近符合我们的预期。 1.4.线程隔离
限流可以降低服务器压力尽量减少因并发流量引起的服务故障的概率但并不能完全避免服务故障。一旦某个服务出现故障我们必须隔离对这个服务的调用避免发生雪崩。 比如查询购物车的时候需要查询商品为了避免因商品服务出现故障导致购物车服务级联失败我们可以把购物车业务中查询商品的部分隔离起来限制可用的线程资源 这样即便商品服务出现故障最多导致查询购物车业务故障并且可用的线程资源也被限定在一定范围不会导致整个购物车服务崩溃。
所以我们要对查询商品的FeignClient接口做线程隔离。 1.4.1.OpenFeign整合Sentinel
1.修改cart-service模块的application.yml文件开启Feign的sentinel功能
feign:sentinel:enabled: true # 开启feign对sentinel的支持 默认SpringBoot的tomcat最大线程数是200允许的最大连接是8492单机测试很难打满。 2.配置cart-service模块的application.yml文件修改tomcat连接
server:port: 8082tomcat:threads:max: 50 # 允许的最大线程数accept-count: 50 # 最大排队等待数量max-connections: 100 # 允许的最大连接
3.重启cart-service服务观察到查询商品的FeignClient自动变成了一个簇点资源 1.4.2.配置线程隔离
1.点击查询商品的FeignClient对应的簇点资源后面的流控按钮在弹出的表单中填写下面内容 2.利用Jemeter测试发送请求 3.查看Sentinel控制台 1.5.服务熔断
在上节课我们利用线程隔离对查询购物车业务进行隔离保护了购物车服务的其它接口。由于查询商品的功能耗时较高我们模拟了500毫秒延时再加上线程隔离限定了线程数为5导致接口吞吐能力有限最终QPS只有10左右。这就导致了几个问题
第一超出的QPS上限的请求就只能抛出异常从而导致购物车的查询失败。但从业务角度来说即便没有查询到最新的商品信息购物车也应该展示给用户用户体验更好。也就是给查询失败设置一个降级处理逻辑。
第二由于查询商品的延迟较高模拟的500ms从而导致查询购物车的响应时间也变的很长。这样不仅拖慢了购物车服务消耗了购物车服务的更多资源而且用户体验也很差。对于商品服务这种不太健康的接口我们应该直接停止调用直接走降级逻辑避免影响到当前服务。也就是将商品查询接口熔断。 1.5.1.编写降级逻辑 1.在hm-api模块中给ItemClient定义降级处理类实现FallbackFactory
package com.hmall.api.client.fallback;Slf4j
public class ItemClientFallback implements FallbackFactoryItemClient {Overridepublic ItemClient create(Throwable cause) {return new ItemClient() {Overridepublic ListItemDTO queryItemByIds(CollectionLong ids) {log.error(远程调用ItemClient#queryItemByIds方法出现异常参数{}, ids, cause);// 查询购物车允许失败查询失败返回空集合return CollUtils.emptyList();}Overridepublic void deductStock(ListOrderDetailDTO items) {// 库存扣减业务需要触发事务回滚查询失败抛出异常throw new BizIllegalException(cause);}};}
}
2.在hm-api模块中的com.hmall.api.config.DefaultFeignConfig类中将ItemClientFallback注册为一个Bean
Beanpublic ItemClientFallbackFactory itemClientFallbackFactory(){return new ItemClientFallbackFactory();}
3.在hm-api模块中的ItemClient接口中使用ItemClientFallbackFactory 1.5.2.服务熔断 在微服务架构中当查询商品的响应时间RT较高例如模拟的 500ms会导致依赖该接口的查询购物车服务的响应时间也显著增加。这不仅会拖慢购物车服务的性能消耗更多资源还会严重影响用户体验。 对于这种性能不佳的商品服务接口我们可以通过熔断机制来避免其对当前服务的影响。具体来说当商品服务接口的响应时间过长或异常比例过高时应立即停止对该接口的调用转而执行降级逻辑。这样可以防止故障扩散保护购物车服务的正常运行。一旦商品服务接口恢复正常再重新允许对该接口的调用。这种模式正是断路器的工作原理。 在 Sentinel 中断路器机制不仅能够统计接口的慢请求比例还能统计异常请求比例。当这些比例超过预设阈值时Sentinel 会自动熔断该接口拦截所有对该接口的访问请求并执行降级逻辑。一旦接口的健康状况恢复正常Sentinel 会自动恢复对该接口的调用。这种方式能够有效保护系统资源提升用户体验同时确保服务的高可用性。 断路器的工作状态切换有一个状态机来控制 状态机包括三个状态 closed关闭状态断路器放行所有请求并开始统计异常比例、慢请求比例。超过阈值则切换到open状态 open打开状态服务调用被熔断访问被熔断服务的请求会被拒绝快速失败直接走降级逻辑。Open状态持续一段时间后会进入half-open状态 half-open半开状态放行一次请求根据执行结果来判断接下来的操作。 请求成功则切换到closed状态 请求失败则切换到open状态 我们可以在控制台通过点击簇点后的熔断按钮来配置熔断策略 这种是按照慢调用比例来做熔断上述配置的含义是 RT超过200毫秒的请求调用就是慢调用 统计最近1000ms内的最少5次请求如果慢调用比例不低于0.5则触发熔断 熔断持续时长20s 2.分布式事务
首先我们看看项目中的下单业务整体流程 在微服务架构中订单、购物车和商品服务分别部署在不同的微服务中每个微服务都有自己的独立数据库。因此在下单流程中业务操作会跨越多个数据库涉及多个微服务的本地事务 订单服务负责处理下单事务。 购物车服务负责清理购物车事务。 库存服务负责扣减库存事务。
这些本地事务相互关联共同构成了一个全局事务。每个微服务的本地事务可以视为一个分支事务而多个分支事务的组合则构成了全局事务。为了确保业务的完整性和一致性我们必须保证整个全局事务要么全部成功要么全部失败。
虽然每个分支事务本身是传统的单体事务能够满足 ACID原子性、一致性、隔离性、持久性特性但全局事务跨越多个服务和数据库无法直接依赖单体事务的 ACID 特性来保证一致性。因此我们需要引入分布式事务解决方案来确保全局事务的一致性。
分布式事务解决方案通过协调各个分支事务的行为确保全局事务的原子性和一致性。常见的解决方案包括两阶段提交、补偿事务TCC、本地消息表、事件溯源等。这些方案各有优缺点需要根据具体的业务场景和技术栈进行选择。 2.1.认识Seata 2.2.部署TC服务
2.2.1.准备数据库表
1.导入数据库表
2.我们将整个seata文件夹拷贝到虚拟机的/root目录 2.2.2.Docker部署
1.将某容器加入指定网络
docker network connect [网络名] [容器名]
2.在虚拟机的/root目录执行下面的命令
docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP192.168.150.101 \
-v ./seata:/seata-server/resources \
--privilegedtrue \
--network hm-net \
-d \
seataio/seata-server:1.5.2 2.3.微服务集成Seata
参与分布式事务的每一个微服务都需要集成Seata我们以trade-service为例。
2.3.1.引入依赖
为了方便各个微服务集成seata我们需要把seata配置共享到nacos因此trade-service模块不仅仅要引入seata依赖还要引入nacos依赖:
!--统一配置管理--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId/dependency!--读取bootstrap文件--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bootstrap/artifactId/dependency!--seata--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactId/dependency 2.3.2.改造配置
1.nacos上添加一个共享的seata配置命名为shared-seata.yaml
seata:registry: # TC服务注册中心的配置微服务根据这些信息去注册中心获取tc服务地址type: nacos # 注册中心类型 nacosnacos:server-addr: 192.168.150.101:8848 # nacos地址namespace: # namespace默认为空group: DEFAULT_GROUP # 分组默认是DEFAULT_GROUPapplication: seata-server # seata服务名称username: nacospassword: nacostx-service-group: hmall # 事务组名称service:vgroup-mapping: # 事务组与tc集群的映射关系hmall: default
2.改造trade-service模块添加bootstrap.yaml
spring:application:name: trade-service # 服务名称profiles:active: devcloud:nacos:server-addr: 192.168.150.101 # nacos地址config:file-extension: yaml # 文件后缀名shared-configs: # 共享配置- dataId: shared-jdbc.yaml # 共享mybatis配置- dataId: shared-log.yaml # 共享日志配置- dataId: shared-swagger.yaml # 共享日志配置- dataId: shared-seata.yaml # 共享seata配置
3.改造application.yaml文件
server:port: 8085
feign:okhttp:enabled: true # 开启OKHttp连接池支持sentinel:enabled: true # 开启Feign对Sentinel的整合
hm:swagger:title: 交易服务接口文档package: com.hmall.trade.controllerdb:database: hm-trade 2.3.3.测试
将其上的Transactional注解改为Seata提供的GlobalTransactional 2.4.XA模式 Seata支持四种不同的分布式事务解决方案 XA TCC AT SAGA 这里我们以XA模式和AT模式来给大家讲解其实现原理。 XA 规范 是 X/Open 组织定义的分布式事务处理DTPDistributed Transaction Processing标准XA 规范 描述了全局的TM与局部的RM之间的接口几乎所有主流的数据库都对 XA 规范 提供了支持。 2.4.1.两阶段提交 2.4.2.优缺点
优点缺点事务的强一致性满足ACID原则因为一阶段需要锁定数据库资源等待二阶段结束才释放性能较差常用数据库都支持实现简单并且没有代码侵入依赖关系型数据库实现事务 2.4.3.实现步骤
1.指定要采用的分布式事务模式。我们可以在Nacos中的共享shared-seata.yaml配置文件中设置
seata:data-source-proxy-mode: XA
2.利用GlobalTransactional标记分布式事务的入口方法 2.5.AT模式
AT模式同样是分阶段提交的事务模型不过缺弥补了XA模型中资源锁定周期过长的缺陷。
2.5.1.Seata的AT模型
基本流程图 2.5.2.AT与XA的区别
区别点XA 模式AT 模式事务提交阶段一阶段不提交事务仅锁定资源等待二阶段决定是否提交。一阶段直接提交本地事务不锁定资源。回滚机制依赖数据库的 XA 机制在二阶段回滚时释放资源并撤销一阶段的操作。利用数据快照undo-log实现数据回滚不依赖数据库的 XA 机制。一致性强一致性事务要么全部提交要么全部回滚中间状态不允许存在。最终一致性通过补偿机制确保最终状态一致但中间可能存在短暂不一致。性能性能较低因为一阶段锁定资源可能导致资源争用和阻塞。性能较高因为一阶段直接提交减少了资源锁定时间。业务侵入性对业务代码侵入性较低主要依赖数据库的 XA 支持。对业务代码无侵入业务逻辑无需修改只需配置 Seata 即可。适用场景适用于对一致性要求极高的场景如金融核心系统。适用于大多数业务场景尤其是对性能要求较高且可以接受最终一致性的场景。资源锁定一阶段锁定资源可能导致资源长时间占用影响并发性能。不锁定资源减少资源争用提升并发性能。数据库支持需要数据库支持 XA 协议部分数据库可能不支持或支持效果不佳。不依赖数据库的 XA 协议适用于更多类型的数据库。复杂度实现复杂依赖数据库的 XA 机制配置和维护成本较高。实现相对简单通过 Seata 的中间件实现配置和维护成本较低。适用范围由于性能和资源锁定问题适用范围相对较窄。适用范围广适合大多数分布式事务场景尤其在微服务架构中表现良好。
总结 XA 模式强一致性依赖数据库 XA 机制一阶段锁定资源性能较低适用范围较窄但对一致性要求极高的场景非常适用。 AT 模式最终一致性利用数据快照实现回滚一阶段直接提交性能较高对业务无侵入适用范围广适合大多数分布式事务场景。
在实际应用中企业可以根据业务需求和对一致性的要求选择合适的事务模式。对于大多数业务场景AT 模式因其简单易用和高性能特点成为分布式事务的首选方案。 大功告成