由RestTemplate引發的加班慘案

前言

今天真是美好的一天呢,股市一如往常地綠,我一如往常地坐在辦公桌前敲代碼。

上級交給我一個刷新歷史數據的需求,一般刷新歷史數據可以採用的方式有SQL腳本以及定時任務。

以往大多數時候我都是採用SQL腳本的方式,因爲這次涉及接口的調用,於是打算使用後臺任務來實現。

本來很日常的一個任務,沒想到還會有意外的插曲。


過程

需求

根據新的業務邏輯修復歷史數據,就是更新某些表的某些字段。

這裏的業務就不詳細介紹了。反正與技術無關。


設計和實現

1、將 需要更新的主表的主鍵 通過腳本刷到臨時表,初始化爲待處理狀態。
(這樣做是爲了修復歷史數據時不影響到其他業務對主表的操作)

2、創建臨時定時任務,用代碼實現取數的邏輯,其中涉及兩次內部接口的調用

3、批量處理完數據後,更新主表數據以及臨時表的狀態。

4、將接口的調用記錄到臨時日誌表,主要字段有主表主鍵、接口標誌、發起請求時間、返回結果時間、返回數據


測試結果

上面的步驟一氣呵成,自以爲胸有成竹。當然開發機也有自測過了,流程是沒問題的。

於是提交給測試部進行測試,此時已經接近下班時間了。

結果測試告知數據跑着跑着就卡住了,待處理的數據量沒有繼續減少了。

想想心都涼了,這是要加班的節奏呀,於是連忙開始分析。

查看了臨時表,待處理的數據量確實沒有繼續減少了;

再查看臨時日誌表,按時間降序後,發現大多數接口的調用間隔時間都是毫秒級別的,但是極少數調用的間隔時間很長,大到幾分鐘。現在就是卡死不動了,也沒新的日誌產生。

那時候懷疑是邏輯問題,於是檢查了一遍,確實找不出問題,因爲本身這個任務的處理邏輯也不復雜。

於是我重啓了測試機的定時任務,發現又好使了。。。


分析

從日誌看確實沒打印有效的信息,這可能是我日誌埋點埋得不好。我的鍋。

根據這現象,在網上查找了一些資料以及和同事討論後,鎖定了一個方向,那就是跟請求接口有關的RestTemplate

在網絡上其中有一篇文章《記錄RestTemplate一個自己挖的坑》如下分析:
來自網絡
另外我單獨測了任務中所調用的接口,響應時間平均下來也是毫秒級別。

所以越來越確定是由於Http請求造成這次任務的異常。

查看了這次任務中使用的請求工具,也就是RestTemplate

以前倒沒怎麼注意這個小傢伙,這次找了一些關於它的資料。


解決

解決方法就是爲RestTemplate設置超時時間,避免過長的無響應連接所帶來的耗時影響。

連接失敗則斷開,再進行重連即可。

原先使用的默認RestTemplate
  <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" />

設置了超時的RestTemplate
  <!-- 同步restful,3s超時 -->
  <bean id="restTemplate3sTimeout" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
      <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <property name="readTimeout" value="3000"/>
        <property name="connectTimeout" value="3000"/>
      </bean>
    </constructor-arg>
  </bean>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章