SpringCloudAlibaba之Sentinel(一)

作者: adm 分类: java 发布时间: 2024-01-31

介绍
  Sentinel组件承担了流量防卫兵的职责,主要用来限流与熔断。它提供了dashboard(仪表盘),让开发者能够可视化配置,简化操作。

启动dashboard
  下载地址,点击下图的jar包下载(笔者就是用的1.8.2这个版本)

  下载后,cmd窗口切换到jar包所在目录,输入命令:

   java -jar sentinel-dashboard-1.8.2.jar

  浏览器访问:localhost:8080,用户名、密码都是sentinel,能够登录成功:

后端配置
  此时dashboard还不能用呢,空空如也;要新建一个模块,并启动它。

  pom.xml引入依赖:


    
        org.springframework.boot
        spring-boot-starter-web
    

    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
    

    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-sentinel
    

    
        com.alibaba.csp
        sentinel-datasource-nacos
    



    
        
            com.alibaba.cloud
            spring-cloud-alibaba-dependencies
            2.2.6.RELEASE
            pom
            import
        

        
            org.springframework.boot
            spring-boot-dependencies
            2.2.6.RELEASE
            pom
            import
        
    


  boostrap.yml中配置:

server:
  port: 8401

spring:
  application:
    name: sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        # sentinel 仪表盘地址
        dashboard: localhost:8080
        port: 8719
      # 取消延迟加载(默认是延迟加载的)
      eager: true
      
management:
  endpoints:
    web:
      exposure:
        include: '*'

  看到配置中的nacos服务发现的配置了吧,因为sentinel是要和nacos搭配使用的。这里我们把nacos启动后,再运行该模块的启动类后,刷新dashboard的访问地址:localhost:8080,发现页面变了:

  这个模块下,新建一个控制器:

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    @RequestMapping("/byUrl")
    public String getUser() throws InterruptedException {
        return "javaCoder";
    }

    public String handleException(BlockException exception) {
        return "超出流量";
    }

}

  我们将对这个接口施加sentinel的限流与熔断。

流控规则
  dashboard添加一条:

资源名:接口的访问路径,或者是修饰接口的@SentinelResource的value值

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

阈值类型:
QPS:每秒钟的请求数量,当调用该接口的QPS打到阈值时,进行限流
并发线程数:调用该api的并发线程数达到阈值的时候,进行限流

是否集群:一般不需要勾选

流控模式:
直接:接口达到限流条件时,直接限流
关联:关联的资源打到限流时,限流自己
链路:指定入口进来的流量,才进行统计

流控效果:
快速失败:限流时,抛异常
Warm Up:从阈值/codeFactor(冷加载因子,默认3),经过预热时长,逐渐达到设定的阈值
排队等待:假如QPS阈值为5,1s钟通过5个请求,每200ms通过一个;其余的请求排队等候,如果在超时时间内进去了就成功访问接口,否则请求作废,不访问接口。选择这个时,阈值类型一定要选择QPS,否则无效

  用上面截图的配置,快速访问接口(快速点击刷新按钮),能够看到:


  说明已被限流,返回的状态码是429,返回信息是Blocked by Sentinel (flow limiting)

  如果我们改造下接口:

	@RequestMapping("/byUrl")
	//添加了@SentinelResource
	@SentinelResource(value = "byUrl", blockHandler = "handleException")
	public String getUser() throws InterruptedException {
	    return "javaCoder";
	}
	
	/**
     * 必须是public修饰
     * 返回类型和getUser()一样
     * 参数类型和getUser()一样,最后再加个BlockException类型的参数
     */
	public String handleException(BlockException exception) {
	    return "超出流量";
	}

  重启项目后,然后再重新加一次流控规则(dashboard上的规则都是临时的,模块重启就会丢失;后面会讲到如何持久化,重启后规则依然保留),其他不变,资源名改为byUrl,再次快速访问接口:


  这时限流后的返回信息就是我们指定的”超出流量”了,当然@SentinelResource的blockHandler也可以不指定,这时返回的是显示500的页面。

  上面流控模式是直接,如果选择关联的话,比如A接口关联了B接口,B接口达到阈值,B没事,A会被限流。读者可以用postman的Runner去测,比如对B接口发起10次请求,每次间隔200ms;然后浏览器中你去访问A,看会是什么结果。

  流控模式是链路,这种情况不常见;入口资源一般就是填写sentinel_spring_web_context(从浏览器端发送),还有一种是sentinel_default_context。

  上面一直演示的是流控效果是快速失败的情况,如果是Warm Up,

  一开始系统的QPS阈值是2(6/3),经过5s,逐步增长到6。这个6不是一直保持着,当一段时间没有请求后,阈值会回落到2的。我们用jmeter来压测一下:

  线程启动后,我们到dashboard的“实时监控”菜单去查看,过几秒后:


  阈值从2逐渐升到6了(6附近波动,偶尔是5或者7,问题不大)。注意这边要用jmeter去测,不要用postman的runner,不然效果是出不来的。

  流控效果选择排队等待:


  用jmeter去测,2s发送30个请求,



  点击绿色按钮启动,

  很多请求都没通过,只有10个通过了;我们把流控规则的超时时间调大,调到2500ms,再用jmeter去2s发30个请求:


  通过的请求明显变多了,因为超时时间变大了:一些排队等到200ms就作废的请求,因为现在调整成2500ms,可以在2500ms内排到自己了,所以成功请求接口。

熔断规则
  熔断:当服务提供方处于不稳定状态时(超时或经常抛出异常),断路器就会打开,请求该服务提供方时会直接失败,即进入熔断状态;经过一段时间后(可由开发配置),断路器进入半打开状态,如果下一次请求是正常的,断路器关闭,能够正常请求服务提供方了;如果下一次请求仍然异常,断路器重新打开,继续保持熔断状态。

  新增这样一条熔断规则(把上面的流控规则记得删掉,以免造成影响):

  1s内,如果请求数大于5(最小请求数)个,并且响应时间大于600ms(最大RT)的请求占比在60%(比例阈值)以上,就会进入熔断状态;8s后断路器进入半打开状态,下一次的请求如果响应时间仍然大于600ms,则再次进入熔断状态。

  我们把接口修改为:

    @RequestMapping("/byUrl")
    public String getUser() throws InterruptedException {
        // 增加了睡眠1s
        Thread.sleep(1000);
        return "javaCoder";
    }

  用jmeter去测:


  然后再到浏览器访问接口,发现是直接返回:


  过了几s后,某次点击等待1s能够返回”javaCoder”,但后面的点击又直接返回上图了。这就对了,返回”javaCoder”的那次是断路器进入半打开状态后的第一次请求,因为我们的接口仍然睡眠了1s才返回,大于600ms了,所以断路器又重新打开了。

  熔断策略是异常比例的话:

  就是1s内,如果请求数大于5(最小请求数)个,并且60%的请求是报错的(请求的方法抛异常了),进入熔断状态;半打开后的判断条件是下一次请求不能报错,方法仍抛异常会重新进入熔断状态。

  接口修改为:

    @RequestMapping("/byUrl")
    public String getUser() throws InterruptedException {
        throw new RuntimeException("抛异常");
    }

  再用上面相同的操作去试一下。

  熔断策略是异常数,和异常比例类似,前者是具体几个请求抛异常了,后者是抛异常的请求的比例。

  未完待续。。。

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!