自适应熔断限流揭秘
原创 Chasen 拍码场
前言
自适应熔断与限流是在分布式系统中常用的机制,用于保护系统免受服务雪崩效应与突发流量影响。它能够根据系统的负载情况和性能指标自动调整限流策略,以确保系统能提供稳定可靠的服务,目前在业内已经有了不少的探索与实践。
熔断限流使用场景
限流
限流主要的应用场景为应对流量激增的场景(如活动促销,外部流量攻击等)。如下图,当系统流量激增时,如不加以限制,可能会导致系统负载被打满,致使服务崩溃,最终导致服务不可用。
通过限流,仅允许部分流量的请求可以通过,其余请求会直接快速失败,即便突发流量出现时,服务始终仅承载部分请求,系统负载可控,保证了服务能稳定可用。
熔断
熔断主要的应用场景为依赖的服务出现故障时防止出现服务雪崩(如下游超时,db故障等)。如下图,当下游服务故障导致超时,由于长时间不响应会导致上游服务请求产生阻塞,导致系统资源增加(常见的如tomcat线程池、连接池等),如持续故障,则请求阻塞会持续增加导致上游系统线程池资源耗尽,导致上游服务不可用,并且会向上产生级联故障,最终因底层服务的故障导致整个链路的服务雪崩。
通过熔断可以在下游发生故障之后,针对下游的调用进行快速失败,这样就避免了系统资源因下游故障而耗尽,使系统保持可用,同时熔断后也会定期进行下游探测,当下游恢复后,会退出熔断,自动恢复下游调用。
传统熔断限流存在的问题
传统熔断限流主要是客户端模式如hystrix, sentinel静态流控功能,存在着一些弊端:
配置滞后,人工评估易存在疏漏;通常都是系统出现故障后,才进行介入,实际可能已经对业务产生了不好的影响。
阈值难以设定,配置成本高;通常阈值的确定需要结合生产压测的实施才能准确设定,但实际在生产进行压测的成本很高,并且规则中变量众多,有一定的上手门槛。
阈值设置存在过时的问题;由于系统是在不断的迭代中的,因此阈值也可能随着版本的迭代而逐渐不适用,从而使系统失去了保护。
跨语言支持不佳;已有的组件仅对java生态支持较好,但对于python,go等语言生态的支持有限。
信也自适应熔断限流的优势
可作为兜底策略;自适应策略有较高的启发值,因此可作为兜底策略提前配置开启。
使用门槛低;采用的是自适应的策略,无复杂的配置项,不需要进行压测,仅需选择开启与关闭即可,且策略主要根据系统的负载情况进行决策,随着版本迭代,也不会失效。
0成本接入,支持跨语言;采用mesh的方式实现,具体的限流与熔断介入是在边车上进行的,因此应用无需客户端接入,能应用在各种语言生态的系统上。
自适应熔断限流策略
自适应限流
策略核心逻辑:资源水位线自适应,通过当前CPU与目标值的误差调整QPS,使CPU趋近于目标值。
核心算法:PID算法
业内实践:淘宝noah、蚂蚁mosn等
算法概述:PID算法利用反馈来检测偏差信号,并通过偏差信号来控制被控量。而控制器本身就是比例、积分、微分三个环节的加和。使用广泛,在四轴飞行器,平衡小车、汽车定速巡航、温度控制器等场景均有应用。算法明细见下图,其中Kp:比例增益,用于控制调节幅度;Ki:积分时间常数,用于补偿误差;Kd:微分时间常数,用于抑制波动;e(t):cpu与基准线的误差;u(t):调整的qps;其中基准线取的是80%。
自适应熔断
策略核心逻辑:通过计算实际被下游拒绝的概率来控制请求是否熔断
核心算法:SRE算法
业内实践:B站kratos、go-zero、小米、QQ音乐微服务等
算法概述:SRE算法是Google提出的一种弹性熔断算法,称之为Handing Overload,不同于传统熔断算法,SRE算法没有半开的状态,也没有完全开启的状态,通过计算下游服务的拒绝率来控制流量的发送,在保护自身不被下游拖垮的同时,尽可能释放请求到下游,最大化保证业务的完整性。算法明细见下图,其中requests: 一个时间窗口的请求总量;Accepts: 成功请求数量;K: 倍率,K 越小表示越激进,越小表示越容易被丢弃请求,K建议区间[1.5, 2]。
自适应熔断限流整体方案
指标采集与转储;首先利用otel进行熔断限流指标的采集,采集过程中otel会定期通过自适应熔断限流平台进行节点发现,只有开启了熔断限流功能的实例才会进行指标采集。采集到指标会批量推送至kafka中,由数据转储模块进行指标消息消费,并针对监控数据进行预处理后存入redis中。
自适应计算引擎;根据开启的规则进行自适应熔断限流触发的扫描,根据默认的熔断限流自适应策略从redis中获取对应的监控指标进行熔断限流触发判定,判断规则中也针对误触发做了许多的条件限制,比如会过滤掉非流量导致的负载升高场景等。针对触发的规则会生成自适应调节记录,并下发熔点限流指令,同时会周期性的进行自适应策略计算更新熔断限流的阈值,直至满足恢复的条件,满足恢复条件后会下发熔断限流恢复指令进行恢复,触发与恢复都会通过谛听监控平台进行告警通知。
规则转换:规则转换模块会监听下发熔断限流指令来构建EnvoyFilter CRD,将熔断限流指令转换成边车测的流控规则,熔断限流指令转换为EnvoyFilter后会通过mesh的控制面IstioD采用XDS协议下发给边车。
边车:根据下发的流控XDS配置执行入口(限流)或出口(熔断)的流控。
问题与优化
1、XDS下发性能问题
添加EnvoyFilter后触发同namespace下所有Pod的xDS推送,在自适应调节过程会频繁变更EnvoyFilter导致推送频率过高,mesh控制面Istio的负载也会大幅上升,因此针对Istio的源码进行了性能优化,在推送XDS时进行label匹配,仅会对label匹配的实例推送XDS配置。
2、自适应熔断在envoy上实现问题
由于在envoy上实现自适应熔断并无开源经验可借鉴,SRE熔断算法需要类似与基于概率的方式限流,envoy原生并没有概率限流的策略。经过研究与测试,采用超长token投递频率结合限流生效比例的方式模拟出概率限流的效果,经多次压测验证,误差稳定在2%范围内,满足实际熔断要求。
3、API监控指标维度爆炸问题
由于自适应熔断场景对熔断目标的粒度要求高,需要是API维度,由于熔断场景主要针对的是出口调用的场景,且熔断发生时下游并未返回报文,因此无法使用spring ServletRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)来获取接口路径,这种情况下当路径中存在变量时,会出现维度爆炸的问题。因此通过研发模板匹配EnvoyFilter,当接口开启熔断功能时会下发模板匹配EnvoyFilter,当向下游发起调用时会先通过模板匹配EnvoyFilter进行接口匹配,自适应熔断仅会作用在模板匹配通过的接口请求。
此外还做了许多的难点攻克与优化,如算法调优、istio监控指标定制、 envoy精细化限流失准问题和api server性能问题等
自适应熔断限流平台
自适应熔断限流设置
自适应限流设置没有复杂的规则参数设置,仅需选择功能开关的开启或关闭,并且支持实例级别的灰度。
自适应熔断设置支持API维度与站点维度,API与站点列表是根据监控信息自动提取的,且无额外规则参数设置,用户仅需关注开关的开启与关闭。
自适应熔断限流详情与快照
自适应限流记录详情中除了包含触发的基础的站点实例信息外还包含了触发恢复的原因、条件描述,及触发与恢复前后的监控指标快照,通过快照可以方便的进行问题排查与分析。如图上所示,当流量导致CPU飙升后,自适应限流会介入,使CPU负载降低直至趋近于设定的目标水位线,从而保障了服务的可用性。同时由于部分请求快速失败了,导致整体吞吐量实的提升。
自适应熔断记录详情与自适应限流详情类似,也是由基础信息与监控指标快照组成,通过快照可以发现当下游出现大量超时后,自适应熔断开始介入,大部分请求被快速失败,避免了服务被下游拖垮。
但与传统熔断不同的是,自适应熔断始终尽可能的往下游释放请求,当下游超时有所恢复时,流量也能快速实现恢复,在保证自身服务不被下游拖垮的同时,最大化的保证了业务的完整性。
最后
目前我们已经完成了自适应限流与熔断的阶段性落地,完成了部分站点的试点与开启,后续也会进一步的探索,如自适应限流细化到接口层面,仅针对导致负载上升的接口进行自适应限流;进一步细化指标粒度,提升自适应策略触发与恢复的灵敏度等;使服务保障机制向更精准、更高效、更稳定的方向发展。
作者介绍
Chasen,现任基础框架研发专家
- 点赞
- 收藏
- 关注作者
评论(0)