亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

記一次線程掛死的排查過(guò)程(附 HttpClient 配置建議)

jollywing / 1344人閱讀

摘要:此時(shí)我想到了福爾摩斯說(shuō)過(guò)的一句話當(dāng)你排除掉各種不可能出現(xiàn)的情況之后,剩下的情況無(wú)論多么難以置信,都是真相。福爾摩斯冷靜下來(lái)想一想,這個(gè)線程,有可能靜悄悄地退出了嗎,沒(méi)留下半點(diǎn)異常日志從理論上來(lái)說(shuō),不可能。配置建議最后,附上一份配置建議。

1、事發(fā)

我們有個(gè)視頻處理程序,基于 SpringBoot,會(huì)啟動(dòng)幾個(gè)線程來(lái)跑。要退出程序時(shí),會(huì)發(fā)送一個(gè)信號(hào)給程序,每個(gè)線程收到信號(hào)后會(huì)平滑退出,等全部線程都退出后,整個(gè)進(jìn)程再平滑退出。

整個(gè)程序平時(shí)運(yùn)行都正常,然后有一天,我們發(fā)送了退出信號(hào)給程序后,發(fā)現(xiàn)程序無(wú)法自動(dòng)退出了!腫么回事呢,grep 一下日志看到是這樣的。

# grep "receive exit signal" /PATH/TO/LOG

[2019-02-22 09:49:28,884][INFO ][Thread-75][n.p.j.e.l.l.PolyvQueueVideo:83] - receive exit signal ... exit current thread
[2019-02-22 09:49:56,271][INFO ][Thread-78][n.p.j.e.l.l.PolyvQueueVideo:83] - receive exit signal ... exit current thread
[2019-02-22 09:53:24,943][INFO ][Thread-74][n.p.j.e.l.l.PolyvQueueVideo:83] - receive exit signal ... exit current thread
[2019-02-22 09:55:23,317][INFO ][Thread-79][n.p.j.e.l.l.PolyvQueueVideo:83] - receive exit signal ... exit current thread
[2019-02-22 09:57:00,196][INFO ][Thread-77][n.p.j.e.l.l.PolyvQueueVideo:83] - receive exit signal ... exit current thread

這里的程序總共啟動(dòng)了6個(gè)線程的,但上面看到只有5個(gè)線程退出了,還有一個(gè)哪兒去了?不肯輕易就義么?好頑強(qiáng)的線程。。。

2、排查

有點(diǎn)小幸運(yùn)的是,從上面這5個(gè)線程的名稱,我們可以推斷出那個(gè)頑強(qiáng)的線程的名稱,從74到79,中間唯獨(dú)缺了76!那就是你啦 Thread-76!

再查 Thread-76 的日志,確實(shí)是我們想找的那個(gè)線程,然后發(fā)現(xiàn)原來(lái)在好幾天前它 好像就停止了運(yùn)行 ,不再有日志輸出。也沒(méi)有任何異常信息!Thread-76 就這樣悄悄的離開(kāi),不帶走一片云彩。我對(duì)著日志和代碼大眼瞪小眼看了半個(gè)小時(shí),一籌莫展。

此時(shí)我想到了福爾摩斯說(shuō)過(guò)的一句話:

“當(dāng)你排除掉各種不可能出現(xiàn)的情況之后,剩下的情況無(wú)論多么難以置信,都是真相?!?-- 福爾摩斯

冷靜下來(lái)想一想,Thread-76 這個(gè)線程,有可能靜悄悄地退出了嗎,沒(méi)留下半點(diǎn)異常日志?從理論上來(lái)說(shuō),不可能。一個(gè)線程,要么順利地執(zhí)行直到結(jié)束,要么中途出錯(cuò)退出了,如果這樣肯定有異常信息,但我們并沒(méi)看到有異常日志。排除掉 “Thread-76 已經(jīng)退出了” 這個(gè)可能性之后,我有個(gè)大膽的想法:這個(gè)線程還一直運(yùn)行著!安安靜靜地運(yùn)行著,持續(xù)著好幾天,沒(méi)有半點(diǎn)日志輸出!

是出現(xiàn)了死鎖嗎?不確定,但我們可以驗(yàn)證一下這個(gè)線程是不是真的還存活著。祭出 jstack,把線程信息 dump 出來(lái),一查,果然見(jiàn)到了 Thread-76!

"Thread-76" #141 prio=5 os_prio=0 tid=0x00007f812d7d9800 nid=0x12848 runnable [0x00007f8227cfa000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:170)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
        - locked <0x00000005e64cad10> (a java.io.BufferedInputStream)
        at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:77)
        at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:105)
        at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1115)
        at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1832)
        at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1590)
        at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:995)
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:397)
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
        at net.polyv.jet.encoding.legacy.util.IPUtil.delRemoteServerCacheFile(IPUtil.java:175)
        ***

可以看到,這個(gè)線程并沒(méi)有發(fā)生死鎖,但卡在了發(fā)送 HTTP 請(qǐng)求這一步。可能是網(wǎng)絡(luò)有問(wèn)題,或者是服務(wù)端除了問(wèn)題,反正我們沒(méi)收到響應(yīng),然后線程就一直停在這了。怎么會(huì)這樣呢,難道發(fā)送 HTTP 請(qǐng)求時(shí)沒(méi)有設(shè)置超時(shí)時(shí)間嗎?我一查代碼,還真的沒(méi)設(shè)置。。。這是個(gè)低級(jí)錯(cuò)誤啊。

3、總結(jié)

弄清楚了原因之后,問(wèn)題就迎刃而解了??偨Y(jié)一下,有幾個(gè)地方可以改進(jìn):

客戶端發(fā)送 HTTP 請(qǐng)求時(shí),一定要設(shè)置超時(shí)時(shí)間,避免出現(xiàn)問(wèn)題導(dǎo)致請(qǐng)求卡死。

接收 HTTP 請(qǐng)求的服務(wù)端,各級(jí)服務(wù)器(例如 Nginx、Tomcat)也都要設(shè)置超時(shí)時(shí)間,理由同上。

多線程的程序,出問(wèn)題時(shí)進(jìn)行排查的難度會(huì)相對(duì)大一些。所以,對(duì)于手工啟動(dòng)、維護(hù)的線程,可以的話自定義個(gè)線程名稱吧,出問(wèn)題時(shí)也有跡可循。

4、HttpClient 配置建議

最后,附上一份 HttpClient 配置建議。

由于各種原因,HttpClient 經(jīng)歷過(guò)好幾次版本變更,且這幾次變更導(dǎo)致其 API 用法都不一樣,不了解情況的人往往會(huì)覺(jué)得懵逼,我到底該用哪個(gè)版本呢?到底該用哪種方法做配置呢?到底該配置哪幾種超時(shí)時(shí)間呢?下面這個(gè)例子,應(yīng)該基本上涵蓋了大多數(shù)的應(yīng)用場(chǎng)景了,拿走不謝。對(duì)應(yīng)的版本是 HttpClient 4.5.* 。

public static CloseableHttpClient buildHttpClient() throws KeyStoreException, NoSuchAlgorithmException,
        KeyManagementException {
    HttpClientBuilder builder = HttpClientBuilder.create();
    
    // 信任全部 HTTPS 證書(shū),避免 HTTPS 請(qǐng)求因?yàn)樽C書(shū)問(wèn)題而失敗。留意,風(fēng)險(xiǎn)自擔(dān)。
    SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build(); // 信任全部證書(shū)
    builder.setSSLContext(sslContext);
    HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; // 也信任全部域名
    SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
    Registry socketFactoryRegistry = RegistryBuilder.create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", sslSocketFactory).build();
    PoolingHttpClientConnectionManager connectionManager =
            new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    
    // 設(shè)置并發(fā)連接數(shù)上限
    connectionManager.setMaxTotal(CONNECTION_LIMIT_TOTAL); // 總的并發(fā)連接數(shù)上限
    connectionManager.setDefaultMaxPerRoute(CONNECTION_LIMIT_PER_HOST); // 單個(gè)域名的并發(fā)連接數(shù)上限
    builder.setConnectionManager(connectionManager);
    
    // 設(shè)置默認(rèn)的超時(shí)時(shí)間。具體數(shù)值可按需調(diào)整。
    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(CONNECT_TIMEOUT) // 建立連接的超時(shí)時(shí)間
            .setSocketTimeout(SOCKET_TIMEOUT) // 連接建立后,傳輸數(shù)據(jù)時(shí)的超時(shí)時(shí)間
            .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT) // 從連接池中獲取連接時(shí)的超時(shí)時(shí)間
            .build();
    builder.setDefaultRequestConfig(requestConfig);
    
    // 除了 GET、HEAD 之外,也自動(dòng)跟隨 POST、PUT 的 301、302 重定向。按需使用。
    builder.setRedirectStrategy(new LaxRedirectStrategy());
    
    return builder.build();
}

參考:

HttpClient Timeout

How to ignore SSL certificate errors in Apache HttpClient 4.4

如果需要自動(dòng)重試機(jī)制,可以看 這里

當(dāng) POST 遇上302,請(qǐng)看 這里

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/77729.html

相關(guān)文章

  • 一次OkHttpClient導(dǎo)致線程過(guò)多的排查

    摘要:首先先解讀下這個(gè)報(bào)警內(nèi)容,原因活躍線程數(shù)過(guò)多,是監(jiān)聽(tīng)的端口號(hào)用來(lái)獲取虛擬機(jī)各項(xiàng)信息,代表著此時(shí)的線程數(shù),是設(shè)置的報(bào)警閾值。 前言 前天,一位21世紀(jì)的好好青年正在工位上默念社會(huì)主義大法好的時(shí)候,釘釘上又報(bào)警了(公司項(xiàng)目接入了open-faclon監(jiān)控,指標(biāo)不正常會(huì)報(bào)警給釘釘?shù)臋C(jī)器人),無(wú)奈默默流淚揮手告別社會(huì)主義大法開(kāi)始定位線上問(wèn)題。 報(bào)警內(nèi)容 首先我們先來(lái)看下報(bào)警信息,為防止泄露公...

    tianyu 評(píng)論0 收藏0
  • 一次 JAVA 的內(nèi)存泄露分析

    摘要:展示如下場(chǎng)景再現(xiàn)經(jīng)過(guò)分析,最后我們定位到是使用產(chǎn)生的內(nèi)存泄露問(wèn)題。下面通過(guò)一個(gè),來(lái)簡(jiǎn)單講下具體內(nèi)存泄露的原因。這一次的內(nèi)存泄露問(wèn)題算是解決了??偨Y(jié)關(guān)于內(nèi)存泄露問(wèn)題在第一次排查時(shí),往往是有點(diǎn)不知所措的。 記一次 JAVA 的內(nèi)存泄露分析 摘要:本文屬于原創(chuàng),歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)保留出處:https://github.com/jasonGeng88/blog 當(dāng)前環(huán)境 jdk == 1.8 ...

    Tecode 評(píng)論0 收藏0
  • 串行還是并行?——一次 AsyncTask 問(wèn)題排查

    摘要:當(dāng)然,如果你的核心數(shù)夠多,到個(gè)線程的并行度不滿足的話,也可以自定義一個(gè)線程池來(lái)執(zhí)行,不過(guò)這樣的話,要注意自己維護(hù)這個(gè)線程池的初始化,釋放等等操作了。 事情起源于一個(gè)bug排查,一個(gè)AsyncTask的子類,執(zhí)行的時(shí)候發(fā)現(xiàn)onPreExecute方法執(zhí)行了,doInBackground卻遲遲沒(méi)有被調(diào)用。懂AsyncTask一些表面原理的都知道,onPreExecute方法是在主線程執(zhí)行,...

    mo0n1andin 評(píng)論0 收藏0
  • 一次排查線程引發(fā)Java DNS緩存的Bug

    摘要:?jiǎn)栴}描述最近通知應(yīng)用在近三個(gè)月內(nèi)出現(xiàn)過(guò)次緩存的問(wèn)題,第一次在重啟之后一直沒(méi)有出現(xiàn)過(guò)問(wèn)題,所以也沒(méi)有去重視,但是最近又出現(xiàn)過(guò)一次,看來(lái)很有必要徹底排查一次具體的錯(cuò)誤日志如下具體表現(xiàn)就是出現(xiàn)此異常之后連續(xù)的出現(xiàn)大量此異常 問(wèn)題描述最近通知應(yīng)用在近三個(gè)月內(nèi)出現(xiàn)過(guò)2次DNS緩存的問(wèn)題,第一次在重啟之后一直沒(méi)有出現(xiàn)過(guò)問(wèn)題,所以也沒(méi)有去重視,但是最近又出現(xiàn)過(guò)一次,看來(lái)很有必要徹底排查一次;具體的錯(cuò)...

    cocopeak 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<