平穩運行半年的系統宕機了,記錄一次排錯調優的全過程!

據說微信搜索《Java魚仔》會變動強哦!前端

本文收錄於JavaStarter ,裏面有我完整的Java系列文章,學習或面試均可以看看哦git

(一)前言

最近發生了一件很讓人頭疼的事情,已經上線半年且平穩運行半年系統在年後早高峯的使用時發生了瀕臨宕機的狀況。訪問速度特別慢,後臺查到大量time_wait的鏈接,從代碼層面到架構層面到網絡層面排查了幾天幾夜,總算是有告終果。github

(二)架構、問題描述

先簡單描述一下這個系統的架構,公網域名對應的公網IP鏈接着華爲雲的ELB彈性負載均衡服務,ELB下是兩臺Nginx服務器多活,Nginx下鏈接着四臺內網應用集羣服務器(經過專線),Mysql服務器讀寫分離、Redis服務器主從配置。面試

發生宕機問題時,四臺集羣服務器的Load Average飆到了200,要知道8核的服務器Load average超過40就須要注意了。同時Nginx的tcp鏈接數也異常,有大量的TIME_WAIT鏈接。sql

load average達到了200

(三)問題排查

這個問題主要緣由仍是系統擋不住忽然間的高併發,根據上面的這些報錯數據,首先是想辦法把load average降下去。請求大於當前的處理能力,會出現等待,引發load average升高。所以主要從下面幾個方面進行了排查:數據庫

3.1 檢查Nginx配置

首先是運維人員檢查Nginx配置,看看是不是配置不對形成大量time_wait鏈接,檢查結果是沒有問題。服務器

3.2 抓網絡請求

運維人員幫忙抓取了應用服務器在高併發時的網絡包,最後分析下來有一個接口的請求次數是全部請求的40%。這是一個疑問點,這個請求爲何會被調用如此多的次數。微信

3.3 檢查線程堆棧信息

由於請求數量如此多,所以須要檢查佔用CPU最高的線程堆棧信息,最後發現垃圾回收線程居然佔用了30%+資源,說明垃圾回收應該是存在一些問題的。網絡

3.4 檢查數據庫鏈接池

檢查數據庫鏈接池是否正常,看看有無死鎖或者資源耗盡等問題,查出來是一切正常的。架構

3.5 檢查垃圾回收狀況

經過jstat -gcutil 命令抓取垃圾回收狀況,發現YGC很頻繁,大概一秒一次,下圖是高峯期過了以後的垃圾回收狀況,YGC大概在一分鐘8次左右。所以也是懷疑業務代碼存在問題。

(四)定位業務代碼

經過上面的信息,咱們初步懷疑那個被頻繁調用的接口存在問題。查到代碼後,發現每次刷新頁面的時候,都會調用這個接口7次,這種調用太頻繁了。同時代碼中發現了大量JSON轉換、序列化的狀況,查了一些資料後發現這種行爲確實會致使YGC頻繁操做。

因而優化代碼邏輯,刷新頁面的時候調用一次接口就行,數據一次性傳給前端,而不是屢次調用。同時將沒有必要的JSON轉換代碼優化掉。按理說如今的性能應該能夠提高很多。打包、上傳、從新觀察。

(五)問題仍是存在

平穩了4天,在週五早晨高峯的時候,運行緩慢、負載高的狀況又發生了。這下傻眼了,難道是有其餘地方沒有檢查到嗎。

這時想到一個問題,明明一直沒有動這些服務器,爲何平穩運行了半年後忽然出現問題,因而往其餘方面去想,懷疑是從公網IP進來到應用服務器中的某條鏈路存在問題。因而嘗試着斷掉公網鏈路,去壓測放在內網的這些應用,居然不會出現以前的問題。

因而檢查公網到內網的專線網絡請求狀況,發現出口帶寬最高就只能到200M,就是早高峯的時候,而當時買的專線帶寬是能夠到500M的。所以懷疑是帶寬滿了致使請求進不來堵塞在公網的Nginx服務器上,而用戶發現運行緩慢後頻繁去刷新,致使大量的Tcp鏈接time_wait。因而趕忙聯繫相關服務商對網絡帶寬狀況進行檢測,果真500M的帶寬直接打了折扣,聯繫相關人員處理這方面的問題。

同時一些靜態資源放在私有云的服務器上也會致使網絡流量大,將這些靜態資源分離到公有云的Nginx服務器上,來下降這條專線的網絡壓力。

(六)後續措施

後續觀察來看,問題應該是解決了,當時發生宕機時,是用戶反饋上來的,這一點很不合理,後續須要作好服務的監控等各項措施。同時在總體的排查問題時,也解決了一些雖然不是問題根源,但也須要優化的地方。

我是魚仔,咱們下期再見!

相關文章
相關標籤/搜索