Sentinel

1.基本概述

Sentinel是一款开源的流量控制组件,由阿里巴巴提供支持,旨在保护微服务架构中的应用程序免受不良请求的影响。

Spring Cloud Sentinel主要提供以下功能:

  1. 流量控制:可以通过配置规则来限制对服务的访问量,包括流量整形、流量降级、熔断降级等功能。
  2. 实时监控:提供实时的监控面板,展示各个服务的运行状态、流量情况以及异常信息,帮助开发人员及时发现问题并进行处理。
  3. 系统保护:可以对系统中不稳定的资源进行熔断,避免故障在整个系统中蔓延,保证系统的稳定性。

对于在微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。

解决方法如下:

  • 超时处理: 设置适当的超时时间可以避免请求无限等待,当请求在规定的时间内未得到响应时,可以及时返回错误信息或进行相应处理,防止资源被长时间占用。
  • 舱壁模式(Bulkhead Pattern): 舱壁模式通过将系统的不同功能隔离在不同的线程池或资源池中,避免某一功能的故障影响整个系统。这样即使某一功能出现问题导致资源耗尽,其他功能仍能正常运行。
  • 熔断降级(Circuit Breaker & Fallback): 熔断机制可以监控服务的状态,当服务异常达到一定阈值时自动触发熔断,暂时中断对该服务的请求,避免继续请求可能导致雪崩效应的不可用服务。降级则是在服务不可用时提供一些默认值或缓存数据,保证系统的基本功能继续可用。
  • 流量控制: 通过限制并发请求的数量或速率,可以有效控制系统的流量,防止系统过载。流量控制可以结合限流、排队等策略来平滑处理突发流量,保证系统稳定运行。

参考官方文档的基本原理:https://sentinelguard.io/zh-cn/docs/basic-implementation.html

总体架构设计如下:

在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:

  • NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
  • ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
  • StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
  • FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
  • AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
  • DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
  • SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;

Sentinel将ProcessorSlot作为SPI接口进行扩展,使得Slot Chain具备了扩展的能力。您可以自行加入自定义的slot并 编排 slot 间的顺序,从而可以给 Sentinel添加自定义的功能。

 

官网:home | Sentinel (sentinelguard.io)

安装Sentinel控制台:

Tags · alibaba/Sentinel · GitHub

Release v1.8.1 · alibaba/Sentinel · GitHub

下载jar包运行即可默认端口为8080,账号密码都为sentinel

运行:

java -jar .\sentinel-dashboard-1.8.1.jar

访问

http://localhost:8080

账号密码都为sentinel

首页如下

 

2.简单使用

新建微服务HelloWorld项目

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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dreams.hello</groupId>
    <artifactId>HelloWorld</artifactId>
    <version>1.0</version>
    <modules>
        <module>user-service</module>
        <module>hello-service</module>
        <module>gateway</module>
    </modules>

    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>
</project>

新建个模块hello-server作为一个微服务项目

在hello-server下创建com.dreams.hello.controller包

创建HelloController文件,定义接口

package com.dreams.hello.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping()
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello World!";
    }
}
启动类
package com.dreams.hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication

public class HelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }
}

application.yml配置如下:

server:
  port: 8081
spring:
  application:
    name: hello-service

依赖如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

使用sentinel

在hello-server引入依赖

<!--引入sentinel依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

在配置文件加入配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 # sentinel控制台地址

启动hello-server

此时控制台什么都没有

 

访问多次接口后

http://localhost:8081/hello

接口正常

而控制台出现

可以对其监控

多访问,可以看到是实时监控

 

3.限流规则

1.流控模式

添加限流规则时,点击高级选项可以选择三种流控模式:

  1. 直接模式:统计当前资源的请求,当触发阈值时直接对当前资源进行限流。这也是默认的模式。
  2. 关联模式:统计与当前资源相关的另一个资源的请求,当触发阈值时,对当前资源进行限流。
  3. 链路模式:统计从指定链路访问到本资源的请求,当触发阈值时,对指定链路进行限流。

一、直接模式

统计当前资源的请求,当触发阈值时直接对当前资源进行限流。这也是默认的模式。

打开簇点链路

可以对其接口进行流控,点击流控

这里设置流控规则QPS为2,即每秒允许2个请求

点击高级选项,可以看到默认是直接模式

默认即可

流控规则界面

快些多次请求

就会出现

可以看到qps不会超过2

 

二、关联模式

统计与当前资源相关的另一个资源的请求,当触发阈值时,对当前资源进行限流。

比如在系统资源紧张时,可以通过调整相对非重要的接口来节省资源

添加两个接口,模拟在订单添加和订单搜索情况

package com.dreams.hello.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping()
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello World!";
    }


    @GetMapping("/order/list")
    public String listOrder() {
        return "订单搜索!";
    }

    @GetMapping("/order/add")
    public String updateOrder() {
        return "添加订单!";
    }
}
访问3个接口后

 

 

就可以在簇点链路看到

对搜索订单添加流控规则

在系统资源紧张时,可以通过调整相对非重要的接口来节省资源。很明显添加订单更重要。

因此当添加订单业务(填在关联资源处)触发阈值时,就对查询订单(填在资源名处)业务限流。

 

三、链路模式

链路模式:统计从指定链路访问到本资源的请求,当触发阈值时,对指定链路进行限流。

举例:

新建service包,包下创建OrderService文件,模拟业务

package com.dreams.hello.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
@Service
public class OrderService {
    @SentinelResource("goods")
    public String list(){
        return "商品信息";
    }
}

Sentinel默认只标记Controller中的方法为资源,所以使用注解@SentinelResource(“goods”)就是将该方法定义为一个资源,命名为goods

在controller调用

package com.dreams.hello.controller;

import com.dreams.hello.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping()
public class HelloController {
    @Autowired
    OrderService orderService;

    @GetMapping("/hello")
    public String hello() {
        return "Hello World!";
    }


    @GetMapping("/order/list")
    public String listOrder() {
        String list = orderService.list();
        return "订单搜索" + list;
    }

    @GetMapping("/order/add")
    public String updateOrder() {
    String list = orderService.list();
        return "添加订单" + list;
    }
}

不过Sentinel默认会将Controller方法做context整合,导致链路模式的流控失效,需要修改application.yml,添加配置:

在配置文件加入配置web-context-unify

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 # sentinel控制台地址
      web-context-unify: false # 关闭context整合

 

运行再次请求3个接口,可以看到,出现了goods资源

对goods限流,点击流控

 

触发设定的阈值时对该链路进行限流,入口资源填写的就是要限制的链路,限制该路径对该资源的请求,但是另一个请求order/add不受影响

 

 

2.流控效果

流控效果是指请求达到流控阈值时应该采取的措施:

  • 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。
  • warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
  • 排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

快速失败

同上,默认的效果,已经演示过了

warm up

warm up也叫预热模式,是应对服务冷启动的一种方案。

请求阈值初始值是threshold /coldFactor,持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3

例如,设置QPS的threshold为10,预热时间为5秒,那么初始阈值就是10/3,也就是3,然后在5秒后逐渐增长到10。

 

排队等待

当请求超过QPS阈值时,快速失败和warm up会拒绝新的请求并抛出异常。而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

例如: QPS=5,意味着每200ms处理一个队列中的请求; timeout=2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常

 

4.隔离和降级

线程隔离和熔断是在分布式系统中常见的应对策略,用于保护系统免受异常情况的影响。

线程隔离(Thread Isolation):线程隔离是一种将不同的任务或请求在独立的线程中执行的策略。在多线程环境下,如果一个线程发生了异常或故障,通过线程隔离可以避免异常的扩散影响其他线程,保证系统的稳定性。线程隔离可以通过使用线程池或线程分组的方式实现,确保每个任务或请求都在独立的线程中执行。

熔断(Circuit Breaker):熔断是一种在出现故障或异常情况时主动断开服务调用的策略。熔断器会监控系统或服务的状态,当发现系统或服务出现异常或超过预设的阈值时,会断开对该系统或服务的调用,并且在一定时间内阻止对其的继续请求。熔断能够减少对故障系统的压力,同时也可以快速失败,避免长时间的等待导致更多的资源浪费。

Feign整合

实现一般通过Feign整合。

新建个模块user-service

使用nacos完成服务注册,feign实现远程调用

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>HelloWorld</artifactId>
        <groupId>com.dreams.hello</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>user-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- nacos客户端依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.7.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

controller层

package com.dreams.user.controller;

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

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/list")
    public String list(){
        return "User server Hello !";
    }

    @GetMapping("/{id}")
    String findById(@PathVariable("id") Long id){
        return "user";
    }

}

application.yml配置文件

server:
  port: 8082
spring:
  application:
    name: user-service
  profiles:
    active: dev # 环境
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
      config:
        file-extension: yaml # 文件后缀名

 

下面更改hello-server模块

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos客户端依赖包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
<!--feign客户端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
<!--引入HttpClient依赖-->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>10.10.1</version>
    </dependency>
<!--引入sentinel依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2021.0.5.0</version>
</dependency>

application.yml文件加入,不过因为我们没有使用HttpClient,所以不加也无所谓。

feign:
  httpclient:
    enabled: true # 支持HttpClient的开关
    max-connections: 200 # 最大连接数
    max-connections-per-route: 50 # 单个路径的最大连接数

 

新建包api下新建文件UserClient

@FeignClient(value = “user-service”)就是在nacos中调用服务user-server

package com.dreams.hello.api;

import com.dreams.hello.api.fallback.UserClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "user-service")
public interface UserClient {
    @GetMapping("/user/{id}")
    String findById(@PathVariable("id") Long id);
}
方法就是需要远程调用user-server的接口

在controller层添加一个接口

注入

@Autowired
private UserClient userClient;

调用

@GetMapping("/order/user")
public String usrOrder() {
    String user = userClient.findById(1L);
    String list = orderService.list();
    return user + "添加订单" + list;
}

运行正常

下面Feign整合Sentinel

要开启只要在application.yml文件加入如下配置,这里是hello-server远程调用user-server,所以在hello-server的application.yml文件加入即可

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

 

在hello-server下的com.dreams.hello.api包新建fallback包存放

UserClientFallbackFactory文件,只要在该方法下实现要返回的数据即可。当 FeignClient 调用发生异常时,会自动触发降级逻辑,并返回预先定义的降级结果。这样可以保证系统在异常情况下依然能够正常运行,并提供一定程度的容错能力。

代码如下:

package com.dreams.hello.api.fallback;

import com.dreams.hello.api.UserClient;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;


public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public String findById(Long id) {
                return "返回默认信息";
            }
        };
    }
}

 

在UserClient文件配置,在@FeignClient注解添加fallbackFactory参数,值为上述代码的类名

@FeignClient(value = "user-service", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
    @GetMapping("/user/{id}")
    String findById(@PathVariable("id") Long id);
}

然后还要将配置注册进bean

可以自定义配置类,也可以直接在启动类配置Bean

这里直接在启动类配置Bean

package com.dreams.hello;


import com.dreams.hello.api.fallback.UserClientFallbackFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;


@SpringBootApplication
@EnableFeignClients
public class HelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }

    @Bean
    public UserClientFallbackFactory userClientFallbackFactory(){
        return new UserClientFallbackFactory();
    }

}

 

这样当调用user/{id}是出现异常,将返回定义的默认值“返回默认信息”。

运行

我们配置阙值为0,看看返回的效果

如图:

 

线程隔离(舱壁模式)

线程隔离分为线程池隔离和信号量隔离(Sentinel默认采用)

线程池隔离

即每个资源享用固定的线程数量,互不影响,这样即使一方异常也不会引起雪崩。

优点:使用线程池,就可以好容易管理各个线程

  • 支持主动超时
  • 支持异步调用

缺点:线程的额外开销比较大

Hystix默认是基于线程池实现的线程隔离,每一个被隔离的业务都要创建一个独立的线程池,线程过多会带来额外的CPU开销,性能一般,但是隔离性更强。

信号量隔离

固定总共多少,一起使用,但是固定只能共存一定数量

优点:轻量级,无额外开销

缺点:不使用线程池,也就不支持主动超时不支持异步调用

Sentinel是基于信号量(计数器)实现的线程隔离,不用创建线程池,性能较好,但是隔离性一般。

 

实现也很简单,同样打开流控

将阙值类型改为线程数,就开启了线程隔离(舱壁模式)

 

熔断降级

熔断:当资源的异常比例超过设定的阈值时,系统会触发熔断,暂时关闭资源的访问,避免继续向下游服务发送请求,从而保护系统不受连锁故障的影响。

降级:当资源被熔断后,可以配置降级策略,返回预设的默认值或执行预定义的降级逻辑,保证系统的可用性和稳定性。

 

断路器有三个状态:

  • 关闭状态(Closed):在关闭状态下,断路器允许请求通过,并监控失败请求的数量或失败率。如果失败请求未达到触发熔断的阈值,则保持断路器处于关闭状态,继续监控请求。
  • 打开状态(Open):一旦失败请求的数量或失败率超过了设定的阈值,断路器会进入打开状态,停止所有对资源的访问,并直接返回失败响应,从而避免向下游服务发送更多请求。
  • 半开状态(Half-Open):熔断时间结束,断路器会尝试放通部分请求进入资源,以检测资源的可用性。如果这些请求成功,则断路器会恢复到关闭状态;如果这些请求仍然失败,则断路器会重新进入打开状态。

 

断路器三个熔断策略:慢调用、异常比例、异常数

在簇点链路配置

 

1.慢调用:

慢调用熔断策略基于请求的响应时间来触发熔断。当服务的请求响应时间超过预设的阈值时,断路器会进入打开状态,停止对资源的访问。

业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。如图超过500ms的调用是慢调用,统计最近10000ms内的请求,如果请求量超过10次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。

2.异常比例:

异常比例熔断策略基于请求的异常率来触发熔断。当服务的异常请求比例超过设置的阈值时,断路器会进入打开状态,停止对资源的访问,以避免错误请求继续影响系统的稳定性。这种策略有助于及时发现并应对服务异常情况。

统计最近1000ms内的请求,如果请求量超过10次,并且异常比例不低于0.4,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。

 

3.异常数:

异常数熔断策略基于一定时间内的异常请求数量来触发熔断。当异常请求的数量达到设定的阈值时,断路器会进入打开状态,暂时停止对资源的访问,以减轻系统的负荷和保护资源不受进一步损害。

 

5.授权规则

授权规则可以对调用方的来源做控制。

在白名单内的调用者允许访问,在黑名单内的调用者不允许访问

流控应用的值就是请求头要带参数origin的值

比如:

同样在hello-server新建sentinel/HeaderOriginParser文件 

Sentinel提供了 RequestOriginParser 接口来处理来源。

只要Sentinel保护的接口资源被访问,Sentinel就会调用 RequestOriginParser 的实现类去解析访问来源。我们实现这个接口来加上我们的逻辑。

package com.dreams.hello.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

@Component
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        // 1.获取请求头
        String name = request.getHeader("origin");
        // 2.非空判断
        if (StringUtils.isEmpty(name)) {
            name = "blank";
        }
        return name;
    }
}

这段代码的作用是根据请求头中的”origin“字段来确定请求的来源

新建个模块gateway

依赖:

<dependencies>
     <!--nacos服务注册发现依赖-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.7.RELEASE</version> 
    </dependency>
    <!--网关gateway依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <version>2.2.7.RELEASE</version>
    </dependency>
</dependencies>

application.yml配置

server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes:
        - id: user-service # 路由标示,必须唯一
          uri: lb://user-service # 路由的目标地址
          predicates: # 路由断言,判断请求是否符合规则
            - Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
        - id: hello-service
          uri: lb://hello-service
          predicates:
            - Path=/order/**
    default-filters:
      - AddRequestHeader=origin,dreams

这里AddRequestHeader=origin,dreams配置每个网关的值都加上了origin=dreams

如果不走网关就失败

网关正常

 

6.自定义异常

如果我们没有处理,那前端就会拿到未处理的错误消息

 

我们自定义一个返回类

package com.dreams.hello.sentinel;

import java.io.Serializable;


public class Result implements Serializable {
    String msg;
    int code;
    String data;

    public Result(String msg, int code, String data) {
        this.msg = msg;
        this.code = code;
        this.data = data;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}

 

BlockExceptionHandler 是 Sentinel 提供的异常处理器接口,用于在发生流量控制异常时进行处理。

  • FlowException限流异常
  • ParamFlowException热点参数限流的异常
  • DegradeException降级异常
  • AuthorityException授权规则异常
  • SystemBlockException系统规则异常

 

package com.dreams.hello.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int code = 429;
        if (e instanceof FlowException) {
            msg = "请求限流";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            code = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setStatus(code);
        ObjectMapper objectMapper = new ObjectMapper();
        response.getWriter().println(objectMapper.writeValueAsString(new Result(msg,code,null)));
    }
}

这样就可以返回指定的结果,前端也好处理。

 

 

7.规则持久化

可以参考:Sentinel规则持久化

Sentinel的控制台规则管理有三种模式:

  • 原始模式 :API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource) 简单,无任何依赖 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境
  • Pull 模式 :扩展写数据源(WritableDataSource), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等 简单,无任何依赖;规则持久化 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
  • Push 模式: 扩展读数据源(ReadableDataSource),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。

可以参考官方文档:Sentinel持久化

推荐

 

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇