記一個騰訊信鴿引發的線程卡死問題

一天公司的遊戲有大量玩家報自動戰鬥、種植等操作無法進行,第一時間想到可能是因爲玩家的定時任務線程卡死了。用jstack查看線程堆棧日誌,發現都卡在了一個http read的地方。

公司使用騰訊信鴿做手遊的系統推送,卡住的地方就是調用信鴿的服務端sdk向信鴿服務器發送http請求,並等待迴應的時候。

因爲是調用第三方jar包,所以無法直接設置讀超時。在網上搜索到一種方法是通過系統變量設置超時時間:

 System.setProperty("sun.net.client.defaultReadTimeout", 3000);

測試過有效之後上線。

本以爲萬事大吉了。結果過了一段時間又報出大量玩家無法自動戰鬥,後面一看還是這個問題。

說明設置的系統變量並未生效。

於是在線下詳細測試,發現一個奇怪的問題:在兩個不同的工程中設置這個系統變量,一個是有效的,一個是無效的。

不過能夠復現問題就是件好事。查看堆棧對應的jdk源碼,發現是sun包下的,不開源。再找到openjdk源碼,研究後發現是NetworkClient的static代碼塊的執行時機的問題。

原來java在第一次生成http請求時,會從系統變量sun.net.client.defaultReadTimeout讀取默認讀超時時間並放在緩存裏,以後即使修改了這個系統變量,也不會影響默認讀超時時間了。

知道了問題的原因,那就知道解決辦法了:將默認讀超時設在程序的起始位置,或者啓動腳本中

後面向騰訊信鴿寫郵件反映這個問題。在最新版的SDK中看到已經得以修正。

總結:

  1. 使用http請求一定要設置連接超時和讀超時,否則網絡一出問題就會卡死。
  2. 在涉及第三方類庫時使用單獨的線程池,與業務線程池分離。因爲你永遠不知道里面會有什麼未知的問題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章