1、昨天線上出了個問題:我們線上的一個爬蟲任務一直沒有執行完畢,導致後面其他的任務跑的數據出錯。發現問題之後,立刻找運維幫忙dump線上機器的日誌來看:

我們可以看到線程的狀態還是runnable,然後看下線程的是阻塞在了socketRead0,因為之前有遇到過類似的問題就是MySQL的查詢語句,從線程池中拿連接的時候沒有校驗連接的有效性導致拿不到連接,然MySQL的連接超時時間是默認的8小時。導致任務一個無效的線程,拿阻塞了8個小時才斷開連接,問題當然是毀滅性的了。當然缺少有效性的校驗和超時時間的設置是必要的,但是任務的監控添加也是有必要的。這個後面在說。

今天發生的這個問題是由於DefaultHttpClient這個不推薦使用的客戶端引起的,具體我們項目中的代碼是這樣使用的:

問題就出在這句上面:get.setConfig(RequestConfig.custom().setConnectTimeout(Constant.TIMEOUT)

                .setSocketTimeout(Constant.TIMEOUT).build());//10秒鐘超時時間

這個超時時間的設置是不對的。我們跟著源碼進去,我這里貼出非重要的路徑:

當我們跟著源碼到DefaultRequestDirector的exectue的方法的時候就差不多要切入正題了。下面咱們具體看看一個特別重要的方法tryConnect,他裡面給我們會設置連接的超時時間等資訊。

tryConnect是一個內部方法,先檢查是否當前連接是否是開啟的,沒有就會開啟,進入到這個open方法中。

可以看到連接是有的上一個方法返回的open屬性的值是false。那麼就去開啟這個連接。結合上一步我們可以知道這個方法是需要設置超時時間等資訊的。同事我們也可以看到poolEntry連接池中的資訊,創建時間就是我Test啟動的時間,超時時間是個特別大的值。

開啟的時候最終會走到PlainSocketFactory:

你會發現他是從HttpParams params裡面取值的。而不是我們代碼中設置的樣子。

到此問題找到了,具體的解決辦法有沒有呢,當然有啊,而且還不只一個:

解決辦法:

1.用下面的這種方式設置參數就是OK的啦。因為她就是按照下面的方式取值的么。

2.第二種不用這個廢棄的方式了。這種方式呢大家猜也難能猜到了,她設置值的時候是直接加載的config,就是咱們構造的這個socketConfig啦。大家有興趣就跟進源碼中去看看了。

第二章fa

debug源碼真的很爽。