微服务架构➖SpringCloud➖Sentinel

微服务架构➖SpringCloud➖Sentinel

关于作者

  • 作者介绍

🍓 博客主页:作者主页

🍓 简介:JAVA领域优质创作者🥇、一名在校大三学生🎓、在校期间参加各种省赛、国赛,斩获一系列荣誉 🏆、阿里云专家博主51CTO专家博主

🍓 关注我:关注我学习资料、文档下载统统都有,每日定时更新文章,励志做一名JAVA资深程序猿👨‍💻


Spring Cloud Alibaba Sentinel

服务雪崩效应以及服务容错

由于tomcat等服务器支持的最大线程数有限,如果一个服务出现了问题,调用这个服务的服务器就会出现线程阻塞的情况,此时如果有大量请求进入,就会导致服务瘫痪,这个服务器上的其他接口也不能调用,继而导致其他服务也会阻塞,瘫痪。 这种传播就是服务雪崩效应。我们无法完全杜绝雪崩源头的发生,只有做好足够的容错,保证在一个服务发生问题,不会影响到其它服务的正常运行。也就是"雪落而不雪崩"。 服务容错:常见的容错思路有隔离、超时、限流、熔断、降级这几种。 降级:类似于try/catch,在服务接口级别的try/catch 容错组件有:Hystrix,Resilience4J,Sentinel。

1.Sentinel初识

Sentinel (分布式系统的流量防卫兵)是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。

Sentinel具有以下特征:

  • 丰富的应用场景:Sentinel承接了阿里巴巴近10年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

  • 完备的实时监控:Sentinel提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒级数据,甚至500台以下规模的集群的汇总运行情况。

  • 广泛的开源生态:Sentinel提供开箱即用的与其它开源框架/库的整合模块,例如与Spring Cloud、Dubbo.gRPC的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。

  • 完善的SPI扩展点: Sentinel提供简单易用、完善的SPI扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

sentinel分为两个部分:

  • 核心库(Java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo / Spring Cloud等框架也有较好的支持。
  • 控制台(Dashboard)基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat 等应用容器。

2. Sentinel的使用

2.1 Sentinel的集成

  • 在pom.xml中加入下面依赖(给需要流量控制的微服务模块添加)
xml 复制代码
<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  • 下载控制台jar包,sentinel-dashboard-1.7.0.jar

  • 修改配置(每个集成了Sentinel的微服务模块都要加):

yaml 复制代码
spring:
  cloud:
    sentinel:
      transport:
        port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可
        dashboard: localhost:8080 # 指定控制台服务的地址
  • 运行命令启动jar包,sentinel-dashboard-1.7.0.jar
shell 复制代码
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar
  • 访问localhost:8080 进入控制台 ( 默认用户名密码是sentinel/sentinel ) 控制台界面如下图所示

注:需要微服务访问一次,才能刷新加载出微服务的资源信息。

2.2 Sentinel主要功能

流量控制:将请求排成队列形状处理。

熔断降级:当要调用的服务的响应时间变长或者异常比例升高的时候,减少该调用的并发线程数量,快速失败,以限制其对资源的占用。(hystrix利用线程池隔离的方式进行限制,线程池隔离:对每个服务调用接口划分一块线程池,调用某服务只能使用对应线程池里的线程,因此达到隔离效果不影响统一服务器上的其他接口)

系统负载保护:集群环境下,当cpu,内存快占满时,把请求发到其他机器上去。

2.3 Sentinel规则

2.3.1 流控规则

对某一资源设置访问频率限制

阈值类型 :频率指标有QPS(每秒请求次数),线程数(并发线程个数) 单机阈值:对上述频率定量规则

流控模式:直接:对资源的直接限制。 关联:当某一资源达到上述设定的限制时,另一资源会被限流。 链路:假设有一个服务A,会调用另一个资源B(可以是一个接口,也可以是一个方法,用@SentinelResource注解可以设置该资源的名字),当b满足上述访问频率时,会对a进行限流。

流控效果:快速失败:当一个资源被流控时,再次访问该资源时直接出异常界面。 Warm up:预热,逐渐放开频率限制,阈值逐渐增长。 排队等待:处理不过来的请求会放到队列中等待被处理。

2.3.2 降级规则

流控,降级,熔断的区别:流控超过频率就把请求完全屏蔽等频率降下来就继续提供服务,降级超过频率采用备用服务或者丢弃部分资源,等待一定时间以后继续提供服务。熔断直接停用服务,等一段时间后再去尝试是否可以调用服务。

降级策略:RT:一秒内的请求平均响应时间,时间窗口:等待的时间; 异常比例:一秒内的请求异常的数量/请求总数量;异常数:一分钟产生的异常个数

2.3.3 热点规则

热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。

带参数的流控规则

第1步: 编写代码

java 复制代码
@RequestMapping("/order/message3")
@SentinelResource("message3")
public String message3(String name, Integer age) {
    return "message3" + name + age;
}

第2步: 配置热点规则

第3步: 分别用两个参数访问,会发现只对第一个参数限流了

热点规则增强使用

参数例外项允许对一个参数的具体值进行流控,编辑刚才定义的规则,增加参数例外项

2.3.4 授权规则

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源 访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:

  • 若配置白名单,则只有请求来源位于白名单内时才可通过;
  • 若配置黑名单,则请求来源位于黑名单时不通过,其余的请求通过。

判断请求头/参数,确定是否为白名单/黑名单,下面是一个配置类,,请求发出的时候的该类就可以从url上获取request域的源标识。

java 复制代码
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {

    //定义区分来源: 本质作用是通过request域获取到来源标识
    //app  pc
    //然后 交给流控应用 位置进行匹配
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String serviceName = request.getParameter("serviceName");
        if (StringUtils.isEmpty(serviceName)){
            throw new RuntimeException("serviceName is not empty");
        }
        return serviceName;
    }
}

分别访问:

http://localhost:8091/order/message1?serviceName=service

http://localhost:8091/order/message1?serviceName=service-A

记一次错误

shell 复制代码
java.util.ServiceConfigurationError: com.alibaba.csp.sentinel.init.InitFunc: Provider com.itheima.config.FilePersistence not found

因为没有配置 FilePersistence 而导致的sentinel无法使用。

2.3.5 系统规则---服务器维度的流控

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 、CPU 使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过 系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般 是 CPU cores * 2.5。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。 CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护。
2.3.6 自定义异常返回

写个配置类,继承UrlBlockHandler,它会接受异常,然后运行blocked,可以在该函数里面写if,else语句判断异常类型,进行相对处理,实例代码:

java 复制代码
package com.itheima.config;

import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//自定义异常返回页面
@Component
public class ExceptionHandlerPage implements UrlBlockHandler {
    @Override
    public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
        response.setContentType("application/json;charset=utf-8");

        ResponseData responseData = null;
        //BlockException  异常接口,包含Sentinel的五个异常
        //  FlowException  限流异常
        //  DegradeException  降级异常
        //  ParamFlowException  参数限流异常
        //  AuthorityException  授权异常
        //  SystemBlockException  系统负载异常
        if (e instanceof FlowException) {
            responseData = new ResponseData(-1, "接口被限流了...");
        } else if (e instanceof DegradeException) {
            responseData = new ResponseData(-2, "接口被降级了...");
        }
        response.getWriter().write(JSON.toJSONString(responseData));
    }
}

@Data
@AllArgsConstructor//全参构造
@NoArgsConstructor
//无参构造
class ResponseData {
    private int code;
    private String message;
}
相关推荐
raoxiaoya2 小时前
同时安装多个版本的golang
开发语言·后端·golang
考虑考虑4 小时前
go使用gorilla/websocket实现websocket
后端·程序员·go
李少兄4 小时前
解决Spring Boot多模块自动配置失效问题
java·spring boot·后端
Piper蛋窝5 小时前
Go 1.19 相比 Go 1.18 有哪些值得注意的改动?
后端
码农BookSea5 小时前
不用Mockito写单元测试?你可能在浪费一半时间
后端·单元测试
他҈姓҈林҈5 小时前
Spring Boot 支持政策
spring boot
codingandsleeping6 小时前
Express入门
javascript·后端·node.js
ss2736 小时前
基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
spring boot·后端·高考
两点王爷6 小时前
springboot项目文件上传到服务器本机,返回访问地址
java·服务器·spring boot·文件上传
专注API从业者7 小时前
《Go 语言高并发爬虫开发:淘宝商品 API 实时采集与 ETL 数据处理管道》
开发语言·后端·爬虫·golang