系统监控和流控-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,对于分析后的结构化数据进行监控。