范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Sentinel熔断降级与系统自适应限流

  熔断降级
  限流需要我们根据不同的硬件条件做好压测,压测出一个接口或者一个服务在某种硬件配置下最大能承受的 QPS,根据这个结果配置限流规则,并且在后期需求的不断叠加,也需要对接口重新做压测,或者根据线上的实际表现不断调整限流的阈值。因此,限流可能很少使用,或者限流的阈值都会配置的比压测结果略大,这时就需要结合熔断降级做兜底。
  Sentinel 支持对同一个资源配置多个相同类型或不同类型的规则,在配置了限流规则的基础上,我们还可以为同一资源配置熔断降级规则。当接口的 QPS 未达限流阈值却已经有很多请求超时的情况下,就可能达到熔断降级规则的阈值从而触发熔断,这就能很好地保护服务自身。  熔断规则可配置的属性
  DegradeRule 规则类声明的字段如下:  public class DegradeRule extends AbstractRule {     // 可配置字段     private double count;     private int timeWindow;     private int grade = RuleConstant.DEGRADE_GRADE_RT;     private int rtSlowRequestAmount = RuleConstant.DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT;     private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;     // 非配置字段     private AtomicLong passCount = new AtomicLong(0);     private final AtomicBoolean cut = new AtomicBoolean(false); }  count:限流阈值。  timeWindow:重置熔断的窗口时间,默认值 0。  grade:降级策略,支持 DEGRADE_GRADE_RT(按平均响应耗时)、DEGRADE_GRADE_EXCEPTION_RATIO(按失败比率)和 DEGRADE_GRADE_EXCEPTION_COUNT(失败次数)三种熔断降级策略。  rtSlowRequestAmount:当 grade 配置为 DEGRADE_GRADE_RT 时,该值表示可触发熔断的超过阈值的慢请求数量。如果该值配置为 5,阈值为 100 毫秒,当连续 5 个请求计算平均耗时都超过 100 毫秒时,后面的请求才会被熔断,下个时间窗口修复。  minRequestAmount:当 grade 配置为 DEGRADE_GRADE_EXCEPTION_RATIO 时,该值表示可触发熔断的最小请求数,假设阈值配置为 10,第一个请求就失败的情况下,失败率为 100%,minRequestAmount 就是避免出现这种情况的。  passCount:只在 grade 为 DEGRADE_GRADE_RT 时使用,累加慢请求数,该值由一个定时任务重置,周期为 timeWindow(窗口时间大小)。  cut:记录当前是否已经触发熔断,当 passCount 的值大于等待 rtSlowRequestAmount 时被设置为 true,由定时任务在 timeWindow 之后重置为 false。  熔断降级判断流程
  DegradeSlot 是实现熔断降级的切入点,它作为 ProcessorSlot 插入到 ProcessorSlotChain 链表中,在 entry 方法中调用 Checker 去判断是否熔断当前请求,如果熔断则抛出 Block 异常。
  Checker 并不是一个接口,而是一种检测行为,限流的 ckeck 由 FlowRuleChecker 实现,而熔断的 check 行为则由 DegradeRuleManager 负责,真正 check 逻辑判断由 DegradeRule 实现,流程如下图所示。
  当 DegradeSlot#entry 方法被调用时,由 DegradeSlot 调用 DegradeRuleManager#checkDegrade 方法检查当前请求是否满足某个熔断降级规则。熔断规则配置由 DegradeRuleManager 加载,所以 DegradeSlot 将 check 逻辑交给 DegradeRuleManager 去完成,checkDegrade 方法的源码如下:  public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)         throws BlockException {         // 因为我们可以对同一个资源配置多个熔断降级规则,所以返回的将是一个集合。         Set rules = degradeRules.get(resource.getName());         if (rules == null) {             return;         }         for (DegradeRule rule : rules) {             if (!rule.passCheck(context, node, count)) {                 throw new DegradeException(rule.getLimitApp(), rule);             }         } }
  DegradeRuleManager 首先根据资源名称获取配置的熔断降级规则,然后遍历熔断降级规则,调用 DegradeRule#passCheck 方法将检查是否需要触发熔断的逻辑交给 DegradeRule 完成。如果对一个资源配置多个熔断降级规则,那么只要有一个熔断降级规则满足条件,就会触发熔断。
  DegradeRule#passCheck 方法源码如下:     @Override     public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {         if (cut.get()) {             return false;         }         // (1)         ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(this.getResource());         if (clusterNode == null) {             return true;         }         // (2)         if (grade == RuleConstant.DEGRADE_GRADE_RT) {             double rt = clusterNode.avgRt();             if (rt < this.count) {                 passCount.set(0);                 return true;             }             if (passCount.incrementAndGet() < rtSlowRequestAmount) {                 return true;             }         }          // (3)         else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {             double exception = clusterNode.exceptionQps();             double success = clusterNode.successQps();             double total = clusterNode.totalQps();             if (total < minRequestAmount) {                 return true;             }             double realSuccess = success - exception;             if (realSuccess <= 0 && exception < minRequestAmount) {                 return true;             }             if (exception / success < count) {                 return true;             }         }          // (4)         else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {             double exception = clusterNode.totalException();             if (exception < count) {                 return true;             }         }         // (5)         if (cut.compareAndSet(false, true)) {             ResetTask resetTask = new ResetTask(this);             pool.schedule(resetTask, timeWindow, TimeUnit.SECONDS);         }         // 熔断         return false;     }  根据资源名称获取该资源全局的指标数据统计 ClusterNode。  如果熔断降级策略为 DEGRADE_GRADE_RT,从 ClusterNode 读取当前平均耗时,如果平均耗时超过限流的阈值,并且超过阈值的慢请求数大于 rtSlowRequestAmount,则跳转到(5);否则如果平均耗时下降小于阈值,将计数器 passCount 重置为 0。  如果熔断降级策略为 DEGRADE_GRADE_EXCEPTION_RATIO,读取当前时间窗口(1 秒)的异常总数、成功总数、总 QPS,判断异常总数与成功总数的比值是否小于规则设置的阈值,小于才能通过。失败率大于等于阈值且当前总的 QPS 大于 minRequestAmount,则跳转到(5)。  如果熔断降级策略为 DEGRADE_GRADE_EXCEPTION_COUNT,读取当前滑动窗口(1 分钟)的异常总数,如果异常总数大于规则配置的阈值,则跳转到(5),否则请求通过。  记录当前已经触发熔断,后续请求不需要重复判断。并且开启定时任务用于重置熔断标志,休眠 timeWindow 时长后重置熔断标志;当 timeWindow 不配置或者配置为 0 时,cut 被立即重置,也就是不保存熔断判断的结果,每个请求都需要重新判断一次。
  官方文档在介绍 DEGRADE_GRADE_EXCEPTION_COUNT 策略的地方加了使用注意说明,内容为:
  注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。
  这句话并不难理解,因为调用 ClusterNode#totalException 方法获取的是一分钟内的总异常数。StatisticNode 的 totalException 源码如下: // 数组大小为 60,窗口时间长度为 1000 毫秒 private transient Metric rollingCounterInMinute = new ArrayMetric(60, 60 * 1000, false);  @Override public long totalException() {     // 获取 1 分钟的总异常数     return rollingCounterInMinute.exception(); }
  也因如此,DEGRADE_GRADE_EXCEPTION_COUNT 这个熔断降级策略似乎使用场景不多,笔者也未曾使用过。
  timeWindow、passCount、cut 是作者出于性能考虑而添加的,在配置熔断规则时,建议不要将 timeWindow 配置为 0 或者小于 0,可将 timeWindow 配置为 1000 毫秒,一个窗口时间长度,能减少一点计算就能降低一点 Sentinel 对性能的影响。 系统自适应限流
  系统自适应限流就是在系统负载过高的情况下,自动切断后续请求,以保证服务的稳定运行。系统自适应限流也属于熔断降级的一种实现,而非限流降级,它与熔断降级都有一个共性,在保证服务稳定运行的情况下尽最大可能处理更多请求,一旦系统负载达到阈值就熔断请求。
  SystemSlot 是实现系统自适应限流的切入点。DegradeSlot 在 ProcessorSlotChain 链表中被放在 FlowSlot 的后面,作为限流的兜底解决方案,而 SystemSlot 在 ProcessorSlotChain 链表中被放在 FlowSlot 的前面,强制优先考虑系统目前的情况能否处理当前请求,让系统尽可能跑在最大吞吐量的同时保证系统的稳定性。 系统自适应限流规则配置
  系统自适应限流规则针对所有流量类型为 IN 的资源生效,因此不需要配置规则的资源名称。SystemRule 定义的字段如下: public class SystemRule extends AbstractRule {     private double highestSystemLoad = -1;     private double highestCpuUsage = -1;     private double qps = -1;     private long avgRt = -1;     private long maxThread = -1; }  qps:按 QPS 限流的阈值,默认 -1,大于 0 才生效。 avgRt:按平均耗时的限流阈值,默认 -1,大于 0 才生效。 maxThread:最大并行占用的线程数阈值,默认 -1,大于 0 才生效。 highestCpuUsage:按 CPU 使用率限流的阈值,取值[0,1]之间,默认 -1,大于等于 0.0 才生效。 highestSystemLoad:按系统负载限流的阈值,默认 -1,大于 0.0 才生效。
  如果配置了多个 SystemRule,则每个配置项只取最小值。例如三个 SystemRule 都配置了 qps,则取这三个规则中最小的 qps 作为限流阈值,这在调用 SystemRuleManager#loadRules 方法加载规则时完成。    public static void loadSystemConf(SystemRule rule) {         // 是否开启系统自适应限流判断功能         boolean checkStatus = false;         // highestSystemLoad         if (rule.getHighestSystemLoad() >= 0) {             // 多个规则都配置则取最小值             highestSystemLoad = Math.min(highestSystemLoad, rule.getHighestSystemLoad());             highestSystemLoadIsSet = true;             // 开启系统自适应限流检查功能             checkStatus = true;         }         // highestCpuUsage         if (rule.getHighestCpuUsage() >= 0) {             if (rule.getHighestCpuUsage() > 1) {}             // [0,1)             else {                 // 多个规则都配置则取最小值                 highestCpuUsage = Math.min(highestCpuUsage, rule.getHighestCpuUsage());                 highestCpuUsageIsSet = true;                 checkStatus = true;             }         }         // avgRt         if (rule.getAvgRt() >= 0) {             // 多个规则都配置则取最小值             maxRt = Math.min(maxRt, rule.getAvgRt());             maxRtIsSet = true;             checkStatus = true;         }         // maxThread         if (rule.getMaxThread() >= 0) {             // 多个规则都配置则取最小值             maxThread = Math.min(maxThread, rule.getMaxThread());             maxThreadIsSet = true;             checkStatus = true;         }         // qps         if (rule.getQps() >= 0) {             // 多个规则都配置则取最小值             qps = Math.min(qps, rule.getQps());             qpsIsSet = true;             checkStatus = true;         }         checkSystemStatus.set(checkStatus);     }  系统自适应限流判断流程
  当 SystemSlot#entry 方法被调用时,由 SystemSlot 调用 SystemRuleManager#checkSystem 方法判断是否需要限流,流程如下图所示:
  SystemRuleManager#checkSystem 方法从全局的资源指标数据统计节点 Constans.ENTRY_NODE 读取当前时间窗口的指标数据,判断总的 QPS、平均耗时这些指标数据是否达到阈值,或者总占用的线程数是否达到阈值,如果达到阈值则抛出 Block 异常(SystemBlockException)。除此之外,checkSystem 方法还实现了根据系统当前 Load 和 CPU 使用率限流。
  SystemRuleManager#checkSystem 方法源码如下: public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {         if (resourceWrapper == null) {             return;         }         // 如果有配置 SystemRule,则 checkSystemStatus 为 true         if (!checkSystemStatus.get()) {             return;         }         // 只限流类型为 IN 的流量         if (resourceWrapper.getEntryType() != EntryType.IN) {             return;         }         // qps 限流         double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();         if (currentQps > qps) {             throw new SystemBlockException(resourceWrapper.getName(), "qps");         }         // 占用线程数限流         int currentThread = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.curThreadNum();         if (currentThread > maxThread) {             throw new SystemBlockException(resourceWrapper.getName(), "thread");         }         // 平均耗时限流         double rt = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.avgRt();         if (rt > maxRt) {             throw new SystemBlockException(resourceWrapper.getName(), "rt");         }         // 系统平均负载限流         if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {             if (!checkBbr(currentThread)) {                 throw new SystemBlockException(resourceWrapper.getName(), "load");             }         }         // cpu 使用率限流         if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {             throw new SystemBlockException(resourceWrapper.getName(), "cpu");         } }  Constans.ENTRY_NODE:统计所有流量类型为 IN 的指标数据、总的并行占用线程数。 SystemStatusListener#run 方法被定时调用,负责获取系统的平均负载和 CPU 使用率。 当系统负载大于限流的负载阈值时,使用 BBR 算法判断是否需要限流。 获取系统负载和 CPU 使用率
  使用 TOP 命令可查看系统的平均负载(Load)和 CPU 使用率,如下图所示:
  Load Avg:三个浮点数,分别代表 1 分钟、5 分钟、15 分钟内系统的平均负载。 CPU:usage 为 CPU 总的使用率,user 为用户线程的 CPU 使用率,sys 为系统线程的 CPU 使用率。
  Sentinel 通过定时任务每秒钟使用 OperatingSystemMXBean API 获取这两个指标数据的值,代码如下: @Override     public void run() {         try {             OperatingSystemMXBean osBean = ManagementFactory                                        .getPlatformMXBean(OperatingSystemMXBean.class);             // getSystemLoadAverage             currentLoad = osBean.getSystemLoadAverage();             // getSystemCpuLoad             currentCpuUsage = osBean.getSystemCpuLoad();             if (currentLoad > SystemRuleManager.getSystemLoadThreshold()) {                 writeSystemStatusLog();             }         } catch (Throwable e) {             RecordLog.warn("[SystemStatusListener] Failed to get system metrics from JMX", e);         }     }  getSystemLoadAverage:获取最近 1 分钟系统的平均负载。 getSystemCpuLoad:返回整个系统的最近 CPU 使用率。此值是 [0.0,1.0] 间隔中的双精度值。值为 0.0 表示在最近观察的时间段内,所有 CPU 都处于空闲状态,而值为 1.0 意味着在最近一段时间内,所有 CPU 都处于 100%活动状态。如果系统最近的 CPU 使用率不可用,则该方法返回负值。 checkBbrprivate static boolean checkBbr(int currentThread) {         if (currentThread > 1 &&             currentThread >              Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000) {             return false;         }         return true; }  Constants.ENTRY_NODE.maxSuccessQps:从秒级滑动窗口中获取最大请求成功总数。 Constants.ENTRY_NODE.minRt:当前时间窗口的最小请求处理耗时。
  假设某接口的最大 QPS 为 800,处理一次请求的最小耗时为 5ms,那么至少需要并行的线程数与 Min RT 和 Max QPS 的关系为:
  Max QPS = Threads * (1000/Min Rt)
  推出:
  Threads = Max QPS/(1000/Min Rt) = Max QPS * Min Rt/1000
  替换 Min Rt 为 5ms、Max QPS 为 800,计算结果:
  Threads = 800 * 5/1000 = 4
  所以,checkBbr 方法中,(minRt/1000) 是将最小耗时的单位由毫秒转为秒,表示系统处理最多请求时的最小耗时,maxSuccessQps * (minRt/1000) 表示至少需要每秒多少个线程并行才能达到 maxSuccessQps。在系统负载比较高的情况下,只要并行占用的线程数超过该值就限流。但如果 Load 高不是由当前进程引起的,checkBbr 的效果就不明显。

万物复苏春来到花开中国遍地香央视网消息立春之后,万物复苏的春天来到。下面让我们向暖而行,感受春的气息,领略花开中国。眼下,海南各地的三角梅,花开正艳,一团团一簇簇竞相绽放。三角梅是海南省的省花,在海南各地都很这个新发现,距今2。508亿年!记者从中国地质大学(武汉)获悉,该校宋海军教授团队在我国贵州省贵阳市及其周边发现一个距今2。508亿年的特异埋藏化石库贵阳生物群。相关研究成果10日发表在科学杂志上。宋海军介绍,贵延迟发布?苹果新StudioDisplay将缺席春季发布会CNMO新闻去年苹果春季发布会上发布了旗下最新显示器产品StudioDisplay系列,尽管在之后并未在市场上掀起换机潮,但后续产品的开发似乎已经从那时开始了。根据当时的消息这将是农旅融合引客来来源丽水日报初春,庆元县隆宫乡莲湖星空营地游人如织,众多游客到此感受春日暖阳。该营地是集露营基地观光旅游餐饮住宿等农文旅为一体的综合体项目,是该乡全力打造的首个农旅融合式共富工坊,扬州泰州盐城四日游之高邮篇这次驾车出行,本想专门看看泰州,因为一直有个走遍江苏13市的想法,眼下去了9个,若无疫情阻隔,应该早已如愿路上孩子说,新建了个大运河博物馆,要不咱先去扬州?那好吧。一路狂奔,看到高开门,迎春!蓄势3年,一朝开放。出境游重启,为旅游行业复苏按下快进键。联合国世界旅游组织(UNWTO)最新发布的2023年全球旅游业晴雨表预测,2023年全球国际游客抵达人数可能恢复到疫情前水116家非上市险企高管薪酬,最高近千万,多数低于三百万澎湃新闻记者胡志挺偿二代二期实施后,非上市保险公司董监高收入首次披露,哪些险企高管薪酬较高呢?据澎湃新闻不完全统计,截至目前,有约145家非上市保险公司在中国保险行业协会网站披露了世体除了布斯克茨以外,沙特还梦想着梅西的到来直播吧2月7日讯据世界体育报报道,近日,C罗效力的利雅得胜利向巴萨中场布斯克茨发出了邀请,除此以外,沙特方面还梦想着梅西的到来。卡塔尔成功举办了阿拉伯地区的首届足球世界杯,现在,沙吴易昺ATP排名首次进入前100这只是一个开始北京时间2月7日,在张之臻成为百大球员不到4个月后,吴易昺也跟随脚步,在本周首次打进世界排名前一百,位列No。97位。这是我从小就想要实现的目标。吴易昺在接受ATP官网采访时说,当火箭与76人3换2交易报价!据费城76人队记者KeithPompey报道,消息人士透露,76人后卫科克马兹不满自己在球队扮演的角色,已经向球队提出交易申请,希望在本赛季交易截止日前离开球队。科克马兹是2026格莱美红毯霉霉碧昂丝阿黛尔都钟情的珠宝,究竟有什么魅力一等到格莱美要颁奖,我就知道养眼时刻又来了!这不,美女帅哥齐聚一堂,眼睛都不知道该看谁了惊喜我最喜欢的,还是泰勒斯威夫特的造型。靛青色露腰短上衣,更显腿长比例好。小烟熏眼妆,加上红
唐山,你不能再沉默唐山打人事件的完整视频,相信大家都已经看过,其实早就想说点什么,但是又不知道说什么,无奈惋惜痛惜压抑了很久,仔细想想,充满了疑虑和期望。一疑,施暴者究竟是谁?背景有多么的强大?尽管唐山打人案背后的保护伞在哪唐山打人案已经过去5天,热度一直不减,经过自媒体的多轮解读,主犯陈继志的前世今生终于浮出水面。陈继志第一次出现在社会公众视野中是在2018年的房屋因借款纠纷被拍卖。我们陆续地看到他岛内停电已成家常便饭,民众批当局不顾民生华夏经纬网6月14日讯据香港大公报报道,对于岛内频频发生停电事件,家住台湾高雄中华路的市民侯先生向大公报表示,13日下午三点多家里突然停电,没有冷气吹还算是小事,万幸当时家人没有困唐山打人事件6天后,受伤女子转入普通病房距离唐山打人事件,已经过去6天。事件持续发酵,除了案件的审查进展,两名被送往医院救治的女生的健康状况,也备受网友关注。这次事件以后,关于施暴者的消息同伙的情况烧烤店老板的情况,都有真相来了?巷子里发生了什么,主犯妻子变脸,唐山公安雷厉风行唐山打人事件发酵到现在,热度持续不减,但似乎已经有人开始主动降温,既有暴徒一方的洗白,似乎也有正义一方的借壳发声,暴徒肯定是为了尽可能博同情减轻自己的罪孽,但受害人母亲和当晚见证者暴雨后,如何做好个人防护?温馨提示近日,一场暴雨突袭我们的城市,目前汛情已得到控制,城市也正在慢慢恢复成往日的生活秩序。但暴雨后,我们更要注意个人防护,谨防病疫传染。因此,我们整理了一篇温馨小贴士,与我们的千呼万唤始出来甚至是迟到20年的正义多少有点不正义的感觉头号周刊这几日,唐山烧烤店打人事件发生后,群情激奋,要求严惩凶手的声音连绵不绝。在公安部河北省公安厅统一部署和河北江苏警方合作下,9名涉案人员于6月11日被廊坊市公安局广阳分局全部14K话事人为唐山打人事件发声,谴责打人凶手,呼吁洪门坚持正义唐山烧烤店打人事件经过网络的发酵引发了全社会的关注,打人者手段之残忍,场面之惨烈,伤势之严重,简直令人发指,就算隔着屏幕都能感到心惊肉颤。一时间,下至普通百姓上至社会名流纷纷声援受我,留守儿童,15岁被父母带去国外打工,靠自学英语,30岁当白领这是自拍第302个真实故事如果你有故事,请私信我豆豆口述肖雁回撰文祖一飞编辑我叫豆豆(自学英语的豆豆),1991年出生在浙江的一座小城。我们那里是全国有名的侨乡,而我是侨乡典型的留2022中考安徽中考首日考生觉得不太难作文要抓住两个关键词新安晚报安徽网大皖新闻讯6月14日下午,安徽省2022年中考首日考试结束。从走出考生的面容中可以看出,今年的中考试卷不难,在绝大多数考生的心理承受范围内。尤其是作文这三年来离我最近薪火相传陶仪声当选致公党安徽省委会新一届主委(附班子成员介绍)大会现场6月10日至12日,中国致公党安徽省第七次代表大会在合肥召开。全国政协副主席致公党中央主席中国科协主席万钢代表致公党中央以视频方式致贺词。中共安徽省委常委统战部部长张西明代