前言
我为什么写这篇文章,是因为Sentinel实在是太强大太好用了,再加上阿里开源,Sentinel的发展迅猛。已有多家公司生产使用,但但凡神功,一个不慎,就有可能走火入魔,轻则离职走人,重则走火入魔踏上跑路生涯。本文本着你对官方秘籍已经通篇阅读无一不懂的前提,来此避坑,如无上述经历,请即刻返程回读。
限流篇
为什么要使用Sentinel?
我们为什么要搞限流,限流的作用是什么在此不做赘述,但是在做限流前我们需要思考一个问题,为什么要用Sentinel,达到什么样的流量需要采用限流,什么样的应用适合Sentinel。
新的中间件的应用,尤其是这种作用在应用层的我们一定要考虑的一个问题就是能效的提升会是多少,这种提升的正面例子就是你的应用的稳定性,负面例子自然是所带来的额外开销,响应时间,维护成本等。
很欣慰的是Sentinel本身的设计还是很OK的,性能上的影响微乎其微,具体请参加官方wiki。
Sentinel的很多设计很多算法都是源于Guava,感兴趣的同学可以试着去了解一下。
令牌桶,漏桶算法,是限流界的经典理论支柱,无论是Hystrix还是Sentinel都是在其基础上做的变化,所谓一法通,万法通,便是其理。
一般来讲,当你的应用没有复杂到一定程度的时候,我并不建议你入坑,假如你只是想吃米饭,但是来了一大堆食物,于你而言就是食之无味,弃之可惜。(此处对于其他中间件一样适用)如果限流是必要的,但是应用并没有庞大到一定地步,那么我建议你单独使用限流,利用已有的比如RateLimit来实现你的限流,(比如京东的部分应用是采用该方式来进行的)。一般来讲,底层应用只需要限流就OK了,如果说你的应用限流这快业务需求需要更灵活的,比如预热,或者基于调用关系等更复杂更多样的,那么没错,sentinel就是你的最佳选择。
单机限流VS集群限流
如果你的应用属于分布式应用,那么我并不推荐你使用单机限流,单机限流可以作为备选方案,而我们优先考虑的一定是集群限流,虽然集群限流的引入会导致你的应用复杂度又上升了一个级别。
我们需要明白一点,你的单机流量是你负载均衡的一个选择结果,而你的负载均衡并不一定能够保证流量按照你设定的理想状态(这是负载均衡的作用,所以我们没办法破坏,负载均衡不同的策略导致不同的流量分配结果,受多方面影响,我司这边采用的是最小活跃数。最小活跃数的选择与系统的整个负载有关,某一个接口占用过多资源,亦会导致其他接口出现连锁反应,所以流量波动较大),所以很有可能出现某台机器流量超标,某台机器流量相对较少,比如10000个请求,负载均衡的选择结果,A接受了6000个,B接受了4000个,而AB的单机限流均为5000,那么理想状态下这10000个请求会被全部接受,但实际情况是只接受了9000,那么采用集群限流则不会出现这样的情况。
降级熔断篇
降级熔断也是Sentinel的一个很优秀的功能,用处不做赘述。
熔断这块Sentinel提供了三种方式,平均响应时间,平均失败率,异常数目。统计方式这块是用滑动窗口来设计的。达到熔断条件,Sleep。目前最新的版本支持自定义统计窗口。 此处的话时间窗口会有个默认值,5,即单位窗口内,达到熔断条件的时候并不会立即熔断,而是处于熔断就绪的状态,具体熔断与否取决于这五个请求,详细自行观看源码。
再次说个题外话,我们需要明白一点,一旦采用平均值或者什么率这块我们就需要明白一点,容易发生平均值效应。假设我们采用了平均响应时间,你前一百次的平均值都为100,但是后面系统出现问题,相应时间这块为100000,但是sentinel这块的话记作5000(注:基于RT的话当系统相应时间超过5000时会直接认为超时记录为5000),平均值下来亦然达不到熔断条件。也就是说当你的系统已经处于不正常的状态的时候并不能第一时间进行降级。
基于异常比例亦然,只是说当你的流量数过多的时候才会呈现出较好的表现。假设你前6个流量都是异常(可能是预热或其他并非不正常的行为导致的异常),那么系统会直接进入降级。过早地夭折。
平均值受最大值影响,比率受初始分子分母的影响。 基于此 ,希望各位选用自己合适的方式来讲行熔断选择。
尾篇 熔断设计思考题外话
Hystrix这块当进行熔断时,会清空统计数据,也就是说,熔断关闭后,系统会认为是一个全新的统计开始,之前的数据都会被剔除,Sentinel这块的设计由于要考虑整个系统的数据的准确性(数据源会被多方使用),并未做数据剔除,也就是说,如果熔断时间过短,当熔断关闭后仍位于同一个时间窗口的时候,此时会再次进入熔断开启状态(因为统计数据的采集仍是沿用熔断前的统计数据)。解决的话目前我所建议的方式是熔断这块的数据统计单独记录,(不能影响其他数据的准确性)这个也是Sentinel的官方维护者乐有的建议。
熔断这块没有一个熔断半开的状态,有时候我们的系统确实被搞垮了,熔断时间过后,仍然没有恢复正常,这个时候我们最好的做法是放一个流量过去,而不是大多数流量,这个流量的成功与否决定着我们的系统是否恢复到熔断关闭的状态。
限流熔断可以考虑是否引入其他因素来进行衡量,比如系统的负载等等。另外一点,当达到熔断的时候我们是应该直接熔断还是说进行一个流量的限制,是进行平缓的降级还是说粗暴的降级。
主动降级:
熔断与降级结果是一样的,但是目的不一样,一个属于主动,一个属于被动。被熔断后采用备用方案属于业务方的补偿机制。这个不能称之为降级,降级应该是说当我有预感会有较大的流量的还好,我的负载比较高,那么我会梳理依赖关系,关闭一些次要服务,让出资源来给核心服务用。而且Sentinel这里的话也完全可以把降级给做出来,用户可以主动的在控制台做降级操作,自定义时间窗口大小。比如说大促期间,会关闭一些非核心的业务,这块尽可能把资源让给核心业务。
目前Sentinel尚有许多需要修改更正的,大家可以踊跃参与。
尾篇:限流熔断思考
限流
负载均衡保证了保证集群劳作下的均衡分工,不会出现累得累死,闲的闲死的情况,集群容错则保证了当我们部分机器比如A犯错回家反思的情况下其他机器可以迅速完成指派给A的任务,而不至于让业务方成为下一个望夫石,至于限流,则是我们广大劳动人民一直追求的朝九晚六不加班,他保证了我们的机器不会超负荷工作导致宕机。 许多刚入职场的同学不明白为什么要限流,限流后部分用户不是提供不了服务了嘛?这个问题很简单,人心不足蛇吞象,如是也。
熔断
底层服务出现问题时:错误数过多/平均响应时间变长,上层应用怎么做?底层应用又该怎么做。 底层应用限流是必须的。熔断的具体情况需要具体分析, 代码错误导致系统资源应用不合理,比如特殊情况大对象的使用,数据库出现慢查询、索引未命中。这些情况出现导致系统的正常负载出现问题。限流可能已经解决不了问题了。
另外熔断的话这里最好业务方这里做一下相关处理。核心业务,业务方应当做好熔断/降级之后的一个备用方案。
禁用服务
禁用 --> 导致的问题不一样,还是业务owner最清楚,根据不同的问题,处理手段也不一样。 非核心业务如果影响面可控也是可以采用直接下线服务的方式,这样做的好处是不会再让业务方苦苦等待,浪费有限的资源去等一个没有结果的响应。
扩容
扩容 --> 要速度,需要自身运维系统支持,能暂时解决问题。 扩容的主要依据,系统资源利用率飙升,内存使用爆表,频繁GC。导致原因可能是流量过高,或者代码不当这个时候应用服务器扩容可以暂时解决问题。注:频繁fullGc也可以进行优化,如果代码正确的情况下,这个时候就需要做jvm参数优化了 慢sql-> 数据库服务器。应用sql语句优化、复杂表查询改宽表。加缓存等等。
放任
放任不管(等修复) --> 影响范围能接受(禁用可能会有额外的风险情况)