我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。
Sentinel概述Sentinel (分布式系统的流量防卫兵)
Sentinel核心分为两个部分:
- 核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能,其控制台安装步骤如下:
第一步:打开sentinel下载
https://github.com/alibaba/Sentinel/releases
第二步:下载Jar包(可以存储到一个sentinel目录),如图所示:
第三步:在sentinel对应目录,打开命令行(cmd),启动运行sentinel
访问Sentinel服务java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
访问sentinel服务,默认端口号为8180,登录sentinel默认用户和密码都是sentinel
Sentinel限流入门 准备工作第一步:Sentinel 应用于服务提供方(sca-provider),在消费方添加依赖如下:
com.alibaba.cloud spring-cloud-starter-alibaba-sentinel
第二步:打开服务消费方配置文件bootstrap.yml,添加sentinel配置,代码如下:
spring: cloud: sentinel: transport: dashboard: localhost:8180 # 指定sentinel控制台地址。
第三步:创建一个用于演示限流 *** 作的Controller对象,例如:
package com.jt.provider.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/provider") public class ProviderSentinelController { @GetMapping("/sentinel01") public String doSentinel01(){ return "sentinel 01 test ..."; } }Sentinel限流入门实践
我们设置一下指定接口的流控(流量控制),QPS(每秒请求次数)单机阈值为1,代表每秒请求不能超出1次,要不然就做限流处理,处理方式直接调用失败。
第一步:选择要限流的链路,如图所示:
第二步:设置限流策略,如图所示:
Sentinel流控规则分析 阈值类型- QPS(Queries Per Second):当调用相关url对应的资源时,QPS达到单机阈值时,就会限流。
- 线程数:当调用相关url对应的资源时,线程数达到单机阈值时,就会限流。
Sentinel的流控模式代表的流控的方式,默认【直接】,还有关联,链路。
直接模式
Sentinel默认的流控处理就是【直接->快速失败】。
关联模式
当关联的资源达到阈值,就限流自己。例如设置了关联资源为/ur2时,假如关联资源/url2的qps阀值超过1时,就限流/url1接口(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)。这种关联模式有什么应用场景呢?我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。那就可以利用关联模式;在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。例如
第一步:在ProviderSentinelController中添加一个方法,例如:
@GetMapping("/sentinel02") public String doSentinel02(){ return "sentinel 02 test ..."; }
第二步:在sentinel中做限流设计,例如
第三步:打开两个测试窗口,对/provider/sentinel02进行访问,检查/provider/sentinel01的状态
链路模式
链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。现在对链路模式做一个实践,例如:
第一步:在指定包创建一个ResourceService类,代码如下:
package com.jt.provider.service; @Service public class ResourceService{ @SentinelResource("doGetResource") public String doGetResource(){ return "doGetResource"; } }
第二步:在ProviderSentinelController中添加一个方法,例如:
@Autowired private ResourceService resourceService; @GetMapping("/sentinel03") public String doSentinel03() throws InterruptedException { resourceService.doGetResource(); return "sentinel 03 test"; }
@SentinelResource 描述方法时,可以在sentinel控制台创建一个 链路资源,这个链路的名称默认为value属性的值,当出现限流时,客户默认看到的是一个500异常 假如希望对限流结果进行自定义处理,可以考虑使用blockHandlerClass 属性指定一个限流处理类,完后再通过blockHandler属性指定具体异常处理方法, 这个异常处理方法必须与@sentinelResource注解描述的方法,返回值类型相同, 同时必须是static方法,方法中参数可以是BlockException类型。
说明,流控模式为链路模式时,假如是sentinel 1.7.2以后版本,Sentinel Web过滤器默认会聚合所有URL的入口为sentinel_spring_web_context,因此单独对指定链路限流会不生效,需要在application.yml添加如下语句来关闭URL PATH聚合,例如:
sentinel:
web-context-unify: false
还有,当我们也可以基于@SentinelResource注解描述的方法进行限流后的异常进行自定义处理,其步骤如下:
第一步:定义blockHandlerClass,例如:
package com.jt.provider.service; import com.alibaba.csp.sentinel.slots.block.BlockException; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Slf4j @Component public class ResourceBlockHandler { public static String call(BlockException ex){ log.error("block exception {}", ex.getMessage()); return "访问太频繁了,稍等片刻再访问"; } }
第二步:修改@SentinelResource注解中的属性定义,例如:
@SentinelResource(value="doGetResource", blockHandlerClass = ResourceBlockHandler.class, blockHandler = "call") public String doGetResource(){ return "do get resource"; }
第三步:在controller方法中,调用@Sentinel注解描述的方法,例如:
@GetMapping("/sentinel03") public String doSentinel03(){ return resourceService.doGetResource(); //return "sentinel 03 test"; }Sentinel降级应用实践
//AtomicLong 类支持线程安全的自增自减 *** 作 private AtomicLong atomicLong=new AtomicLong(1); @GetMapping("/sentinel04") public String doSentinel04() throws InterruptedException { //获取自增对象的值,然后再加1 long num=atomicLong.getAndIncrement(); if(num%2==0){//模拟50%的慢调用比例 Thread.sleep(200); } return "sentinel 04 test"; }
熔断策略选择"慢调用比例",表示请求数超过3时,假如平均响应时间超过200毫秒的有30%,则对请求进行熔断,熔断时长为10秒钟,10秒以后恢复正常。
第三步:对指定链路进行刷新,多次访问测试,检测页面上是否会出现 Blocked By Sentinel (flow Limiting)内容.
我们也可以进行断点调试,在DefaultBlockExceptionHandler中的handle方法内部加断点,分析异常类型,假如异常类型DegradeException则为降级熔断。
Sentinel热点规则分析(重点)热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
快速入门第一步:在sca-provider中添加如下方法,例如:
@GetMapping("/sentinel/findById") @SentinelResource("resource") public String doFindById(@RequestParam("id") Integer id){ return "resource id is "+id; }
系统规则是一种全局设计规则,其中,
Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
CPU使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
说明,系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)