springboot集成与使用Sentinel的方法

前言

在上一篇中,我们初步了解了Sentinel的基本概念,以及其有关限流方面的基础理论,本篇将通过简单的与框架进行整合,看看Sentinel如何在实际项目中进行使用

控制台安装与部署

在实际的小微服务中,使用Sentinel做限流还有另一个强大的利器,就是其提供的dashboard,尽管我们可以通过编写Sentinel提供的一些API限流规则封装一些通用的方法,但是这对于很多初次接触Sentinel的同学来说,学习成本仍然不小,而提供的dashboard可以很方便的通过界面配置的方式达到上一篇中我们追求的效果,甚至更加灵活,而开发人员无非要做的就是,在程序代码中,只需要捕获限流后的异常并抛给页面提醒调用者即可,

进入Sentinel的git,点击下载提供的dashboard,最新的为1.8

下载到本地之后,其实就是一个springboot打成的jar包,windows环境下,cmd窗口,直接通过下面的命令启动即可,

java -jar -Dserver.port=9100 sentinel-dashboard-1.8.0.jar

启动成功后,访问一下吧,初次访问,需要登录用户名和密码,均为 : sentinel/sentinel

但是进来之后发现空空如也,别紧张,这个dashboard默认是懒加载的,意思就是没有应用接入进来,它就不展示任何信息,等到我们将本地的服务通过配置接入的时候就能看到效果了

springboot工程快速接入dashboard

1、导入基本的依赖

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

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

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql-connector-java.version}</version>
    </dependency>

		<dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-sentinel</artifactId>
    </dependency>

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

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

2、yml配置

server:
 port: 8082

spring:
 datasource:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://IT:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
  username: root
  password: root

#logging:
# config: classpath:logback-spring.xml #日志

 application:
  name: service-order

 #注册中心使用nacos
 cloud:
  nacos:
   discovery:
    server-addr: IP:8848

  #连接sentinel的dashboard
  sentinel:
   transport:
    dashboard: localhost:9100

 #设置单个文件最大上传大小
 servlet:
  multipart:
   max-file-size: 20MB

mybatis-plus:
 mapper-locations: classpath*:mapper/*.xml
 global-config:
  db-column-underline: true #开启驼峰转换
  db-config:
   id-type: uuid
   field-strategy: not_null
  refresh: true
 configuration:
  map-underscore-to-camel-case: true
  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句便于调试

#暴露的健康检查服务端点
management:
 endpoints:
  web:
   exposure:
    include: '*'

3、编写简单的controller接口

@RestController
public class FlowController {

  @Autowired
  private FlowService flowService;

  @GetMapping("/testFlow")
  public String testFlow(){
    return flowService.doFlow();
  }

}

浏览器访问一次:localhost:8082/testFlow 之后,这次再观察dashboard,发现相关的可配置菜单和可视化界面的参数就都展示了出来

dashboard使用简单说明

其实在上一篇中,我们谈到了使用Sentinel提供的API配置的多种限流规则,比如基于QPS下的快速失败,预热,匀速队列,关联链路等,而dashboard上面的配置则正好对应其底层的各种配置规则,下面我们演示几种常用的场景吧

在簇点链路这一栏,图中可以看到我们的后端服务接口即刚刚调用过的接口就会展示在这里,配置限流规则可以通过加号中的”添加流控“进行配置,

规则1:QPS,如上所示,我们配置了针对访问testFlow这个接口的所有来源的请求进行QPS的限流,每秒最大允许通过2个请求,

配置完毕后,当我们再次快速访问接口时,会出现下面的结果,很明显,我们的配置规则生效了

在上面的演示中,其实我们用到的就是最基本的降级策略,就是基于QPS的快速降级,我们不妨点开高级选项,是不是发现这里有了更多的配置,其实在可视化界面下,使用它做限流规则配置时就是使用它提供的不同配置项组合使用

关联配置

链路配置,比如多个微服务之间存在多级调用时,请求第一个服务接口,而第一个服务再调用第二个服务接口,第一个服务请求接口失败了,这时候再访问第二个服务接口时就会快速失败,通过这种配置规则可以避免服务的雪崩

关于流控效果,在前一篇中我们通过简单的demo演示了效果,就不再赘述了

关于降级

还以前面的 /testFlow接口为例:

服务降级可能大家并不陌生,即在一个应用中,当请求到某个服务接口长时间没有响应时,为了避免更多的请求进来造成服务的雪崩,我们采取一种机制,让程序快速返回结果,或者干脆抛出友好的提示,让调用者知道当前的服务不可用,这样就不至于出现服务端的线程资源被耗尽的情况

对于上述图中的配置,解释起来就是:超过了每秒请求的阈值之后,后面的请求再过来的时候,在5秒之内,服务处于不可用的状态,5秒之后,服务恢复,我们通过快速刷新接口,可以看到效果

如果是异常数的配置,则触发条件如下:

  • 开启条件:1秒内,有一个/testFlow请求过来,便开启熔断检查
  • 触发熔断:当前时间窗口内,有超过50%的请求产生异常
  • 触发熔断之后的5秒内,再有请求过来,都会被blocked

Sentinel异常处理、注解使用、与限流

在上面我们为 /testFlow这个接口配置了限流的规则,当请求超过每秒2个时,后端返回了下面的异常,这个异常是由Sentinel框架自身返回的提示

Blocked by Sentinel (flow limiting)

但在真实的开发中,这样做并不友好,而且对于调用者来说,并不知道到底出了什么问题,甚至前端的同学也不知道怎么做后续的处理,因此需要服务端对Sentinel的异常进行处理

@SentinelResource

使用这个注解,可以对我们要进行限流的资源接口当出现异常时进行捕获,比如下面的这个接口 getByResource,@SentinelResource的使用很简单,最基本的就是配置资源名称,加上blockHandler ,blockHandler 里面是触发限流规则时的方法,即在这个方法中进行后续的业务处理,如抛出友好的提示等

@RestController
public class RateLimitController {

  @GetMapping("/getByResource")
  @SentinelResource(value = "getByResource",blockHandler = "handleException")
  public ResponseResult getByResource(){
    return ResponseResult.success("this is success result");
  }

  public ResponseResult handleException(BlockException blockExe){
    return ResponseResult.fail(412,"is block:" + blockExe.getMessage());
  }

}

同样,我们在dashboard中对这个接口进行配置,每秒1次的QPS,正常访问时,

快速访问时,就走到了降级后的方法中了

但是如果这么做的话,很明显的一个问题就是,异常处理的逻辑和业务耦合在一起,代码会越来越膨胀,后续不方便管理,因此我们单独提供一个类,这个类专门用于提供不同的异常方法,

public class CustomerBlockHandler {

  public static ResponseResult handleException(BlockException exe){
    return ResponseResult.fail(412,"is block:" + exe.getMessage());
  }
}

那么在接口中我们就可以这样调用

@GetMapping("/getByResource1")
  @SentinelResource(value = "customerBlockHandler",
  blockHandlerClass = CustomerBlockHandler.class,
  blockHandler = "handleException")
  public ResponseResult getByResource1(){
    return ResponseResult.success("this is success result");
  }

同样,再在控制台配置限流规则后可以达到我们的效果,

Sentinel降级处理

有这么一种情况,当调用接口时,由于参数校验不通过,或者后端抛出了运行时的异常,如果没有合适的处理,将会出现下面的结果,

@GetMapping("/createOrder")
  @SentinelResource(value = "fallback")
  public String createOrder(String id){
    if(id.equals("2")){
      throw new IllegalArgumentException("参数异常");
    }
    return orderService.createOrder(id);
  }

显然,这是一种不太友好的情况,对于这种情况,就可以使用Sentinel的服务降级进行处理了,改造后的接口如下:

@GetMapping("/createOrder")
  @SentinelResource(value = "fallback",fallback = "getFallBack")
  public String createOrder(String id){
    if(id.equals("2")){
      throw new IllegalArgumentException("参数异常");
    }
    return orderService.createOrder(id);
  }

  public static String getFallBack(String id,Throwable t){
    return id + ":=====>" + t.getMessage();
  }

再次访问时,可以看到出现了我们的降级方法,也可以理解为兜底的方法

同样我们可以利用一个单独的类,统一处理这样的降级,如下:

@GetMapping("/createOrder")
  @SentinelResource(value = "fallback",fallbackClass = MyFallBackHandler.class,fallback = "getFallBack")
  public String createOrder(String id){
    if(id.equals("2")){
      throw new IllegalArgumentException("参数异常");
    }
    return orderService.createOrder(id);
  }
public class MyFallBackHandler {

  public static String getFallBack(String id,Throwable t){
    return id + ":=====>" + t.getMessage();
  }

}

其实在真实的开发中,不管是单应用还是微服务之间的调用,一般情况下可能出现的异常我们基本上都是可以提前预知的,如超时异常,系统参数异常等,这样我们就可以预设部分的降级处理方法,在适当的接口上面进行引用即可

Sentinel降级处理结合feign的使用

在上一篇和本次的dashboard的讲解使用中,我们提到了链路的处理规则,对应于不同的微服务来说就是不同的服务之间的调用,当调用某个服务接口失败时的情况,以openfeign的使用为例,本例我们在createOrder接口中,还调用了storage服务中的接口,

@Component
@FeignClient(value = "service-storage")
public interface StorageFeignService {

  @GetMapping(value = "/storage/get/{id}")
  public Integer getPaymentById(@PathVariable("id") String id);
}
	@Autowired
  private StorageFeignService feignService;

  @Override
  public String createOrder(String id) {
    int storage = feignService.getPaymentById(id);
    log.info("storage is = {}",storage);
    return "success";
  }

设想,假如在调用getPaymentById接口失败时,为了不至于因为报错或者长时间的超时等待造成雪崩,我们可以统一feignService中进行处理,这里需要提供一个类,比如FallBackStorageService,这个类实现了StorageFeignService 接口

@Component
@FeignClient(value = "service-storage",fallback = FallBackStorageService.class)
public interface StorageFeignService {

  @GetMapping(value = "/storage/get/{id}")
  public Integer getPaymentById(@PathVariable("id") String id);
}
@Component
public class FallBackStorageService implements StorageFeignService {

  @Override
  public Integer getPaymentById(String id) {
    return 1001;
  }
}

即当storage模块中的getPaymentById服务接口异常或者不可用时,将会由FallBackStorageService 中的getPaymentById进行降级,俗称兜底

当然不要忘了在yml中添加如下这一句配置,让Sentinel支持在feign调用时对于异常的生效

feign:
 sentinel:
  enabled: true

那我们简单测试下吧,正常访问时:

这时我们停掉storage服务,再次访问上面的接口时,很明显就走到了我们的降级逻辑中,当然我这里只是做了很简单的处理,可以在降级逻辑中添加更友好的提示信息

当然上面是服务不可用的时候的降级逻辑,当情况是异常时候,我们可以通过实现FallbackFactory接口进行处理

@Component
public class FeignFallbackHandler implements FallbackFactory<StorageFeignService> {

  @Override
  public StorageFeignService create(Throwable throwable) {
    return new StorageFeignService(){
      @Override
      public Integer getPaymentById(String id) {
        System.out.println("异常触发:" + throwable.getMessage());
        return 1001;
      }
    };
  }
}

本篇到这里就要结束了,通过本篇内容,比较详细的介绍了Sentinel的相关使用,基于dashboard配置的各种限流规则,以及结合程序中进行使用,最后提到了和feign整合使用时的处理方法,篇幅较长,最后感谢观看!

到此这篇关于springboot集成与使用Sentinel的方法的文章就介绍到这了,更多相关springboot Sentinel集成与使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot基于Sentinel在服务上实现接口限流

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • 详解SpringBoot Redis自适应配置(Cluster Standalone Sentinel)

    核心代码段 提供一个JedisConnectionFactory  根据配置来判断 单点 集群 还是哨兵 @Bean @ConditionalOnMissingBean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = null; String[] split = node.split(","); Set<HostAndPort> nodes =

  • springboot集成与使用Sentinel的方法

    前言 在上一篇中,我们初步了解了Sentinel的基本概念,以及其有关限流方面的基础理论,本篇将通过简单的与框架进行整合,看看Sentinel如何在实际项目中进行使用 控制台安装与部署 在实际的小微服务中,使用Sentinel做限流还有另一个强大的利器,就是其提供的dashboard,尽管我们可以通过编写Sentinel提供的一些API限流规则封装一些通用的方法,但是这对于很多初次接触Sentinel的同学来说,学习成本仍然不小,而提供的dashboard可以很方便的通过界面配置的方式达到上一篇

  • SpringBoot集成slf4j日志配置的方法

    目录 前言 1.slf4j概述 2.pom.xml的日志依赖 3.application.yml的日志配置 4.logback.xml配置文件定义 5.logback.xml配置文件解析 5.1 定义日志的存储路径 5.2 定义日志的输出格式 5.3 定义控制台输出 5.4 定义日志相关参数 5.5 定义日志的输出级别 6.测试日志输出 7.小结 前言 日志,作为一个应用系统的重要部分,然而并不会在项目预研或需求设计阶段就作为一个功能模块单独规划设计,但这丝毫不影响它在任何一个系统中的重要的地位

  • springboot集成shiro自定义登陆过滤器方法

    目录 前言 自定义UsernamePasswordAuthenticationFilter 覆盖默认的FormAuthenticationFilter 完整UsernamePasswordAuthenticationFilter代码 前言 在上一篇博客springboot集成shiro权限管理简单实现中,用户在登录的过程中,有以下几个问题: 用户在没有登陆的情况下,访问需要权限的接口,服务器自动跳转到登陆页面,前端无法控制: 用户在登录成功后,服务器自动跳转到成功页,前端无法控制: 用户在登录失

  • SpringBoot集成Quartz实现定时任务的方法

    1 需求 在我的前后端分离的实验室管理项目中,有一个功能是学生状态统计.我的设计是按天统计每种状态的比例.为了便于计算,在每天0点,系统需要将学生的状态重置,并插入一条数据作为一天的开始状态.另外,考虑到学生的请假需求,请假的申请往往是提前做好,等系统时间走到实际请假时间的时候,系统要将学生的状态修改为请假. 显然,这两个子需求都可以通过定时任务实现.在网上略做搜索以后,我选择了比较流行的定时任务框架Quartz. 2 Quartz Quartz是一个定时任务框架,其他介绍网上也很详尽.这里要介

  • Springboot集成JSR303参数校验的方法实现

    JSR303 是一套 JavaBean 参数校验的标准 1.pom导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> 2.注解类型 (1)空检查 @Null 验证对象是否为null @NotNull 验证对象是否不为null,

  • SpringBoot集成Swagger2生成接口文档的方法示例

    我们提供Restful接口的时候,API文档是尤为的重要,它承载着对接口的定义,描述等.它还是和API消费方沟通的重要工具.在实际情况中由于接口和文档存放的位置不同,我们很难及时的去维护文档.个人在实际的工作中就遇到过很多接口更新了很久,但是文档却还是老版本的情况,其实在这个时候这份文档就已经失去了它存在的意义.而 Swagger 是目前我见过的最好的API文档生成工具,使用起来也很方便,还可以直接调试我们的API.我们今天就来看下 Swagger2 与 SpringBoot 的结合. 准备工作

  • SpringBoot集成Beetl后统一处理页面异常的方法

    背景 SpringBoot集成Beetl后如果页面出现异常会将出现异常之前的页面输出到客户端,但是由于页面不完整会导致用户看到的页面错乱或者空白,如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 在控制台可以看到 >

  • SpringBoot集成WebSocket实现前后端消息互传的方法

    什么是WebSocket? WebSocket 协议是基于 TCP 的一种新的网络协议.它实现了浏览器与服务器全双工 (full-duplex) 通信-允许服务器主动发送信息给客户端. 为什么需要WebSocket? 大家都知道以前客户端想知道服务端的处理进度,要不停地使用 Ajax 进行轮询,让浏览器隔个几秒就向服务器发一次请求,这对服务器压力较大.另外一种轮询就是采用 long poll 的方式,这就跟打电话差不多,没收到消息就一直不挂电话,也就是说,客户端发起连接后,如果没消息,就一直不返

  • SpringBoot集成Redisson实现分布式锁的方法示例

    上篇 <SpringBoot 集成 redis 分布式锁优化>对死锁的问题进行了优化,今天介绍的是 redis 官方推荐使用的 Redisson ,Redisson 架设在 redis 基础上的 Java 驻内存数据网格(In-Memory Data Grid),基于NIO的 Netty 框架上,利用了 redis 键值数据库.功能非常强大,解决了很多分布式架构中的问题. Github的wiki地址: https://github.com/redisson/redisson/wiki 官方文档

  • springboot集成nacos的配置方法

    本文介绍了springboot集成nacos的配置方法,分享给大家,具体如下: nacos仓库:https://github.com/alibaba/nacos nacos介绍文档:https://nacos.io/zh-cn/docs/architecture.html nacos使用例子:https://github.com/nacos-group/nacos-examples springboot配置-集成nacos,例子代码下载 springboot-nacos-consumer spr

随机推荐