摘要:首先先解讀下這個報警內容,原因活躍線程數過多,是監聽的端口號用來獲取虛擬機各項信息,代表著此時的線程數,是設置的報警閾值。
前言
前天,一位21世紀的好好青年正在工位上默念社會主義大法好的時候,釘釘上又報警了(公司項目接入了open-faclon監控,指標不正常會報警給釘釘的機器人),無奈默默流淚揮手告別社會主義大法開始定位線上問題。
報警內容首先我們先來看下報警信息,為防止泄露公司信息,對項目名稱和監聽的端口號進行了抹除:
這個問題曾多次出現,一直沒有抓到導致這個問題的鬼。首先先解讀下這個報警內容,原因:活躍線程數過多,jmxport是監聽的jmx端口號用來獲取虛擬機各項信息,5118>=1500:5118代表著此時的線程數,1500是設置的報警閾值。
為什么要將閾值設置為1500呢(如果你對這個閾值的設置并不感興趣,可直接跳過閱讀)?
為了搞清楚這個閾值的建立規則,我可是下了大功夫的....操作系統可以簡單的分為32位和64位,每一個32位進程都獨享4G的虛擬地址空間,其中低2G是給用戶的,高2G是給系統預留的。也就是每一個32位進程中,實際能夠使用的內存不到2G。64位下由于尋址操作變為2的64次方基本可以看做沒有限制。介紹完這個,就來介紹下博主監控程序的運行環境,4核8GB內存64為linux系統java8,程序的jvm參數為-server -Xms4g -Xmx4g -Xmn2g。-Xss 為jvm啟動的每個線程分配的內存大小,如果未設置,則默認是1m(java8)。系統總內存為8G,堆內存設置為了4G,可用給分配線程的內存不會超過4G,理論上可以達到最大的線程數應該是4*1024個(實際會更少,系統文件、元空間等都會占用大量內存)。搜索了大量相關資料,只是簡單的計算出了一個理想情況下線程數的最大值,對于閾值設置并沒有找到一個很權威的說法。所以博主就大膽猜測,這個閾值應該是運維根據自己的經驗設置的,之所以設置這個閾值是為了更好的得知服務器的運行狀況,當超過這個數了,我們應當檢測其原因,如果是程序代碼造成的問題就需要對癥下藥,如果是環境問題或者流量確實達到這個閾值,我們就需要去考慮做集群做高可用。
如何定位線程過多的原因
jdk給了我們很多好用的工具,如果對jvm一點都沒有了解過得同學建議大家讀一下我之前的寫的jvm相關的學習筆記。首先定位java項目進程pid,然后打印堆棧文件并分析堆棧文件。其過程如下圖所示:
接下來我們著重來分析erp.txt這個文件,針對于線程過多的排查主要是查詢程序內線程池是否使用得當,我們可以根據是否存在大量相似的線程名來判斷。經過分析發現文件中大量存在OkHttp ConnectionPool,如下圖所示:
經過匹配,OkHttp Connection達到4000多個,然后再次定位,發現系統中有調用php的代碼使用OKhttp,代碼如下所示:
public final class HttpUtil { public static String doPost(String url, String content) throws IOException { OkHttpClient client = new OkHttpClient(); RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), content); Request request = new Request.Builder().url(url).post(body).build(); Response response = client.newCall(request).execute(); return response.body().string(); } public static String doGet(String url) throws IOException { OkHttpClient httpClient = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); Response response = httpClient.newCall(request).execute(); return response.body().string(); } }
簡單了解下OkHttpClient
線程過多是OkHttpClient導致的,我們就需要對癥下藥,簡單了解下其用法。翻看其源碼可以發現如下圖注釋:
簡單翻譯下:對于所有的http請求,建議你創造一個OkHttpClient實例并重復使用這是因為每個實例都有它自己的連接池和線程池,重用連接池和線程池可以減少延遲節省內存,下面的是OKHttpClinet的一些常見用法。至此我們已經完全清楚此次問題的來龍去脈,只需要重用OkHttpClient就好....
總結解決這個問題非常簡單,只要將OKhttpClient設置為單例,按照推薦用法去創建即可解決,不過這篇博客的價值并不在于此,而是和大家探討一些解決問題的思路,如果你有更好的辦法,歡迎留言。問題解決了,我繼續默念社會主義大法好了^.^
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69161.html
摘要:直接顯示了一個疑似內存泄漏的問題。然后分析文件給出的信息,發現一個叫的類。文件里面說的內存泄漏的大概的意思就是說,這個類里面的存放的東西太多了,爆掉了。修改了代碼將調用的地方改成了單例。修改完線上跑了一段日子,后來也沒有出現過這樣的問題。 問題描述: ????早上去公司上班,突然就郵件一直報警,接口報異常,然后去查服務器的運行情況,發現java的cpu爆了.接著就開始排查問題 問題解決...
摘要:此時我想到了福爾摩斯說過的一句話當你排除掉各種不可能出現的情況之后,剩下的情況無論多么難以置信,都是真相。福爾摩斯冷靜下來想一想,這個線程,有可能靜悄悄地退出了嗎,沒留下半點異常日志從理論上來說,不可能。配置建議最后,附上一份配置建議。 1、事發 我們有個視頻處理程序,基于 SpringBoot,會啟動幾個線程來跑。要退出程序時,會發送一個信號給程序,每個線程收到信號后會平滑退出,等全...
摘要:當然,如果你的核心數夠多,到個線程的并行度不滿足的話,也可以自定義一個線程池來執行,不過這樣的話,要注意自己維護這個線程池的初始化,釋放等等操作了。 事情起源于一個bug排查,一個AsyncTask的子類,執行的時候發現onPreExecute方法執行了,doInBackground卻遲遲沒有被調用。懂AsyncTask一些表面原理的都知道,onPreExecute方法是在主線程執行,...
閱讀 1203·2021-11-17 09:33
閱讀 3599·2021-09-28 09:42
閱讀 3326·2021-09-13 10:35
閱讀 2478·2021-09-06 15:00
閱讀 2438·2021-08-27 13:12
閱讀 3609·2021-07-26 23:38
閱讀 1826·2019-08-30 15:55
閱讀 539·2019-08-30 15:53