spring cloud 之 sentinel

sentinel概述

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

sentinel的两个部分 

核心库(Java 客户端): 不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持
控制台(Dashboard): 基于 Spring Boot 开发,打包后可以直接运行,默认访问端口8080,用户名密码均为sentinel

sentinel项目搭建 

环境介绍

我这里的搭建三个服务

cloud-gateway-service  网关服务,集成sentinel,这里转发到cloud-feign-client

cloud-feign-client  feign的客户端,在这里将调用cloud-test-service

cloud-test-service 测试服务,主要提供一个controller访问

项目采用nacos作为注册中心

cloud-gateway-service搭建

依赖引入

<dependencies>
        <!-- 网关依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--nacos客户端依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--spring cloud gateway整合sentinel的依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>

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

</dependencies>

项目配置文件

server:
  port: 10010
spring:
  application:
    name: could-gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: cloud-feign-client
          uri: lb://cloud-feign-client
          predicates:
            - Path=/test/**
          filters:
            - StripPrefix=1
      discovery:
        locator:
          enabled: true
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080



cloud-feign-client搭建 

此服务中也加入了sentinel流控规则,对服务上的sentinel和gateway上的sentinel之间还是有着不同的

网关上做粗粒度的限流,而服务上能更精细化的限流

加入依赖

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

 配置文件

spring:
  application:
    name: cloud-feign-client
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
server:
  port: 9300
feign:
  httpclient:
    connection-timeout: 5000


下面的代码块是一个feign调用测试服务的代码 

package com.slbuildenv.cloud.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(value="cloud-test-service" )
public interface TestFeign {

    @GetMapping("/find/date")
    String findDate();
}
package com.slbuildenv.cloud.controller;

import com.slbuildenv.cloud.client.TestFeign;
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("/feign")
public class TestFeignRemote {

    @Autowired
    private TestFeign testFeign;

    @GetMapping("/date")
    public String getRemoteDate() throws InterruptedException {
       return  testFeign.findDate();
    }

}

cloud-test-service搭建 

该服务仅仅是提供访问数据,目前不涉及service和mapper,只有一个controller,别忘了注册nacos,这里不列举配置啦

package com.slbuildenv.cloud.controller;

import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@RestController
@RequestMapping("/find")
@RefreshScope
public class TestFeign {


    @GetMapping("/date")
    public String getDate(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }
}

启动项目 

启动三个项目向nacos注册,nacos控制台查看服务注册

需要下载sentinel dashbord 的jar包,由于该死的github太慢啦,我从别人网盘下载的,我这里下载的版本1.8.4 如有需要可以在传送门这里找云盘下载链接

下载完毕,java -jar sentinel-dashbord 1.8.4.jar 即可,访问8080端口登录,用户名密码均为

sentinel

Sentinel的资源定义方式 

定义资源

对于资源的定义有两种,一种是硬编码的方式,一种是通过 @SentinelResource 注解的方式,推荐使用注解方式,避免造成业务入侵

硬编码方式

 抛出异常的方式定义资源:SphU

    Entry entry = null;
    try {
        // 定义一个sentinel保护的资源,
        entry = SphU.entry(resourceName);
        // 被保护的业务逻辑
    } catch (BlockException e) {
        // 如果被保护的资源被限流或者降级了,就会抛出BlockException
        log.warn("资源被限流或降级了", e);
    } catch (InterruptedException e) {
        log.error("发生InterruptedException",e);
    } finally {
        if (entry != null) {
            entry.exit();
        }
    }

try-with-resources 来定义资源

public static void main(String[] args) {
    // 配置规则.
    initFlowRules();
 
    // 1.5.0 版本开始可以直接利用 try-with-resources 特性
    try (Entry entry = SphU.entry(resourceName)) {
        // 被保护的逻辑
        System.out.println("hello world");
    } catch (BlockException ex) {
        // 处理被流控的逻辑
        System.out.println("blocked!");
    }
}

 返回布尔值的方式定义资源  SphO.entry(“资源名”)

  // 资源名可使用任意有业务语义的字符串
  if (SphO.entry("自定义资源名")) {
    // 务必保证finally会被执行
    try {
      /**
      * 被保护的业务逻辑
      */
    } finally {
      SphO.exit();
    }
  } else {
    // 资源访问阻止,被限流或被降级
    // 进行相应的处理操作
  }

 @SentinelResource注解方式

  @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "block_testHotKey")
    public String testHotKey(@RequestParam(value = "test1")String test1,
                             @RequestParam(value = "test2")String test2){
        return "testHotKey....";
    }

value:资源名称,必需项

entryType:entry 类型,可选项(默认为 EntryType.OUT)

blockHandler / blockHandlerClass:blockHandler 指定函数负责处理 BlockException 异常,可选项。blockHandler 函数默认需要和原方法在同一个类中,通过指定 blockHandlerClass 为对应类的 Class 对象,则可以指定其他类中的函数,但注意对应的函数必需为 static 函数,否则无法解析 

fallback /fallbackClass:fallback 指定的函数负责处理业务运行的异常,可选项,fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。fallback 函数默认需要和原方法在同一个类中,通过指定 fallbackClass 为对应类的 Class 对象,则可以指定指定为其他类的函数,但注意对应的函数必需为 static 函数,否则无法解析
defaultFallback:默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑。defaultFallback 函数默认需要和原方法在同一个类中,通过指定 fallbackClass 为对应类的 Class 对象,则可以指定指定为其他类的函数,但注意对应的函数必需为 static 函数,否则无法解析
exceptionsToIgnore:用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

Sentinel的规则 

流控规则

资源名: 唯一名称,默认请求路径,表示对该资源进行流控
针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)

阈值类型/单击阈值:

  • QPS(每秒钟的请求数量):当调用该api的QPS达到阈值时,进行限流
  • 线程数:当调用该线程数达到阈值的时候,进行限流

是否集群:不需要集群

流控模式:

  • 直接: api达到限流条件时,直接限流
  • 关联: 当关联的资源达到阈值时,就限流自己
  • 链路: 只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】

流控效果:

  • 快速失败: 直接失败,抛异常
  • Warm Up: 根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFctor,经过预热时长,才达到设置的QPS阈值
  • 排队等待: 匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

添加流控为每秒请求数为1的时候进行流控,目前流控效果如下:

http://localhost:9300/feign/date 多次点击触发此效果

降级规则 

RT 平均响应时间: 当1s内持续进入5个请求,且对应请求的平均响应时间(秒级)均超过阈值,那么在接下来的时间窗口期内,对该方法的调用都会自动的熔断。

注意Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要更改上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置

异常比例: 当资源的每秒请求大于5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,在接下来的时间窗口内,对该方法的调用都会自动的返回。异常的取值在[0.1,1.0]

异常数: 当资源近1分钟的异常数超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若时间小于60s,则结束熔断状态后仍可能再进入熔断状态

 热点key规则

sentinel可以根据当前经常被访问的数据,统计其被访问次数,然后进行降级操作,在cloud-feign-client中加入测试热点key的controller

@SentinelResource注解和Hystrix中的@HystrixCommand类似,之前的案例,限流、降级出问题了,都是用的sentinel默认的提示信息,这个注解就是类似hystrix的注解,自定义兜底方法,某个方法出问题,就找对应的兜底方法
value = “testHotKey”:就是该资源的唯一标识,blockHandler = “block_testHotKey”:就是兜底方法

package com.slbuildenv.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.slbuildenv.cloud.client.TestFeign;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/feign")
public class TestFeignRemote {

    @Autowired
    private TestFeign testFeign;

    @GetMapping("/date")
    public String getRemoteDate() throws InterruptedException {
       return  testFeign.findDate();
    }

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "block_testHotKey")
    public String testHotKey(@RequestParam(value = "test1")String test1,
                             @RequestParam(value = "test2")String test2){
        return "testHotKey....";
    }
    public String block_testHotKey(String p1, String p2, BlockException exception){
        return "testHotKey被限流了...";
    }

}

 通过测试得知,我们的第一个参数被降级限流啦

系统规则

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

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

 Sentinel的规则持久化

将持久化规则放入Nacos中持久化

加入依赖

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

加入配置

spring:
  cloud:
    sentinel:
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 # nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow # 还可以是:degrade、authority、param-flow

更加详细配置请参考sentinel规则持久化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值