`
iamzhongyong
  • 浏览: 797148 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

系统监控和流控-java应用

 
阅读更多

     目前系统的监控方面,linux机器,可以定时的获取cpu、load、IO、网络等情况,统计之后,如果超过阀值,即可报警。

web的请求,可以通过分析apache的日志,获取PV、UV以及页面的响应时间等信息,统计这些信息,如果有异常,报警即可。

但是java系统(一个java进程)中的bean的情况如何做到监控和流控呢?

    双十一,各个系统都有一些监控和流控的策略,了解了一圈之后,打算总结一下,只是粗略的写一下思路,记录一下,不涉及到细节(因为细节坑很多)。

    监控的目前是为了了解系统的运行细节,流控是为了在出现问题(瞬间请求暴涨、持续一段时间请求超过平均值、底层依赖的应用或者DB出现异常)的时候能够做出处理(动态限流拒绝新的请求进来<限流策略可以设置>、利用开关<修改静态类的属性>进行应用降级处理减少非核心的调用)。

    (1)业务日志

    监控业务代码抛出来的日志信息(可以在linux中通过crontab定时程序来抓取,也可以通过控制台来远程处理,也可以把文件拉到集中的分析服务器来处理),如果异常数太多,或者出现自己之前设置过的报警关键字,则进行报警;

    (2)java gc的日志

    java在运行过程中,如果配置了参数(-verbose:gc -Xloggc:/home/admin/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps),能够看到系统的gc的情况,如果FullGc特别频繁(超过一小时一次),可以提示报警;

    (3)拥堵线程数作为监控指标

    创建一个对象,里面一个key是方法的代表,然后属性中有个计数器(这个key此时对应的拥堵线程数),如果方法体内处理变慢,并发情况下拥堵线程数会增加,此时,可以进行报警,也可以把后续的请求当掉,降低负载。计数器进行变化可以有两种方式:第一种就是,通过AOP的方式,在方法调用前(before)拥堵线程数加一,方法返回后(after)拥堵线程数减一,这种好处就是不用硬编码;另外一种就需要写代码,在方法体内,调用开始加以,然后try住,在finally的时候减一。

    (4)根据方法调用的QPS和RT

    QPS即一秒内方法调用的次数,RT即一秒内方法调用的平均返回时间。对于web请求,一般在web服务器(apache/nginx)中做掉这个,在服务器A中部署一个client,用来做计数统计,具体的计数规则可能会比较复杂,超过阀值(有可能是攻击),则请求server端此时的拒绝策略,是让用户等待,还是跳转待验证码页面让其输入验证码之后再进行访问,还是直接返回错误。对于java中的bean方法,如何获取呢?如三种描述,两种方式一种是AOP拦截,一种是代码中硬编码。

    (5)基于AOP获取一个特定方法在特定时间段(例如一分钟)的拥堵线程数、执行次数(总次数、成功次数、失败次数)、响应时间

    做一个本地内存对象,用于记录这些信息,通过AOP的before获取信息(当前时间,线程数加一,调用次数加一),afterReturen获取信息(返回时间、线程数减一,调用次数加一,可以定制啥叫成功失败,然后相应次数增加),afterThrowing获取信息(返回时间、线程数减一、失败次数加一),最后定时dump内存中的数据,存储到DB或者日志,然后对于这些信息进行监控(可以根据历史来进行同比和环比)进行报警。

    (6)动态来添加QPS和RT的流控

    这种流控方式最为灵活,应用端依赖一个jar包,然后添加一个全局的AOP配置(对于页面的请求,在web.xml中添加filter即可​),拦截所有的方法(性能消耗可以忽略),但是只有符合规则的方法才会进行统计,然后有一个控制台设置规则,设置好规则后推送到应用端,应用端获取这个规则,根据这个规则来进行统计,超出阀值则进行限流。这种方式最为灵活,遇到紧急问题的时候可以通过控制台来限流掉。

    (7)请求是海量的情况下如何进行监控

    在请求很大的情况下,此时应用就不要处理监控的逻辑了,只要获取调用的信息(时间点、响应时间、方法签名等信息),然后把这些信息打印到日志中,异步来进行处理,把这些日志拉到专门的分析集群,然后在分析集群里面来做实时的分析,把分析的结果持久话到BD,对于分析后的结构化数据进行监控。

 

转载公司一位同事的文章:

http://rdc.taobao.com/team/jm/archives/2594

 

流量预警和限流方案中,比较常用的有两种。第一种滑窗模式,通过统计多个单元时间的访问次数来进行控制,当单位时间的访问次数达到的某个峰值时进行限流。第二种为响应模式,通过控制当前活跃请求数,来进行流量控制。下面来简单分析下两种的优缺点。

1、滑窗模式

模式分析:

在每次有访问进来时,我们判断前N个单位时间里总访问量是否超过了设置的阈值,若超过则不允许执行。

这种模式的实现的方式更加契合流控的本质意义。理解较为简单。但由于访问量的预先不可预见性,会发生单位时间的前半段有大量的请求涌入,而后半段则拒绝所有请求的情况发生。(一般,需要会将单位时间切的足够的细来解决这个问题)其次,我们很难确定这个阈值设置在多少比较合适,只能通过经验或者模拟(如压测)来进行估计,不过即使是压测也很难估计的准确,线上每台机器的硬件参数的不同,或者同一台机子在不同的时间点其可以接受的阈值也不尽相同(系统中),每个时间点导致能够承受的最大阈值也不尽相同,我们无法考虑的周全。

所以滑窗模式往往用来对某一资源的保护上(或者说是承诺比较合适:我对某一接口的提供者承诺过,最高调用量不超过XX),如对db的保护,对某一服务的调用的控制上。因为对于我们应用来说,db或某一接口就是一共单一的整体。

代码实现思路:

每一个窗(单位时间)就是一个独立的计数器(原子计数器),用以数组保存。将当前时间以某种方式(比如取模)映射到数组的一项中。每次访问先对当前窗内计数器+1,再计算前N个单元格的访问量综合,超过阈值则限流。

这里有个问题,时间永远是递增的,单纯的取模,会导致数组过长,使用内存过多,我们可以用环形队列来解决这个问题。

2、响应模式

模式分析:

每次操作执行时,我们通过判断当前正在执行的访问数是否超过某个阈值在决定是否限流。

该模式看着思路比较的另类,但却有其独到之处。实际上我们限流的根本是为了保护资源,防止系统接受的请求过多,应接不暇,拖慢系统中其他接口的服务,造成雪崩。也就是说我们真正需要关心的是那些运行中的请求,而那些已经完成的请求已是过去时,不再是需要关心的了。

我们来看看其阈值的计算方式,对于一个请求来说,响应时间rt/qps是一个比较容易获取的参数,那么我们这样计算:qps/1000*rt。

此外,一个应用往往是个复杂的系统,提供的服务或者暴露的请求、资源不止一个。内部GC、定时任务的执行、其他服务访问的骤增,外部依赖方、db的抖动,抑或是代码中不经意间的一个bug。都可能导致相应时间的变化,导致系统同时可以执行请求的变化。而这种模式,则能恰如其分的自动做出调整,当系统不适时,rt增加时,会自动的对qps做出适应。

代码实现思路:

当访问开始时,我们对当前计数器(原子计数器)+1,当完成时,-1。该计数器即为当前正在执行的请求数。只需判断这个计数器是否超过阈值即可。

 

分享到:
评论
1 楼 di1984HIT 2014-02-16  
相应模式感觉很简单,就是简单根据次数判断么?

相关推荐

Global site tag (gtag.js) - Google Analytics