挖掘應用處理變慢的“真相”

一、發現問題

一個風和日麗的下午,服務於億級用戶電商平臺的監控系統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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章