查看原文
其他

明明白白| 如何打造平台稳定性能力

钟华 中生代架构 2019-05-15

架构师成长的好伙伴连接技术 接力价值


授权声明

本文转载自阿里巴巴中间件(Aliware_2018)


 第68篇好文:3611字 | 7分钟阅读

前言

在整个稳定性体系中,所包含的范围非常广泛,从机房的布线、网络通信、硬件部署、应用架构、数据容灾等方面都与之相关。

从共享服务中台的角度看,则更多的是从应用架构设计和中间件平台的维度对平台的稳定性实现更精确化的管理和保障。


01

限流和降级产生的背景

_____

先设想一个场景,你开发了一个企业中非常核心的一个服务,日常情况下会有上百个应用调用,如果对服务的调用不加限制的使用,可能会因为某个应用开发的bug 或不合理的设计给服务造成非常大的压力,直接导致所有服务节点全部被请求占满,使得原本非常核心的应用因为访问服务超时而产生了很大的生成事故。


从现象来说,所有服务节点看起来运行很繁忙,但从应用方的角度来看,因为服务响应时间过长,实际上该服务并没有提供有效服务。


从设置上来说,服务就是给其他应用提供服务的,用户怎么调用服务很难控制,所以必须从服务自身做好保护,否则可能因为一个小的问题造成平台级的故障。



另一个是活动大促的场景,准备好的50台机器资源可以应对预估的100万参与人数。


但实际情况是瞬间来了1000万用户,远远超过服务处理能力的访问请求,会使后端的服务器直接满负荷运算,并伴随着大量的资源抢占和上下文切换,使平台处理能力下降到一个极低的程度,影响业务请求的响应时间。


类似的还有因为一个社会热点,应用端出现用户请求陡增的情况。


02

限流的作用和前期准备

_____

限流的作用相当于电路上的保险丝,当过载的时候掐掉一点流量,让系统有能力集中资源以较快的深度处理 平台处理能力范围内 的业务请求。


也就是让上面提到的大促场景中,仅让1000万用户中的100万用户进入后端的处理流程中,将其余900万用户的请求通过队列或直接阻挡在平台处理单元之外的方式,保障平台在处理能力范围内对100万的用户请求进行处理。



平台要具备限流能力,需要配备好压测和监控能力。


通过压测,我们可以知道服务实例的部署最大能满足多少的业务请求。


但传统的压力测试方法都是采用模拟的数据,从实践的角度来看,这些压测数据与在实际生产环境中所表现的指标还是有比较大的偏差,也就是说,采用模拟数据进行压力测试的方式并不能准确测量出平台的能力峰值。


阿里巴巴中间件团队经过内部5年+的全生态沉淀,开发出的针对分布式场景,可模拟海量用户的真实业务场景的性能测试产品PTS,能更方便和准确的对服务的容量进行评估,这在“如何打造系统稳定平台”之后的章节中会详细介绍。


在掌握服务的容量后,接下来就是针对服务资源的使用情况进行监控,通过资源监控的指标与之前所获取的服务能力进行比较,如果超过服务处理上限则启动限流。


通过CPU、内存和磁盘IO等资源的使用情况来判断系统目前的负载往往是不准确的。


因为很多情况下系统本身的处理能力出于什么样的水位跟这些操作系统资源的使用情况没有一个清晰的对应关系,所以在实际生产中,都会通过服务的QPS作为限流的关键判断指标。


03

阿里巴巴是如何做限流管控的

_____

对于平台限流的实现,先从一个典型服务化应用架构的角度来看。


用户的请求首先会通过前端接入层(一般采用Nginx),分发到后端的应用集群上,应用集群中主要负责用户的前端交互以及业务需求对后端服务集群中的服务进行服务调用。


为了避免出现远超过系统处理负载上限的访问请求,同时又能很好的兼顾安全问题,通过一些安全策略防止对平台的恶意攻击,所以最优的限流拦截点在前端接入层面,因为一旦让“洪流”进入到系统的下层,对于系统的冲击以及限流的难度都会加大。



阿里巴巴是通过在 Nginx 上实现的扩展组件 TMD(taobao missile defense淘宝导弹防御系统)实现了接入层限流的主要工作,TMD系统可通过域名类限流、cookie限流、黑名单以及一些安全策略等很好的实现了在接入层的限流措施。


TMD系统包含了淘宝技术团队开发的开源模块 nginx-http-sysguard,主要用于当访问负载和内存达到一定的阈值时,会执行相应的动作,比如直接返回503、504或者其他url请求返回代码,一直等到内存或者负载回到阈值的范围内,站点才恢复可用。


在模块 nginx-http-sysguard基础上,淘宝TMD系统给用户提供了可视化的配置管理界面,方便用户针对不同的业务场景实现不同的限流规则。


如果来自单台机器持续访问淘宝平台上的一个URL页面,可在TMD中设置规则:访问频率大雨180次/秒,则进行IP访问频率限速或cookie访问频率限速。


正是有了TMD 这样配置灵活、操作方便的规则配置界面,运维人员可以针对所发现的异常请求以及实时的处理状态,设置出各种保护措施,保障平台在面对大流量时具备一定的自我保护能力,在平台接入层外部惊涛骇浪的访问洪流下,平台接入蹭内部保持稳定、健康的运行状态。


在接入层实现了限流后,一定会有部分用户的请求得不到系统正常的处理,所以平台一般会给用户返回限流页面,在一定程度上减少用户因为请求没有成功处理的失落体验,限流页面的风格会与网站、app的设计风格统一,页面也会包含跳转引导界面,以形成用户体验和业务处理流程的闭环。


04

TMD平台在服务层面临的挑战

_____

TMD平台能很好的实现在平台接入层的限流功能,但对于服务层就无能为力了。


对于实现服务的限流控制,传统的实现方式通常用spring的aop机制,对需要限流的接口定义一个advice拦截器,示例代码如下:


<bean id="spuServiceAdvisor"

   class="org.springframework.aop.suppport.RegexpMethodPointcutAdvisor">

    <property name="partners">
        <list>
            <value>com.taobao.item.service.SpuService.*</value>
        </list>
        </property>
        <propetry name="advise">
            <ref bean="spuServiceApiAdvice" />
        </property>
    </bean>
    <bean id="spuServiceApiAdvice" />
        class="com.taobao.trade.buy.web.buy.util.monitor.advice.SpuServiceApiAdvice" />


其中的 SuperServiceApiAdvice 类实现MethodBeforeAdvice接口,重写before方法,那么在调用指定的接口或者方法前会计算当前thread count或qps,如果当前的线程数大于所设置的最大线程数阈值,则返回访问限流的异常信息。


示例代码如下:


Override
protected void invokeBeforeMethodForFlowControl(MonitorStore monitorStore) throws FlowControlException{
    long newThreadCnt = monitorStore
    .getStoreDataInfo(getMonitorNmae(),getKey()).getThreadCnt()
    .get();

    if(newThreadCnt > MonitorParam.MAX_THREAD_COUT_FIVE){
       throw new FlowControlException(
       "SpuServiceApiAdvice access control, threadcnt="
               + newThreadCnt);
        }
}


这套流控技术方案是可行的,实现起来也非常简单,但在实际应用场景中还是会发现不少问题,比如:


1. 如果一个应用需要对100个接口进行限流,那么对应地也就需要配置100个advice和编写100个拦截器,如果是成百上千的应用呢?

 2. 限流阀值是硬编码形式,无法动态调整,当然你也可以动态调整(比如定义成一个静态变量,然后通过curl去调整),但当限流开关达到一定量级后你会发现这是一件非常痛苦的事,很难维护管理;

 3. 限流手段太过单一,无法对特殊场景实现多样化的限流;

 4. 没有一个统一的监控平台,无法监控当前的限流情况;

 5. 限流算法简单,当在双十一这种特殊场景,会看到毛刺现象,需要一种更平滑的限流算法;

想要加入中生代架构群的小伙伴,请添加群助手小姜的微信

申请备注(姓名+公司+技术方向)才能通过哦!



“做技术要懂管理,做管理要学模式”

突破是中生代社区新上架的图书

签名版即将售罄

购书后加上方微信可以进书友群

申请备注(购书)



推荐阅读



* 资深技术专家杨彪:你真的了解REST吗?

* 阿里开源|Nacos帮我们解决什么问题?

* 如何改变Redis用不好的误区

* 阿里特技|如何通过限流实现服务的高可用性


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存