基于系统负载的动态限流组件 dynamic-limiter

标签: | 发表时间:2018-01-05 19:40 | 作者:
出处:http://mp.weixin.qq.com

 宋鹏玉,2014年加入 Qunar,目前在国内机票报价组,热爱技术,欢迎交流。

背景

一个系统的处理能力是有限的,当请求量超过处理能力时,通常会引起排队,造成响应时间迅速提升。如果对服务占用的资源量没有约束,还可能因为系统资源占用过多而宕机。因此,为了保证系统在遭遇突发流量时,能够正常运行,需要为你的服务加上限流。

通常限流可以分为两类:单机限流、全局限流。常见的单机限流工具有 Guava RateLimiter 和 Java Semaphore,全局限流可以用 Redis 做全局计数器来实现,基础架构组也提供了一个灵活的全局限流组件 common-blocking。这些限流工具有一个共同的缺点:都需要手动设置一个固定的限流阈值。

首先,手动设置固定阈值需要做容量评估,准确的容量评估是比较难的。其次,在每次系统更新升级后,阈值会变得不再准确,需要重新调整,比较繁琐。再次,固定阈值也不能应对服务器性能波动的情况,对于一些日志量比较大的应用,整点日志压缩时,会消耗较多性能,此时系统的处理能力肯定比其他时候要稍差一些。最后,应用大多运行在虚拟机上,同一个实体机上的虚拟机之间也会相互影响,这个体现在监控上就是 CPU 使用率里的 steal 值了。

既然固定阈值有这么多缺点,我们就想有没有什么办法能够自动计算限流阈值呢?下面介绍一下:基于系统负载的动态限流。

动态限流原理

动态限流的目标是,计算一个合理的阈值,让系统在提供最大处理能力的同时,保持健壮,不被压垮。

为什么叫动态限流呢?因为我们希望在系统运行时,限流阈值能够根据实际情况做动态调整。具体根据什么来调整呢?系统负载,这里我们使用了最常见的三种监控指标:CPU 使用率、Load 和服务响应时间。

动态限流的基本思路可以看下面这幅图。系统负载反过来说就是系统健康程度,这里定义了两个负载阈值,假设将 CPU 使用率阈值分别设置成 50 和 70,如果此时系统 CPU 使用率是 60 那么系统就处于不健康状态,CPU 使用率是 80 则系统处于恶化状态。实际中,可以通过配置来指定使用 CPU、Load 和响应时间中的一个或多个来计算系统健康度。使用多个指标时,先分别计算健康度,再取其中健康度最差的一个作为整体的健康度,起到一个多重约束的作用。原理可以参考 “木桶理论”,一个系统的最大处理能力取决于多种资源中的瓶颈。

当系统负载较低,处于健康状态时不限流。当系统负载稍高,处于不健康状态时,以最近几秒处理请求的 QPS 计算限流阈值。当系统负载过高,状态恶化时,让限流阈值以一定的系数进行衰减,直到系统负载降低,系统状态由恶化变为不健康,最终让系统负载收敛在两个负载阈值之间。

前面提到在健康状态下不限流,那么系统在从健康状态变为不健康或恶化状态时,就需要计算一个初始限流阈值,初始限流阈值的计算参考了健康状态的 QPS 和当前处理请求的 QPS。具体的计算公式如下图所示,其中 H 表示健康状态下的 QPS,C 表示当前处理请求的 QPS。

其中的重点是系统状态从健康变成恶化时的阈值计算,限流阈值等于 H 乘以一个系数,这个系数是 C 除以 H 的二分之一次方,也就是流量暴涨倍数的二分之一次方。这样计算的目的,是避免像下图这样的情况,初始阈值设置的不合理时,限流阈值收敛到合理区间太慢,浪费系统资源。

初始阈值设定之后,还需要根据系统负载进行动态调整,如何动态调整呢?可以先看下面这幅阈值调整示意图,相比之前的基本思路图,这里多了一个负载阈值 0,设置它的目的是希望当初始阈值设置不合理导致系统负载变得很低时,能够快速提升阈值。当系统负载接近收敛区间时,进行细微调整,避免步子迈得太大,把系统搞垮了。简单说就是当系统负载低的时候,快速调整,当系统负载高的时候,细微调整。

在实际中,负载阈值 1 和 2 可以灵活配置,为了减少配置工作量,负载阈值 0 固定为负载阈值 1 的 70%。

既然系统状态从健康变成不健康或恶化时,才打开限流,那么反过来系统状态从恶化或不健康恢复成健康时,就需要考虑如何关闭限流。满足哪些条件后不再限流,恢复正常呢?当突发流量消失,系统能够处理全部请求,并且处于健康状态时,不再限流。

到这里动态限流的原理就讲完了,下面我们看一下线上测试效果。

测试效果

最初我们做了基于 Load 的动态限流,服务器 CPU 是 4 核的,所以两个负载阈值分别设置成 3 和 5,限流阈值更新频率为 1 秒一次。

实际效果请看下面的监控图,左边是 10 倍流量压测而未开限流的情况,未开限流时 CPU 使用率高达 99%,Load 也高达 20。中间打开限流之后,Load 降到 5 左右,CPU 使用率也降了下去,但是波动很大,为什么呢?想到之前看过的文章里提到 Load 是 5 秒采样一次,而这里阈值 1 秒更新一次,更新太快了,更新之后还没有体现在 Load 计算上就又更新了。

当我们将阈值更新频率改为 10 秒一次时,从下图可以看出来,CPU 和 Load 的波动小了很多。

看监控我们发现 Load 在 3 到 5 之间波动时,CPU 使用率才 60%,还有提高的空间。我们知道 Load 和 CPU 不同步的原因是,Load 不仅和计算有关,也和 IO 有关。而报价是计算密集型的应用,所以我们又试验了基于 CPU 使用率的动态限流。

我们将阈值设定为 70 到 90,看下面的监控图,CPU 使用率基本稳定在 70 到 90 之间,Load 稍微高一些。压测之后搜索耗时从 70 涨到了 150 并保持稳定,稳定就表示服务是正常的。

下面我们再看一下,基于 CPU 和基于 Load 限流时搜索成功量的对比,分别是 164 和 134,说明基于 CPU 的限流的确提升了系统处理能力,提高了资源利用效率。

一些服务可能对响应时间比较敏感,所以我们又做了基于时间的动态限流,当我们将阈值设定在 140 到 200 之间时,看监控压测之后搜索耗时也基本稳定在这个 140 到 200 之间,CPU 和 Load 监控也保持稳定。

总结

我们将上述讲的基于负载的动态限流封装到了一个 API dynamic-limiter 中,方便多个系统复用。

最后总结一下,动态限流适合什么样的场景呢?

1.如果你的系统内单个服务占用大部分资源,就可以使用基于 CPU 或 Load 的动态限流。

2.如果你的服务对响应时间要求比较高,可以使用基于时间的动态限流。

实际中,也可以同时参考多种因素来进行动态限流,起到一个多重约束的作用。比如同时使用 CPU 和 TIME 时,表示既对 CPU 使用率有一个硬约束,又对服务响应时间有一个硬约束。



相关 [系统 负载 dynamic] 推荐:

基于系统负载的动态限流组件 dynamic-limiter

- -
 宋鹏玉,2014年加入 Qunar,目前在国内机票报价组,热爱技术,欢迎交流. 一个系统的处理能力是有限的,当请求量超过处理能力时,通常会引起排队,造成响应时间迅速提升. 如果对服务占用的资源量没有约束,还可能因为系统资源占用过多而宕机. 因此,为了保证系统在遭遇突发流量时,能够正常运行,需要为你的服务加上限流.

Dynamic Proxy (动态代理)

- - CSDN博客推荐文章
动态代理主要有一个 Proxy类 和一个 InvocationHandler接口. 真实主题角色(实现了抽象主题接口). 动态代理主题角色(实现了 InvocationHandler接口,并实现了 invoke()方法). Proxy 要调用 newProxyInstance方法. 1.抽象主题角色 SubjectDemo.java.

Dynamic Code Evolution for Java dcevm 原理 - redcreen

- - 博客园_redcreen的专栏
在 hostswap dcevm中我们对Dynamic Code Evolution VM有了一个简单的了解,这篇文章将介绍Dynamic Code Evolution VM的实现原理. Dynamic Code Evolution (下文简称DCE):泛指java在运行时修改程序的技术.例如aop等.

系统负载能力浅析

- - ImportNew
用什么来衡量一个系统的负载能力呢. 有一个概念叫做每秒请求数(Requests per second),指的是每秒能够成功处理请求的数目. 比如说,你可以配置tomcat服务器的maxConnection为无限大,但是受限于服务器系统或者硬件限制,很多请求是不会在一定的时间内得到响应的,这并不作为一个成功的请求,其中成功得到响应的请求数即为每秒请求数,反应出系统的负载能力.

使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model

- wang - 老赵点滴 - 追求编程之美
这也是之前在珠三角技术沙龙上的示例之一,解决的是在ASP.NET MVC使用dynamic类型Model时遇到的一个真实问题. C# 4编译器支持dynamic类型,因此在编写页面模板的时候自然就可以把它作为视图的Model类型. 表现层的需求很容易改变,因此dynamic类型的Model可以减少我们反复修改强类型Model的麻烦,再配合匿名类型的使用,可谓是动静相宜,如鱼得水.

CRM的客户数据模型:Microsoft Dynamic CRM 2011 (II)

- - CSDN博客推荐文章
图1展示了Microsoft Dynamic CRM 2011的概念客户数据模型,来自以下信息源:. 在Microsoft Dynamics CRM 2011中, 使用三个主要的实体:lead(线索), contact(联络人) 和account(账户,本文不用引起混淆的“客户”). Customer Address (客户地址)用来存储客户的各类地址信息,比如shipping address (寄送地址) 和billingaddress(账单地址).

Spark动态资源分配-Dynamic Resource Allocation – lxw的大数据田地

- -
关键字:spark、资源分配、dynamic resource allocation. Spark中,所谓资源单位一般指的是executors,和Yarn中的Containers一样,在Spark On Yarn模式下,通常使用–num-executors来指定Application使用的executors数量,而–executor-memory和–executor-cores分别用来指定每个executor所使用的内存和虚拟CPU核数.

系统负载剧变下的管控策略

- - ITeye博客
假如目前的系统有100台机器,能够支撑每天1亿的点击量(这个就简单比喻一下),然后系统流量剧变了要,我如何应对,系统有那些策略可以处理,这里总结了一下之前的一些做法. 这个最容易理解,加机器,这样的话对于系统刚刚开始的伸缩性设计要求比较高,能够非常灵活的添加机器,来应对流量的变化. 假如系统服务的业务不同,有优先级高的,有优先级低的,那就让不同的业务调用提前分组好的机器,这样的话在关键时刻,可以保核心业务.

分布式系统的负载均衡 | 架构干货

- - SegmentFault 最新的文章
记得第一次接触 Nginx 是在实验室,那时候在服务器部署网站需要用 Nginx. Nginx 是一个服务组件,用来反向代理、负载平衡和 HTTP 缓存等. 负载均衡(LB,Load Balance),是一种技术解决方案. 用来在多个资源(一般是服务器)中分配负载,达到最优化资源使用,避免过载. 资源,相当于每个服务实例的执行操作单元,负载均衡就是将大量的数据处理操作分摊到多个操作单元进行执行,用来解决互联网分布式系统的大流量、高并发和高可用的问题.

从系统架构的角度来看开源和商业负载均衡

- - 运维派
对于绝大多数的互联网企业来说, 负载均衡已经成为其系统网络架构中不可或缺的组成部分. 负载均衡技术是终端用户与业务系统之间沟通的桥梁,也是实现系统处理能力快速扩展的最佳技术. 实现负载均衡的方式很多,有很多开源的负载均衡软件,如:LVS、HAProxy、nginx等,也有很多公司推出独立的负载均衡产品,如:F5的BIG-IP,A10的Thunder,Citrix的NetScaler等等.