由于业务方的一个接口突然猛增,为了不影响其他服务,我们决定修改这个接口的配置让其间接下线处理。但是万万没想到的是更改完接口配置后,过了一会所有的接口调用都返回nginx 502 Bad Gateway.于是赶紧排查问题,登录线上机器发现机器负载高达800多,于是不得已赶紧重启服务。但是重启服务后,过了 一会又负载马上又上来了,服务又不可用。于是赶紧让业务调用方下线这个接口,问题得到解决。事后我们看代码发现,由于更改了接口配置导致接口请求会走一个异常分支,然后调用log4j打印异常堆栈信息,类似logger.warn("msg",e),然后怀疑是打印e这个异常堆栈导致的问题。于是下午在测试环境进行压测复现这个问题,用jmeter模拟线上case进行压测,接口qps在1500左右的时候问题并没有复现,后面同事也对改接口进行压测,接口qps达到4000+的时候问题就复现了。后面我们把e这个参数去掉,然后用相同的参数来压测,发现问题不在复现。于是得出结论,负载飙升和打印e这个对象以及接口qps都有关。因为qps在1500左右即使打印了e负载也正常,4000多的时候负载才升高。去掉打印e这个对象,qps4000多的时候负载却不在升高,所以e这个对象的打印是引起问题很大的一个原因。看了下e.printStackTrace();这个方法的逻辑比较复杂。复杂体现在一个是要打印的内容比较多,还要很多计算逻辑,所以对cpu和io消耗都有。打印日志最终是要从用户态切换到内核态,所以线程切换也要耗费cpu资源。由于接口请求量比较大,线上机器是8核cpu,上述几个原因最终导致了系统负载飙升达800多,导致服务不可用。返回502的原因看了nginx的日志显示连接服务Connection timed out。
之前觉得日志打日志无所谓,越到越好,这样有利于排查问题,之所有有这样的心里是之前接口请求量不大,也从来没遇到打印日志问题会对服务有影响。从这次事件后,打印日志应该简短,不必要的日志不要打印,打印的每一行日志都应该有利于排查问题否则就不该打印。异常日志e参数,一定要确保有必要打印才打印。