1.启动控制台
下载链接:https://github.com/alibaba/Sentinel/releases
启动控制台
java -jar sentinel-dashboard-1.8.0.jar
2.Sentinel控制台
实时监控
监控接口通过的QPS和拒绝的QPS
注:
QPS(Query Per Second),QPS 其实是衡量吞吐量(Throughput)的一个常用指标,就是说服务器在一秒的时间内处理了多少个请求
TPS(Transaction Per Second) 每秒钟系统能够处理的事务的数量。
QPS(TPS):每秒钟 request/事务 的数量 (此处 / 表示 或的意思)
并发数: 系统同时处理的request/事务数 (此处 / 表示 或的意思)
响应时间: 一般取平均响应时间
QPS(TPS)= 并发数/平均响应时间
簇点链路
用来显示微服务的所监控的API ,可以对一系列的规则进行设置。
流控规则
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。 ==== FlowRule RT(响应时间) 1/0.2s =5
1.Provider 端控制脉冲流量:
通常我们会在服务提供端进行服务流控,因为服务端始终是被别人调用的,那么就需要在被调用端进行流控,流量都会集中在被调用端的服务上面来控制脉冲流量。
2.针对不同来源来进行流控:
比如,小程序,App端,H5端分别调用一个服务。如果小程序进来的流量别较少,那么我们就可以针对App进来的流量进行流控。
流控设置如下:
当1秒访问量超过了3次时:
自定义异常的输出:
@RequestMapping("/flow") @SentinelResource(value = "flow",blockHandler = "flowBlockHandler") public String flow() throws InterruptedException { return "正常访问"; } public String flowBlockHandler(BlockException e){ return "流控"; }
这时QPS>2时:
注意:一旦我们的服务重启之后,我们在控制台配置的信息都会丢失,因为它是存储在内存之中的。这时就需要我们再重启一遍,但是在生产环境中这样的操作是不可行的,这时我们就需要对其持久化。
3.针对并发线程数进行流控
主要是为了防止服务中的线程池出现耗尽的情况,当服务去调用一些慢SQL或者点用第三方服务,出现网络的抖动不稳定迟迟得不到响应的时候,所有的线程都会堆积在服务中从而撑爆我们的线程池拖垮服务。
为了应对这种情况,我们就可以对线程数进行流控,一般我们会对接口做压测,然后再去设置阈值。
public String flowBlockHandler(BlockException e){ return "流控"; } @RequestMapping("/flowThread") @SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler") public String flowThread() throws InterruptedException { TimeUnit.SECONDS.sleep(15); System.out.println("正常访问"); return "正常访问"; }
设置阈值为1:
4.BlockExceptionHandler统一异常处理
SpringWeb MVC 接口资源限流入口在 HandlerInterceptor的实现类AbstractSentinelInterceptor的preHandle方法中,对异常的处理是BlockExceptionHandler的实现类 。
返回的结果比较公共比较统一,就可以使用统一异常处理。如果要针对不同的接口做不同的业务逻辑处理就使用针对性的异常处理。
sentinel 1.7.1 引入了sentinel-spring-webmvc-adapter.jar
public class Result<T> { private Integer code; private String msg; private T data; public Result(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public Result(Integer code, String msg) { this.code = code; this.msg = msg; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public static Result error(Integer code, String msg){ return new Result(code,msg); } }
@Component public class MyBlockExceptionHandler implements BlockExceptionHandler { Logger log= LoggerFactory.getLogger(this.getClass()); @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception { // getRule() 资源 规则的详细信息 log.info("BlockExceptionHandler BlockException================"+e.getRule()); Result r = null; if (e instanceof FlowException) { r = Result.error(100,"接口限流了"); } else if (e instanceof DegradeException) { r = Result.error(101,"服务降级了"); } else if (e instanceof ParamFlowException) { r = Result.error(102,"热点参数限流了"); } else if (e instanceof SystemBlockException) { r = Result.error(103,"触发系统保护规则了"); } else if (e instanceof AuthorityException) { r = Result.error(104,"授权规则不通过"); } //返回json数据 response.setStatus(500); response.setCharacterEncoding("utf-8"); response.setContentType(MediaType.APPLICATION_JSON_VALUE); new ObjectMapper().writeValue(response.getWriter(), r); } }
@RestController @RequestMapping("/order") public class OrderSentinelController { @RequestMapping("/flow") // @SentinelResource(value = "flow",blockHandler = "flowBlockHandler") public String flow() throws InterruptedException { return "正常访问"; } public String flowBlockHandler(BlockException e){ return "流控"; } @RequestMapping("/flowThread") // @SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler") public String flowThread() throws InterruptedException { TimeUnit.SECONDS.sleep(15); System.out.println("正常访问"); return "正常访问"; } @RequestMapping("/add") public String add(){ System.out.println("下单成功!"); return "Hello World"; } }
测试:
流控模式
基于调用关系的流量控制。调用关系包括调用方、被调用方;一个方法可能会调用其它方法,形成一个调用链路的层次关系。
直接
资源达到设定的阈值之后,直接被流控抛出异常。
关联
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说, read_db 和write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategy 为RuleConstant.STRATEGY_RELATE 同时设置 refResource 为 write_db 。这样当写库操作过于频繁时,读数据的请求会被限流。
使用场景:秒杀下单,秒杀的情境下我们需要保证下单(也就是插入的操作),如果查询订单的访问量也比较大的时候。这时候插入和查询就会对数据库同时进行读写的争抢资源从而影响系统的存储量,这时候可以为插入限制流控然后影响查询,这样就能保证正常下单不受影响。查询订单被流控,从而保证整个下单的正常使用。
目标:生成订单量比较大打的话就让查询订单来限流。
生成订单来触发查询订单的限流。
如上设置表示为:一秒中内访问查过了两次的生成订单订单的接口那么查询订单就会限流
使用JMeter让其不断发起http请求(/add),会发现此时被限流了。JMeter停止后,请求查询订单(/add)正常。
链路
根据调用链路入口限流。
下面 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为getUser 的虚拟节点,调用链的入口都是这个虚节点的子节点。
public interface IOrderService { String getUser(); } @Service public class OrderSericeImpl implements IOrderService { @Override @SentinelResource(value="getUser",blockHandler = "blockHandlerGetUser")//把它定义成了sentinel的资源 public String getUser() { return "查询用户"; } public String blockHandlerGetUser(BlockException e) { return "流控用户"; } }
@RestController @RequestMapping("/order") public class OrderSentinelController { @Autowired IOrderService orderService; @RequestMapping("test1") public String test1(){ return orderService.getUser(); } @RequestMapping("test2") public String test2(){ return orderService.getUser(); } }
一棵树如下:
getUser /order /add /test1 /test2 /test3 /test4
上图中来自入口 /order/test1 和 /order/test2 的请求都调用到了资源 getUser ,Sentinel 允许只根据某个入口的统计信息对资源限流。
此时测试会发现链路规则不生效。
注意,高版本此功能直接使用不生效,如何解决?
从1.6.3 版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。
1.7.0 版本开始(对应SCA的2.1.1.RELEASE),官方在CommonFilter 引入了
WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。
SCA 2.1.1.RELEASE之后的版本,可以通过配置spring.cloud.sentinel.web-context-unify=false即可关闭收敛
spring.cloud.sentinel.web‐context‐unify: false
测试,此场景拦截不到BlockException,对应@SentinelResource指定的资源必须在@SentinelResource注解中指定blockHandler处理BlockException
注:
@SentinelResource用于定义资源,并提供可选的异常处理和fallback配置项。其主要参数如下:
流控效果
快速失败
( RuleConstant.CONTROL_BEHAVIOR_DEFAULT )方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException 。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
Warm Up(激增流量)
Warm Up( RuleConstant.CONTROL_BEHAVIOR_WARM_UP )方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
冷加载因子: codeFactor 默认是3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
匀速排队(脉冲流量)
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
表示的意思:在一个巨峰流量之下,设有20个,因为设置的阈值是10,这时候就会接收10个,另外10个不会直接让他失败,让它排队等待接收的10个处理完。如果处理完接收的10个就去处理拒绝的那10个。
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
熔断降级
慢调用比例
慢调用比例 ( SLOW_REQUEST_RATIO ):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。**当单位统计时长( statIntervalMs )内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。**经过熔断时长后熔断器会进入探测恢复状态(HALFOPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
示例:
异常比例
异常比例 ( ERROR_RATIO ):当单位统计时长( statIntervalMs )内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALFOPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0] ,代表 0% 100%。
整合openfeign进行降级
热点参数限流 热点识别流控
热点识别流控何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的数据,并对其访问进行限制。
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
测试代码:
/** * 热点规则,必须使用@SentinelResource * @param id * @return * @throws InterruptedException */ @RequestMapping("/get/{id}") @SentinelResource(value = "getById",blockHandler = "HotBlockHandler") public String getById(@PathVariable("id") Integer id) throws InterruptedException { System.out.println("正常访问"); return "正常访问"; } public String HotBlockHandler(@PathVariable("id") Integer id,BlockException e) throws InterruptedException { return "热点异常处理"; }
单机阈值: 针对所有参数的值进行设置的一个公共的阈值
- 假设当前 参数 大部分的值都是热点流量, 单机阈值就是针对热点流量进行设置, 额外针对普通流量进行参数值流控
- 假设当前 参数 大部分的值都是普通流量, 单机阈值就是针对普通流量进行设置, 额外针对热点流量进行参数值流控
当1秒之内的QPS是10,就限流。并且当针对于参数是1的时候QPS是2就进行限流。
测试:当访问参数是1时,且一秒内访问三次时
系统保护规则
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让
系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
Load 自适应(仅对 Linux/Unixlike 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5 。
https://www.cnblogs.com/gentlemanhai/p/8484839.html
CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.01.0),比较灵敏。
平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。