挖掘应用处理变慢的“真相”

2019 年 8 月 27 日

挖掘应用处理变慢的“真相”

一、发现问题


一个风和日丽的下午,服务于亿级用户电商平台的监控系统Sherlock.IO上,突然出现了黄色告警。发出告警的是一个包裹配送相关的应用,几分钟之内这个应用前端的负载均衡服务器(Load Balancer)上连接数量陡增,这引起了 SRE 团队稍微的不安和浓厚的兴趣。


二、初步分析


针对这种情况,第一反应是:难道又是一波外部攻击?经过初步排查,情况貌似没有那么糟糕。


首先,通过内部的追踪工具可以看出,这些新增加的连接很有可能来自于内部


其次,该应用十几台机器平均分布在三个数据中心,其中两个数据中心的应用还是一片岁月静好,只有一个数据中心的应用看上去有些异常


整个电商平台的监控系统非常完备,从硬件到操作系统,再到应用内部各种指标数据一应俱全,且均是实时监控数据。查看该应用每个数据中心的处理请求数,能明显看到出问题的这个数据中心有更多的业务请求,并且是某个时间点突然增加


尽管该应用在每个数据中心服务器的数量差别不大,可出问题的数据中心之前的处理业务请求数本来就偏多。


但是在请求增加之前,三个数据中心的事务处理时间(transaction time)和服务器繁忙线程数(server busy threads)数量相差无几。出问题的这个数据中心事务处理时间明显变长,Tomcat 繁忙线程数直线跃升,也给问题的查找指明了方向。



图 1 (点击查看大图)


从图 1 数据可以看出,红线代表的数据中心在 TPS(Transaction Per Second,每秒时间内能够处理的事务)从平均 270 左右增加到 420 左右时(1.56 倍),平均的事务处理时间从 10 毫秒增加到原来的 2.7 倍左右。之前 TPS 270 左右时,只要平均 3 个 Tomcat 线程来处理,而现在平均繁忙线程需要 11 个左右(3.2 倍)。


那么是什么原因让它在请求增加到原来 1.56 倍的时候,平均事务处理时间增加到原来的 2.7 倍呢?


三、深入探究


要回答这个问题,首先可能要问的是,增加的请求有什么特殊的地方


带着这个问题,我们查看了这个应用处理的服务类型:它是微服务的一个组件,只处理一个特殊的请求,并且对时间延迟的要求也挺高(问题出现之前平均的延迟只有 10 毫秒左右)。


那么是不是新增加的请求有不一样的参数或者不同的有效负荷(payload)呢?


我们根据系统整体的指标数据,无法回答这个问题。不过既然是延迟增加,那就可以从 CAL(eBay 的集中式日志系统,能查看每个应用、服务及事务的详细日志)中去找一些线索。


仔细查看这些变长的业务日志,我们发现在两行日志中间,有一些可疑的时间间隔。出问题之前,这两行日志之间大概只有不到 1 毫秒左右时间差,出问题之后,却出现了 80 毫秒左右的延迟。


那么这两行之间到底出了什么问题?是由于特殊的代码路径还是出于其他原因?


阅读这段源代码,并没有发现特殊的路径,唯一值得怀疑的是:其中有些代码通过 log4j 输出日志,而不是由集中式的日志客户端写日志。正常情况下,所有的日志都应该写入这个集中式日志系统。除此之外,这些 log4j 的日志是通过 logger.debug() 打印的


那么问题有没有可能是跟这些日志相关呢?


首先我们查找了服务器上的文件系统,并没有找到 log4j 的相关配置文件。log4j 在默认的情况下,如果没有代码更改日志的级别,就会默认打印所有级别。查看系统打印的日志文件,发现另一个与之相关并可疑的地方:日志内容正以每秒 3M 的速度产生。日志文件里正是之前看到的 debug 打印的内容


日志文件以这么快的速度写入,很值得怀疑,因为 log4j 1.* 版本是同步日志,写入文件会加锁,导致各个线程锁竞争。为了验证这个问题,我们添加了一个 log4j 的配置文件,设置日志级别为 ERROR单独重启某台服务器之后,便看到了立竿见影的效果


从下面图 2 和图 3 中的对比图可以看到,修改并重启之后,被修改的机器在流量比较大的时候,处理能力更强了,但事务处理时间并没有变长。


说明这个 log4j 的 debug 就是导致服务变差的根本原因


图 2 及图 3 分别为 TPS(每秒时间内能够处理的事务)对比图事务处理时间对比图绿线代表修改配置的服务器,红线代表没有更改的服务器:



图 2 TPS 对比图 (点击查看大图)



图 3 事务处理时间对比图(点击查看大图)


四、解决问题


问题确认之后,真正的元凶就很容易从源代码中弄清楚了。


出问题的代码是一个第三方代码库(jar lib),它使用 log4j1.*版本去打印日志。该应用默认没有设置 log4j 的配置文件,所以 debug 信息也是打印出来的。且默认这些 debug 信息打印到了 System.out 里面。System.out 是一个 PrintStream 对象,PrintStream 的 println 方法里面使用了 synchronized 关键字去竞争锁


在并发比较低的时候,JVM 使用偏向锁或者自旋锁,化解了重量级的同步操作。在并发竞争比较激烈的情况下,JVM 对 synchronized 的优化就无法发挥效果了,所以形成了一个同步顺序队列。竞争越激烈,应用处理越慢。把日志级别设置成 ERROR 之后,就不打印这些 debug 信息了,这部分的锁也就被消除了。


五、总结


从这次事件中的数据可以看出,尽管一开始有锁存在,但在达到临界点之前,这个锁都不会造成太大影响。这也是 JVM 对 synchronized 的优化在起作用。而一旦超过临界点,变慢的效果就会被很快放大。


因此,当我们发现应用的事务处理时间变长的时候,不妨去看一下是不是某些锁导致系统形成一个顺序队列,让系统的处理能力变差


本文转载自公众号 eBay 技术荟(ID:eBayTechRecruiting)


原文链接


https://mp.weixin.qq.com/s/Sh7ddc-3mGXWCGppi50EHg


2019 年 8 月 27 日 08:004113

评论

发布
暂无评论
发现更多内容

Android知识体系大纲!Android平台HTTPS抓包解决方案及问题分析,年薪50W

欢喜学安卓

android 程序员 面试 移动开发

深度剖析原理!2020年Android网络编程总结篇,已开源

欢喜学安卓

android 程序员 面试 移动开发

生产环境全链路压测建设历程 16:淘宝网高可用历程的总结

数列科技杨德华

全链路压测 七日更

数字货币量化交易所系统开发案例

系统开发咨询:I76-883I-5I52 邓森

【Java入门】String,StringBuffer和StringBuilder

HQ数字卡

Java 七日更

甲方日常 71

句子

工作 随笔杂谈 日常

欧盟推出新数字法案,会是一场“锄强扶弱”的数字监管变革吗?

脑极体

今天发的被删了,不是我没写

lidaobing

28天写作营

我们该如何正确的中断一个线程的执行??

冰河

Java 并发编程 多线程 高并发 中断线程

架构师训练营第十一周作业

文智

极客大学架构师训练营

架构师 3 期 3 班 -week5- 作业

zbest

作业 week5

第十三周 作业

熊桂平

极客大学架构师训练营

阿里不允许使用 Executors 创建线程池!那怎么使用,怎么监控?

小傅哥

Java JVMTI 线程池 七日更 Executors

阿里P8手把手教你!微信小程序的事件处理,安卓系列学习进阶视频

欢喜学安卓

android 程序员 面试 移动开发

不讲码德!坏味道偷袭我这个老码农

爱笑的架构师

Java 代码审查 代码坏味道 代码规范 七日更

【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

herongwei

c++ 后端 迭代器模式 源码剖析 stl

架构师 3 期 3 班 -week5- 总结

zbest

总结 week5

Flutter动态创建UI实现方案

FisherJoe

Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)

刘悦的技术博客

django Vue 微信支付 python3 请求数据 扫码

灵魂一击!详解Java中的IO输入输出流

程序员小毕

Java 程序员 架构 io

既生 var 何生 let

喵叔

七日更

十日谈:我的 2020

escray

2020 日更挑战 十日谈

突破某度云盘下载限速,提速30倍!想学?我教你啊

Silently9527

百度云 HTTP

创业感悟 | 2021是继续打工还是选择创业?

黑马腾云

创业

vivo 商城架构升级-SSR 实战篇

vivo互联网技术

前端 服务端 Node SSR

FGC青蛙钱包系统开发|FGC青蛙钱包软件APP开发

开發I852946OIIO

系统开发

程序员告诉你:C/C++后台开发需要学习哪些技能书

赖猫

c++ Linux 后台开发

架构的业务属性

soolaugust

架构 设计 架构师 七日更

TypeScript | 第一章:环境搭建及基础数据类型

梁龙先森

typescript 前端 七日更

和 lvgo 一起学习设计模式.PDF

lvgo

Java 设计模式 23种设计模式

文件写入的6种方法,这种方法性能最好

王磊

Java io 文件读写 文件操作 文件写入

挖掘应用处理变慢的“真相”-InfoQ