场景

SpringCloudAlibaba中使用Nacos实现服务注册与发现(从实例入手):

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/125177618

SpringCloudAlibaba中使用Nacos实现配置中心和配置动态刷新:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/125181154

在上面实现的Nacos作为服务注册中心与配置中心之后,学习Sentinel作为流量控制的使用。

Sentinel

是什么

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

特性

丰富的应用场景:

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

完备的实时监控:

Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

广泛的开源生态:

Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。

完善的 SPI 扩展机制:

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

 

 

Sentinel分为两个部分

核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

官网

https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

教程

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

下载

https://github.com/alibaba/Sentinel/releases

直接点击jar包进行下载

 

 

下载之后直接运行jar包

java -jar sentinel-dashboard-1.8.4.jar

 

 

启动成功之后访问8080端口

http://localhost:8080/

 

 

默认用户名密码都是sentinel,登录成功之后

 

 

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

1、搭建演示工程,参考上面新建模块的流程,新建模块cloudalibaba-sentinel-service8401

修改pom文件,添加sentinel依赖

        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

除此之外,还需要添加nacos以及其它依赖,完整pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringCloudDemo</artifactId>
        <groupId>com.badao</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service8401</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

新建并修改application.yml配置文件,配置nacos地址和sentinel的地址等

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard地址
        #默认8719端口,如果被占用则自动从8719开始依次+1扫描,直至找到被占用的端口
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

新建主启动类并添加注解@EnableDiscoveryClient

package com.badao.springcloudalibabademo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}

新建Controller,并新增两个简单的接口

package com.badao.springcloudalibabademo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@Slf4j
public class FlowLimitController
{
    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        log.info(Thread.currentThread().getName()+"\t"+"...testB");
        return "------testB";
    }

}

2、启动Nacos,启动上面的sentinel,再启动8401服务

Sentinel采用的是懒加载的方式,所以需要调用一次接口才会在Sentinel中有数据。

所以在浏览器中多次调用接口

http://localhost:8401/testA

然后访问sentinel的dashboard

 

 

就可以实时监控刚才调用的服务了。

3、点击流控规则,再点击新增流控规则,可以看到如下界面

 

 

说明:

资源名:唯一名称,默认请求路径。

针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认defaule(不区分来源)

阈值类型/单机阈值:

QPS:每秒终的请求数量,当调用该api的QPS达到阈值的时候,进行限流。

线程数:当调用该api的线程数达到阈值的时候,进行限流。

流控模式:

直接:api达到限流条件时,直接限流。

关联:当关联的资源达到阈值时,就限流自己。

链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】

流控效果:

快速失败:直接失败,抛异常。

Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。

排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。

这块说明可以具体参考官方说明文档:

https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

4、阈值类型为QPS演示

在上面的新建流控规则,选择QPS,高级选项中保持默认,设置单机阈值为1,

单机阈值为1即代表一秒以内如果请求次数大于1次则进行限流。

访问testA接口,先慢频率访问,后快速访问

 

 

 

5、并发线程数阈值类型演示

继续上面的将阈值类型修改为并发线程数,并设置单机阈值为1。

 

 

此时为了演示出效果,需要修改接口有个延迟返回效果,避免返回过快

    @GetMapping("/testA")
    public String testA()
    {
        //暂停毫秒
        try{
            TimeUnit.MILLISECONDS.sleep(800);
        }catch (InterruptedException e){e.printStackTrace();}
        return "------testA";
    }

让testA接口延迟0.8秒返回。

此时当并发量过大时就会触发限流

 

 

6、流控模式为关联效果

要实现当关联资源/testB的qps阈值超过1时,就限流/testA

修改流控规则如下

 

 

为了模拟/testB多次请求,可以借助于Jmeter或者Postman用来做定时模拟请求

这里用postman-新建Collections-新建请求request为testB-配置请求20次,每隔300毫秒请求一次。

 

 

在模拟请求testB的过程中,此时再请求testA就会触发限流。

 

 

7、流控效果Warm Up效果演示

 

 

Warm Up

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。

当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。

通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

概述

当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,

我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。

这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。

它的实现是在 Guava 的算法的基础上实现的。然而,和 Guava 的场景不同,Guava 的场景主要用于调节请求的间隔,

即 Leaky Bucket,而 Sentinel 则主要用于控制每秒的 QPS,即我们满足每秒通过的 QPS 即可,我们不需要关注每个请求的间隔,

换言之,我们更像一个 Token Bucket。

我们用桶里剩余的令牌来量化系统的使用率。假设系统每秒的处理能力为 b,系统每处理一个请求,就从桶中取走一个令牌;

每秒这个令牌桶会自动掉落b个令牌。令牌桶越满,则说明系统的利用率越低;当令牌桶里的令牌高于某个阈值之后,我们称之为令牌桶"饱和"。

当令牌桶饱和的时候,基于 Guava 的计算上,我们可以推出下面两个公式:

rate(c)=m*c+ coldrate

其中,rate 为当前请求和上一个请求的间隔时间,而 rate 是和令牌桶中的高于阈值的令牌数量成线形关系的。

cold rate 则为当桶满的时候,请求和请求的最大间隔。通常是 coldFactor * rate(stable)。

官网详细文档

https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8

公式讲解

阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值。

默认coldFactor为3,即请求QPS从threshols/3开始,经预热时长逐渐升至设定的QPS阈值。

举例

系统初始化的阈值为6/3=2,即阈值刚开始为2;然后过了4秒之后阈值才慢慢升高恢复至6

 

 

此时再高频访问testA,一开始阈值是2,所以会被限流,在4秒之后,阈值变为6,则可以正常访问

 

 

应用场景:

秒杀系统在开启的瞬间,会有很多流量上来,就有可能会把系统打死,预热方式就是慢慢的把阈值增长到设置的阈值。

8、排队等待演示效果

匀速排队:让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效。

这种方式主要用于处理间隔性突发的流量,例如消息队列。例如在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,

我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

编辑上面的流控规则为排队等待

 

 

修改testA的接口使其输出一些信息

    @GetMapping("/testA")
    public String testA()
    {
        log.info(Thread.currentThread().getName()+"\t"+"...testA");
        return "------testA";
    }

然后再用postman发起20次请求,每次请求间隔200毫秒,可以看到testA接口仍然是1秒响应一次

 

 

posted on 2022-06-09 20:26  霸道流氓  阅读(315)  评论(0编辑  收藏  举报