微服务系列五:避免雪崩问题的限流、隔离、熔断措施

目录

实验环境说明

前言

一、一片小雪花引起的雪崩!

[1.1 雪崩问题(级联失败问题)示意图](#1.1 雪崩问题(级联失败问题)示意图)

[1.2 雪崩问题的产生原因与解决策略](#1.2 雪崩问题的产生原因与解决策略)

二、雪崩问题的具体解决策略

[2.1 请求限流](#2.1 请求限流)

[2.2 线程隔离](#2.2 线程隔离)

[2.3 服务熔断](#2.3 服务熔断)

[2.4 总结------具体解决策略](#2.4 总结——具体解决策略)

三、微服务保护工具:sentinel

[3.1 sentinel 介绍](#3.1 sentinel 介绍)

[3.2 sentinel安装](#3.2 sentinel安装)

[3.3 sentinel微服务整合](#3.3 sentinel微服务整合)

[3.4 簇点链路调整](#3.4 簇点链路调整)

四、基于sentinel实现请求限流

[4.1 配置请求限流说明](#4.1 配置请求限流说明)

[4.2 请求限流实践](#4.2 请求限流实践)

[4.2.1 配置请求限流规则](#4.2.1 配置请求限流规则)

[4.2.2 JMeter并发测试](#4.2.2 JMeter并发测试)

[4.2.3 sentinel流控展示](#4.2.3 sentinel流控展示)

五、基于sentinel实现线程隔离

[5.1 模拟无线程隔离配置阻塞请求压垮服务器实验](#5.1 模拟无线程隔离配置阻塞请求压垮服务器实验)

[5.1.1 配置慢请求业务](#5.1.1 配置慢请求业务)

[5.1.2 调整服务器资源量](#5.1.2 调整服务器资源量)

[5.1.3 正常请求现象展示](#5.1.3 正常请求现象展示)

[5.1.4 JMeter压力测试并查看接口响应情况](#5.1.4 JMeter压力测试并查看接口响应情况)

[5.2 配置线程隔离规则](#5.2 配置线程隔离规则)

[5.3 JMeter并发测试](#5.3 JMeter并发测试)

[5.4 sentinel流控效果显示](#5.4 sentinel流控效果显示)

六、fallback逻辑优化

[6.1 fallback实验说明](#6.1 fallback实验说明)

[6.2 调整簇点策略,注册OpenFeign簇点](#6.2 调整簇点策略,注册OpenFeign簇点)

[6.3 FallbackFactory配置Fallback](#6.3 FallbackFactory配置Fallback)

[6.3.1 编写ItemClientFallbackFactory类](#6.3.1 编写ItemClientFallbackFactory类)

[6.3.2 在Config中注册Bean对象](#6.3.2 在Config中注册Bean对象)

[6.3.3 在对应的Client上添加注解使用](#6.3.3 在对应的Client上添加注解使用)

[6.4 线程隔离 + Fallback实验测试](#6.4 线程隔离 + Fallback实验测试)

[6.4.1 给feign簇点添加线程隔离规则](#6.4.1 给feign簇点添加线程隔离规则)

[6.4.2 JMeter并发测试并查看响应结果](#6.4.2 JMeter并发测试并查看响应结果)

[6.4.3 sentinel流控效果展示](#6.4.3 sentinel流控效果展示)

七、基于sentinel实现服务熔断

[7.1 断路器介绍](#7.1 断路器介绍)

[7.2 配置服务熔断规则说明](#7.2 配置服务熔断规则说明)

[7.3 JMeter并发测试并进行前后对比](#7.3 JMeter并发测试并进行前后对比)

八、微服务保护方案相关知识追问巩固


实验环境说明

本文有部分地方需要实验进行。首先对于看过黑马微服务的同学应该会比较熟悉。如果没有你也可以参考我实验的环境搭个简单的测试环境,用于实验。实验的目的也是为了更好的理解业务、理解知识点。

本地环境部分:

|---------------|---------------|-----------|
| 服务名 | 端口号 | 备注 |
| nginx | 18080 / 18081 | 前端运行环境 |
| sentinel | 8090 | 服务保护监控 |
| hm-gateway | 8080 | 后端项目网关模块 |
| item-service | 8081 | 后端商品服务模块 |
| cart-service | 8082 | 后端购物车服务模块 |
| item-service2 | 8083 | 后端商品服务模块 |
| item-service3 | 8084 | 后端商品服务模块 |
| user-service | 8085 | 后端用户管理模块 |
| trade-service | 8086 | 后端交易服务模块 |
| pay-service | 8087 | 后端支付服务模块 |

远程服务器环境部分:

|-----------|-------------|-----------------|
| 服务名 | 端口号 | 备注 |
| nacos | 8848 | 注册中心及配置中心,非容器镜像 |
| nginx | 18080/18081 | 线上前端运行环境,容器镜像 |
| mysql | 3306 | 线上数据库,容器镜像 |
| docker-hm | 8080 | 线上后端运行环境,容器镜像 |

注意事项:

  • 远程环境中非容器镜像指nacos是后单独配置的容器,而mysql、nginx、docker-hm是使用compose统一部署的。
  • 在本节实验中,线上环境的nginx和docker-hm我们不会使用到,而是使用本地的nginx和后端项目
  • 请你确保在配置线上环境时,mysql必须先比nacos启动。如果nacos先启动将无法连接数据库。此时你需要停止nacos容器,先启动mysql。

前言

先前我们依次学习了远程调用、服务治理、请求路由、身份认证、配置管理的相关知识。本篇,我们将从雪崩问题出发,去探讨微服务的保护措施及实现方法。

一、一片小雪花引起的雪崩!

1.1 雪崩问题(级联失败问题)示意图

微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩。

1.2 雪崩问题的产生原因与解决策略

|-------------------------------------|---------------------------------------------|
| 产生原因 | 解决策略 |
| 服务相互调用,而服务提供者出现故障或阻塞 | 尽量避免服务提供者出现阻塞,限制请求数量【请求限流】 |
| 服务调用者被大量阻塞请求占满,导致服务器崩溃 | 尽量避免无节制的调用服务器资源请求异常服务,限制调用服务的线程数量【线程隔离】 |
| 调用链中连环失败,没有及时阻断,对于异常请求仍然不断去重试,浪费资源。 | 尽量避免对已经确认异常的服务继续发送请求,及时做到断止请求【服务熔断】 |

总结:确保服务提供者能处理它能力范围内的请求,同时服务调用者要设置好合适的线程数,以免请求占满服务器资源。最后,如果服务提供者出现大量异常后,也要及时断舍,不要再做无意义的请求去浪费资源。

二、雪崩问题的具体解决策略

2.1 请求限流

**请求限流:**限制访问微服务的请求的并发量,避免服务因流量激增出现故障。

2.2 线程隔离

**举例:**就像将船分为若干块,即使一块进水了,也不会导致整船的进水。减少对整体的影响。

线程隔离:相当于利用线程将服务器隔离成多块,即使部分异常也不会拖垮服务器,减少对服务器的影响。

**fallback优化:**有时候我们不希望抛出服务异常,这时我们可以让异常的服务调用变成自定义的fallback逻辑,这样一来可以快速失败,执行fallback中的业务逻辑,返回默认数据或友好提示。

2.3 服务熔断

**举例:**就像家庭电路中的空气开关。当电器出现漏电异常或者短路时,空气开关会自动切断电源,以免照常更多的电器损失。

**服务熔断:**由断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,则拦截该接口的请求。 熔断期间,所有请求快速失败,全都走fallback逻辑。

fallback逻辑:对于需要熔断的服务,没有必要再发送请求浪费,直接熔断并且走fallback,执行服务异常时的业务逻辑。

2.4 总结------具体解决策略

|----------|-----------------------------------------|
| 请求限流 | 限制流量在服务可以处理的范围,避免因突发流量而故障 |
| 线程隔离 | 控制业务可用的线程数量,将故障隔离在一定范围 |
| 服务熔断 | 将异常比例过高的接口断开,拒绝所有请求,直接走fallback |
| 失败处理 | 定义fallback逻辑,让业务失败时不再抛出异常,而是返回默认数据或友好提示 |

三、微服务保护工具:sentinel

3.1 sentinel 介绍

Sentinel是阿里巴巴开源的一款微服务流量控制组件。Sentinel定位是分布式系统的流量防卫兵。目前互联网应用基本上都使用微服务,微服务的稳定性是一个很重要的问题,而限流、熔断降级 是微服务保持稳定的一个重要的手段。
home | Sentinelhomehttps://sentinelguard.io/zh-cn/index.html
Sentinel主要的功能示意图

3.2 sentinel安装

下载

sentinel的下载地址 Releases · alibaba/Sentinelhttps://github.com/alibaba/Sentinel/releases 下载后放到非中文目录下,将版本后缀删除:

运行

打开cmd命令窗口,运行启动脚本

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

访问

本地访问 localhost:8090端口,即可进入控制台。(登录账号密码默认都是sentinel)

3.3 sentinel微服务整合

基本步骤

  • 引入sentinel依赖
  • 配置控制台发现
  • 访问微服务,测试sentinel监控

以下实验以cart-service模块为例:

引入依赖

XML 复制代码
<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

增加配置文件

bash 复制代码
spring:
  cloud: 
    sentinel:
      transport:
        dashboard: localhost:8090

重启测试服务

对购物车的相关服务进行访问,查看sentinel的监控效果

3.4 簇点链路调整

**簇点链路:**就是单机调用链路。是一次请求进入服务后经过的每一个被Sentinel监控的资源链。默认Sentinel会监控SpringMVC的每一个Endpoint(http接口)。限流、熔断等都是针对簇点链路中的资源设置的。而资源名默认就是接口的请求路径:

当前项目基于restful风格,还存在一些不合适的问题:

如何让每个接口都能显示出来呢?我们需要对簇点链路配置进行一些调整:

修改配置文件,添加一行配置:

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

重新上线测试:

四、基于sentinel实现请求限流

4.1 配置请求限流说明

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

4.2 请求限流实践

以下实验以获取购物车列表接口为例:

4.2.1 配置请求限流规则

4.2.2 JMeter并发测试

4.2.3 sentinel流控展示

五、基于sentinel实现线程隔离

5.1 模拟无线程隔离配置阻塞请求压垮服务器实验

本实验以购物车列表查询接口为例:由于购物车列表需要依赖商品查询的数据,因此可以进行本次实验。(完成本次实验前,请将请求限流规则删除)

5.1.1 配置慢请求业务

将根据ID批量查询商品接口改为慢查询

5.1.2 调整服务器资源量

为了能更快展现压垮服务器的情况,我们需要把tomcat服务器默认的资源量**(默认8192)**改小一点。

5.1.3 正常请求现象展示

购物车列表查询速度500多毫秒,且目前正常查询到商品数据

其他购物车接口查询速度正常,10多毫秒

5.1.4 JMeter压力测试并查看接口响应情况

这一步需要在JMeter高并发请求的过程中进行。

利用JMeter不断发送购物车列表请求,压力服务器

查看购物车接口的响应结果

更加暴力的测试提高到每秒400并发

(哥们别测太高,电脑死机就完蛋了)

5.2 配置线程隔离规则

5.3 JMeter并发测试

5.4 sentinel流控效果显示

六、fallback逻辑优化

6.1 fallback实验说明

第五节线程隔离中存在一个问题:发现没有,控制台基本上全是报错的,但是有时后我们不希望服务抛出异常,而是在服务异常后走我们自定义的业务逻辑。这个时候就需要fallback登场了。

以查询购物车列表为例,在商品查询业务慢导致线程占满,返回请求429的情况下。我们希望还能正常显示购物车列表信息。对此,我们可以给查询逻辑添加fallback,在资源耗尽被拒绝的时候,我们直接走fallback,将单单购物车的数据展示到前端就行了(不管商品信息)

也就是说,我们不需要隔离购物车业务,而是直接隔离异常的商品查询接口!

但是,调用商品查询接口是OpenFeign调用,如何给这条链路添加上线程隔离规则呢?

我们必须先将这条链路注册成一个簇点。接下来就跟着我一起实验吧!

6.2 调整簇点策略,注册OpenFeign簇点

在cart-service模块中,开启feign对sentinel的支持

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

重启查看sentinel

接下来我们就可以对这个接口进行流控啦!不过在此之前我们先配置一下fallback逻辑,

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

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

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

6.3 FallbackFactory配置Fallback

6.3.1 编写ItemClientFallbackFactory类

在hm-api模块下新建client.fallback.itemClientFallbackFactory.java,并实现FallbackFactory接口

java 复制代码
package com.hmall.api.client.fallback;

import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.utils.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;

import java.util.Collection;
import java.util.List;


@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("查询商品信息失败: ", cause);
                // 返回空集合
                return CollUtils.emptyList();
            }

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

6.3.2 在Config中注册Bean对象

java 复制代码
    @Bean
    public ItemClientFallbackFactory itemClientFallbackFactory() {
        return new ItemClientFallbackFactory();
    }

6.3.3 在对应的Client上添加注解使用

到此为止,Fallback已经编写完成了,接下来再次进行线程隔离实验测试

6.4 线程隔离 + Fallback实验测试

6.4.1 给feign簇点添加线程隔离规则

6.4.2 JMeter并发测试并查看响应结果

查询购物车列表不报错了,而且查询从500多毫秒变成了几十毫秒

6.4.3 sentinel流控效果展示

七、基于sentinel实现服务熔断

7.1 断路器介绍

熔断是解决雪崩问题的重要手段。思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

知道服务已经挂了,就不需要再给他发请求了,直接拒绝发起请求,直接走fallback逻辑。进而节约更多的资源。与此同时,服务熔断需要有一个恢复时长,在恢复时再次请求查看是否成功。成功就结束熔断,否则继续进入熔断状态!

7.2 配置服务熔断规则说明

7.3 JMeter并发测试并进行前后对比

不加服务熔断前的状态:

加了服务熔断后的状态

超过熔断时间20s后,请求恢复正常

八、微服务保护方案相关知识追问巩固

  1. 请你谈谈微服务雪崩问题是如何产生的?产生的后果是什么?

  2. 对于雪崩问题,你有哪些好的解决方案呢?

  3. 你知道什么是流量控制组件么?你有用过哪些微服务流量控制组件?

  4. 请你谈谈sentinel如何整合到我们的微服务项目中?说出具体的步骤?

  5. 关于sentinel簇点的概念?什么是簇点链路

  6. restful风格的微服务项目使用sentinel簇点需要注意什么问题?如何配置?

  7. openfeign调用如何注册到sentinel的簇点链路中?

  8. openfeign调用的请求如何单独给它加上流量控制规则?具体的步骤是什么?

  9. 请你谈谈使用sentinel如何实现请求限流、线程隔离?

  10. 请你谈谈如何编写fallback逻辑,具体的步骤是什么?

  11. 请你谈谈使用sentinel如何实现服务熔断,熔断有哪些常见的策略?

  12. 请你谈谈服务熔断中熔断器的工作流程,什么是熔断时长?

相关推荐
aloha_7899 分钟前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java39 分钟前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~43 分钟前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
程序媛小果1 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
小屁孩大帅-杨一凡2 小时前
java后端请求想接收多个对象入参的数据
java·开发语言
java1234_小锋2 小时前
使用 RabbitMQ 有什么好处?
java·开发语言
Dann Hiroaki2 小时前
GPU架构概述
架构
TangKenny2 小时前
计算网络信号
java·算法·华为
肘击鸣的百k路2 小时前
Java 代理模式详解
java·开发语言·代理模式
城南vision2 小时前
Docker学习—Docker核心概念总结
java·学习·docker