微服务:微服务保护

💥 该系列属于【SpringBoot基础】专栏,如您需查看其他SpringBoot相关文章,请您点击左边的连接

目录

一、引言

[1. 什么是雪崩问题](#1. 什么是雪崩问题)

[2. 雪崩问题产生的原因](#2. 雪崩问题产生的原因)

[3. 解决思路](#3. 解决思路)

二、微服务保护

[1. 服务保护方案](#1. 服务保护方案)

(1)请求限流

(2)线程隔离

(3)服务熔断

[2. Sentinel](#2. Sentinel)

(1)介绍和安装

(2)微服务整合

引入sentinel依赖

配置控制台

访问cart-service的任意端点

[3. 请求限流](#3. 请求限流)

[4. 线程隔离](#4. 线程隔离)

[5. Fallback](#5. Fallback)

(1)配置文件

(2)配置FeignClient的Fallback

[6. 服务熔断](#6. 服务熔断)


一、引言

1. 什么是雪崩问题

微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是级联 失败 问题,或者叫雪崩问题。

2. 雪崩问题产生的原因

  • 微服务相互调用,服务提供者出现故障或阻塞。
  • 服务调用者没有做好异常处理,导致自身故障。
  • 调用链中的所有服务级联失败,导致整个集群故障。

3. 解决思路

  • 尽量避免服务出现故障或阻塞,保证代码的健壮性,保证网络畅通,能应对较高的并发请求;

二、微服务保护

1. 服务保护方案

(1)请求限流

服务故障最重要原因,就是并发太高!解决了这个问题,就能避免大部分故障。当然,接口的并发不是一直很高,而是突发的。因此请求限流,就是限制或控制接口访问的并发流量,避免服务因流量激增而出现故障。

请求限流往往会有一个限流器,数量高低起伏的并发请求曲线,经过限流器就变的非常平稳。这就像是水电站的大坝,起到蓄水的作用。

(2)线程隔离

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

(3)服务熔断

线程隔离虽然避免了雪崩问题,但故障服务(商品服务)依然会拖慢购物车服务(服务调用方)的接口响应速度。

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

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

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

2. Sentinel

Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中。

(1)介绍和安装

下载地址:Releases · alibaba/Sentinel (github.com)

将jar包放在任意非中文、不包含特殊字符的目录下,重命名为sentinel-dashboard.jar

例如放在桌面Desktop下,然后运行如下命令启动控制台:

bash 复制代码
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

通过http://localhost:8090访问:

需要输入账号和密码,默认都是:sentinel

登录后,即可看到控制台,默认会监控sentinel-dashboard服务本身:

(2)微服务整合

cart-service模块中整合sentinel,连接sentinel-dashboard控制台,步骤如下:

引入sentinel依赖
XML 复制代码
<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置控制台

修改application.yaml文件,添加下面内容:

bash 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8090
      http-method-specify: true #开启请求方式前缀

我们的SpringMVC接口是按照Restful风格设计,因此购物车的查询、删除、修改等接口全部都是/carts路径,所以我们可以选择打开Sentinel的请求方式前缀,把请求方式 + 请求路径作为簇点资源名。把spring.cloud.sentinel.http-method-specify设置为true

重启,刷新前端购物车页面

访问cart-service的任意端点

访问查询购物车接口,sentinel的客户端就会将服务访问的信息提交到sentinel-dashboard控制台。并展示出统计信息:

3. 请求限流

对某个接口的请求数进行限制

在簇点链路后面点击流控按钮,即可对其做限流配置:

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

利用Jemeter做限流测试,我们每秒发出10个请求:

最终监控结果如下:

可以看出GET:/carts这个接口的通过QPS稳定在6附近,而拒绝的QPS在4附近,符合我们的预期。

4. 线程隔离

每个微服务如果给某个业务(例如查询购物车)过多的线程,那么会导致其他业务(例如业务1)也失灵,这是因为微服务的资源耗尽 了,因此必须对各个业务的最大使用线程做一个限制。

模拟商品服务查询很慢:

java 复制代码
    @ApiOperation("根据id查询商品")
    @GetMapping("{id}")
    public ItemDTO queryItemById(@PathVariable("id") Long id) throws InterruptedException {
        Thread.sleep(500); //耗时500ms
        return BeanUtils.copyBean(itemService.getById(id), ItemDTO.class);
    }

修改cart-service模块的application.yml文件,开启Feign的sentinel功能:

bash 复制代码
feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

默认情况下SpringBoot项目的tomcat最大线程数是200,允许的最大连接是8492,单机测试很难打满。所以我们需要配置一下cart-service模块的application.yml文件,修改tomcat连接:

bash 复制代码
server:
  port: 8082
  tomcat:
    threads:
      max: 50 # 允许的最大线程数
    accept-count: 50 # 最大排队等待数量
    max-connections: 100 # 允许的最大连接

接下来,点击查询商品的FeignClient对应的簇点资源后面的流控按钮:

在弹出的表单中填写下面内容:

这里勾选的是并发线程数限制,也就是说这个查询功能最多使用5个线程,而不是5QPS。如果查询商品的接口每秒处理2个请求,则5个线程的实际QPS在10左右。

我们利用Jemeter测试,每秒发送100个请求:

开启并发查询购物车信息的同时,手动增加和删除购物车商品仍然非常快,因此线程隔离使得不会影响到其它接口。

5. Fallback

fallback可以作为一种后备处理方案,当并发量过大导致请求失败时,可采取fallback的方法

(1)配置文件

在cart-service中添加,将FeignClient作为Sentinel的簇点资源:

bash 复制代码
feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

(2)配置FeignClient的Fallback

代码:

java 复制代码
@Slf4j
public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {
    @Override
    public ItemClient create(Throwable cause) {
        return new ItemClient() {
            @Override
            public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
                log.error("查询商品失败");
                return CollUtils.emptyList();
            }

            @Override
            public void deductStock(List<OrderDetailDTO> items) {
                log.error("扣减商品库存失败");
                throw new RuntimeException(cause);
            }
        };
    }
}

ItemClientFallback注册为一个Bean

hm-api模块中的ItemClient接口中使用ItemClientFallbackFactory

测试:

当queryItemByIds和deductStock因为并发量过大调用接口失败时,返回一个备选方案,前端收到的均为200状态码,不过查询商品返回的可能是空集合。

6. 服务熔断

查询商品响应时间过高,从而导致查询购物车的响应时间也变的很长。对于商品服务这种不太健康的接口,我们应该停止调用,避免影响到当前服务。也就是将商品查询接口熔断 。当商品服务接口恢复正常后,再允许调用。这其实就是断路器的工作模式了。

断路器的工作状态切换有一个状态机来控制:

状态机包括三个状态:

  • closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态

  • open :打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态持续一段时间后会进入half-open状态

  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。

    • 请求成功:则切换到closed状态

    • 请求失败:则切换到open状态

可以在控制台通过点击簇点后的**熔断**按钮来配置熔断策略:

在弹出的表格中这样填写:

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

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

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

  • 熔断持续时长20s

相关推荐
掘金-我是哪吒2 小时前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
茶馆大橘3 小时前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
58沈剑3 小时前
80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...
架构
想进大厂的小王6 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
九卷技术录6 小时前
(微服务)服务治理:几种开源限流算法库/应用软件介绍和使用
微服务·服务治理·限流算法
阿伟*rui7 小时前
认识微服务,微服务的拆分,服务治理(nacos注册中心,远程调用)
微服务·架构·firefox
ZHOU西口7 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
deephub10 小时前
Tokenformer:基于参数标记化的高效可扩展Transformer架构
人工智能·python·深度学习·架构·transformer
想进大厂的小王10 小时前
Spring-cloud 微服务 服务注册_服务发现-Eureka
微服务·eureka·服务发现
架构师那点事儿11 小时前
golang 用unsafe 无所畏惧,但使用不得到会panic
架构·go·掘金技术征文