微服务:微服务保护

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

目录

一、引言

1. 什么是雪崩问题

2. 雪崩问题产生的原因

3. 解决思路

二、微服务保护

1. 服务保护方案

(1)请求限流

(2)线程隔离

(3)服务熔断

2. Sentinel

(1)介绍和安装

(2)微服务整合

引入sentinel依赖

配置控制台

访问cart-service的任意端点

3. 请求限流

4. 线程隔离

5. Fallback

(1)配置文件

(2)配置FeignClient的Fallback

6. 服务熔断


一、引言

1. 什么是雪崩问题

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

 

2. 雪崩问题产生的原因

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

3. 解决思路

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

二、微服务保护

1. 服务保护方案

(1)请求限流

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

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

(2)线程隔离

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

(3)服务熔断

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

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

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

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

2. Sentinel

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

(1)介绍和安装

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

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

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

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依赖
<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

配置控制台

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

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)也失灵,这是因为微服务的资源耗尽了,因此必须对各个业务的最大使用线程做一个限制。

模拟商品服务查询很慢:

    @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功能:

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

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

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的簇点资源:

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

(2)配置FeignClient的Fallback

代码:

@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

 

 

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值