SpringCloudAlibaba-2.熔断、降级与限流(Sentinel)

目录

一、概念

1.1 介绍

1.2 快速配置

二、基础功能演示

三、流控规则

四、降级规则

五、@SentinelResource注解

5.1 按资源名限流演示

5.2 自定义限流处理类

六、热点Key限流

6.1 基本演示

6.2 热点规则添加例外项

七、系统规则

八、服务熔断功能(+ribbon/openFeign)

8.1 sentinel+ribbon

8.2 sentinel+openFeign

九、规则持久化


一、概念

1.1 介绍

        Sentinel是一个轻量级的流量控制熔断降级Java库。类似于Hystrix。可以处理服务使用过程中的各种问题,如服务雪崩服务降级服务熔断服务限流等。

1.2 快速配置

        下载:下载jar包,例如sentinel-dashboard-1.7.0.jar

        使用前提Jdk88080端口未被占用。

        开启:在jar包目录下执行下面指令。

java -jar sentinel-dashboard-1.7.0.jar

        最后输入地址:        http://localhost:8080        即为Sentinel的后台管理界面

二、基础功能演示

        1.建立新工程-cloudalibaba-sentinel-service8401

        2.POM

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

        3.XML

server:
  port: 8401

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

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

        4.主启动

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

        5.业务类

@RestController
public class FlowLimitController
{

    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB";
    }
}

        6.测试

                首先确保启动了NacosSentinel服务。

                连续输入:        localhost:8401/testA   localhost:8401/testB

                Sentinel 后台的数据:(QPS-每秒的请求数

三、流控规则

四、降级规则

 RT(平均响应时间,秒级)
      平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
      窗口期过后关闭断路器
      RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)


异常比列(秒级)
    QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级


异常数(分钟级)
     异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级


        Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
        当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。 

        Sentinel断路器没有半开状态

五、@SentinelResource注解

        简单来说,@SentinelResource 用来标识资源名以及定义违反规则代码出错时的兜底方法,类似于HystrixCommand 定义FallBack。系统默认有兜底方法,默认提示:Blocked by Sentinel (flow limiting)

5.1 按资源名限流演示

        还是在上面的 cloudalibaba-sentinel-service8401

                1.POM引入自定义包

        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

                2.新建Controller

@RestController
public class RateLimitController
{
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }
}

                 3.配置流控规则

         4.测试

                输入:      localhost:8401/byResource   频次大于1时,会返回我们自定义的错误信息。

        注:最好按照资源名设置流控规则,如果按照URL设置,只会使用默认兜底方法

5.2 自定义限流处理类

        上面方式的问题:

1  系统默认的,没有体现我们自己的业务要求。
2  依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。 
3  每个业务方法都添加一个兜底的,那代码膨胀加剧。 
4  全局统一的处理方法没有体现。

        1.自定义限流处理类- CustomerBlockHandler

public class CustomerBlockHandler
{
    public static CommonResult handleException(BlockException exception){
        return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler");
    }
}

        2.修改Controller

    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客户自定义限流处理逻辑");
    }

         3.测试

                设置流控规则

            输入: 

    localhost:8401/rateLimit/customerBlockHandler  频次大于1时,会返回我们自定义的错误信息。

六、热点Key限流

        热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作        

6.1 基本演示

        1.修改Controller

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1, 
                         @RequestParam(value = "p2",required = false) String p2){
    return "------testHotKey";
}
public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
{
    return "-----dealHandler_testHotKey";
}

        2.设置热点规则

        方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理

        3.测试

                输入:        http://localhost:8401/testHotKey?p1=abc        频率超过1,报错

                输入:        http://localhost:8401/testHotKey?p1=abc&p2=33   频率超过1,报错

                输入:        http://localhost:8401/testHotKey?p2=abc        频率超过1,不报错

6.2 热点规则添加例外项

        上面的示例中,参数p1当QPS超过1秒1次点击后马上被限流,假如我们期望p1参数是某个特殊值时,它的限流阈值和平时不一样。(就是在特定条件下允许例外),可以这样设置:

         注:热点参数的注意点,参数必须是基本类型或者String

七、系统规则

         这个设置要慎重,因为全局的,影响到整个服务节点。不再演示

八、服务熔断功能(+ribbon/openFeign

        有两种方案:sentinel+ribbon / sentinel+openFeign

8.1 sentinel+ribbon

        1.新建cloudalibaba-provider-payment9003/9004两个一样的做法,只是端口不同

        2.POM

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

        3.YML

server:
  port: 9003    #记得改

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

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

        4.主启动

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

        5.业务类

@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    public static HashMap<Long,Payment> hashMap = new HashMap<>();
    static
    {
        hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }

}

        6.新建 cloudalibaba-consumer-nacos-order84 

        7.POM


    <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>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

        8.YML

server:
  port: 84


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719


#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider

        9.主启动

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

        10.业务类

                10.1 ApplicationContextConfig

@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}

                10.2 CircleBreakerController 

        @SentinelResource 设置fallback blockHandler 属性,可以分别处理运行时异常违反sentinel规则兜底方法

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
     @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
        if (id == 4) {
            throw new IllegalArgumentException ("非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录");
        }
        return result;
    }
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"fallback,无此流水,exception  "+e.getMessage(),payment);
    }
    public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }

}

        11.测试

        在sentinel中进行配置:

         首先输入:       http://localhost:84/consumer/fallback/1    正常显示数据

         连续输入上面的地址        blockHandler->

{
    "code": 445,
    "message": "blockHandler-sentinel限流,无此流水: blockException  null",
    "data": {
        "id": 1,
        "serial": "null"
    }
}

        再输入:        http://localhost:84/consumer/fallback/4        fallback->

{
    "code": 444,
    "message": "兜底异常handlerFallback,exception内容  IllegalArgumentException,非法参数异常....",
    "data": {
        "id": 4,
        "serial": "null"
    }
}

         注:blockHandler fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。

8.2 sentinel+openFeign

        1.消费端引入openfeign依赖

        <!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        2.修改YML,激活sentinel对feigh的支持

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true  

         3.新建业务接口 PaymentService,带@FeignClient注解

@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}

        4.新建异常处理业务类 PaymentFallbackService实现 PaymentService

@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
    }
}

        5.修改Controller

    @Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        return paymentService.paymentSQL(id);
    }

         6.主启动类添加@EnableFeignClients注解

         7.测试

             输入:           http://localhost:84/consumer/paymentSQL/1        正常显示

             此时关闭8003、8004        返回fallback:

{
    "code": 44444,
    "message": "服务降级返回,---PaymentFallbackService",
    "data": {
        "id": 4,
        "serial": "errorSerial"
    }
}

九、规则持久化

        一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化,将限流配置规则持久化进Nacos保存。

        比如我们希望对cloudalibaba-sentinel-service8401上的规则进行持久化:

        1.POM

<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

        2.YML

spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

        3.Nacos中添加规则配置

[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。

        4.测试

                重启8041服务,发送如下请求:

http://localhost:8401/rateLimit/byUrl

                刷新sentinel,可以看到持久化的配置规则了:

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Alibaba 提供了多种服务限流的解决方案,其中比较常用的是通过使用 Sentinel 来实现服务限流Sentinel 是阿里巴巴开源的一款强大的流量控制组件,它提供了实时监控、熔断降级、系统保护等功能。下面简单介绍一下在 Spring Cloud Alibaba 中如何使用 Sentinel 进行服务限流。 首先,需要在项目的依赖中引入 Sentinel 相关的依赖,可以在 Maven 或者 Gradle 中添加如下配置: Maven: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> ``` Gradle: ``` implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel' ``` 接下来,在启动类上添加 `@EnableSentinel` 注解,开启 Sentinel 功能。 然后,在需要进行限流的方法上添加 `@SentinelResource` 注解,并指定相应的限流规则。例如: ```java @SentinelResource(value = "hello", blockHandler = "blockHandler") public String hello() { return "Hello World"; } public String blockHandler(BlockException ex) { return "Blocked by Sentinel"; } ``` 上述代码中,`@SentinelResource` 注解中的 value 属性是资源名称,blockHandler 属性指定了限流或者熔断降级时的处理方法。 最后,可以通过 Sentinel 控制台进行限流规则的配置和查看实时监控数据。控制台的地址为:http://localhost:8080。 以上就是在 Spring Cloud Alibaba 中使用 Sentinel 进行服务限流的简单介绍,希望对你有所帮助!如果还有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值