關於在接收POST請求,Tomcat偶發性接收到的引數不全問題排查分析

猿碼道發表於2018-01-29

1 問題描述

最近一直在搞每月一次的抽獎活動,併發量也比平時多了不少,隨之而來的,就是平時遇不到的一些問題。這也是可喜可賀的啊,有問題才能成長,沒有問題就是在浪費生命。

其中一個感覺比較奇葩的問題,就是:Tomcat在接收POST請求時,偶發性的POST引數接收不全,這個比例還很高。如下所示:

45應用伺服器正常POST引數獲取:

2016-05-19 15:45:15 INFO :request param : body=[{"appDevice":{"qdPlatform":"weixin","qdVersion":"1.4.1"},"activityId":80,"curPlanId":381,"memberId":"ff808081547ef0b401549f64e6cb2ecb","projectId":"31605061701144","prizeIds":[437,436,435,440,439,438],"planIds":[370,371,372,373,374,375,376,377,378,379,380,381,382]}]
複製程式碼

45應用伺服器不正常POST引數獲取:

2016-05-19 16:03:16 INFO :request param : 7D,"activityId":80,"curPlanId":381,"memberId":"ff80808150f0fdd401510f83cae413a9","projectId":"708","prizeIds":[437,436,435,440,439,438][370,371,372,373,374,375,376,377,378,379,380,381,382][370,371,372,373,374,375,376,377,378,379,380,381,382]=[]
複製程式碼

2 排查問題

排查問題之前,先理清服務架構,如圖:

理清服務架構

排查問題開始之前,簡單說下自己排查問題的幾個原則(僅供參考):

  1. 問題重現:一定要先重現問題,任何重現不了的問題,都不是問題。同理,任何存在的問題,都必然能再次重現。

  2. 由近及遠:先確認自己的程式碼無問題,然後再去確認外部程式碼無問題(如:框架程式碼,第三方程式碼等)。

  3. 由外到內:程式就是一個IPO,有輸入Input(如:引數、環境等)也有輸出Out(如:結果、異常等),輸出Out是問題的表象,先確定外部因素Input無問題,再確認程式程式碼邏輯無問題。

  4. 由淺入深:其實就是由易到難、自上向下,先從上層應用排查問題,如:上層API、應用層、HTTP傳輸等,然後再確認底層應用排查問題,如:底層API、網路層、系統層、位元組碼、JVM等;

  1. 確認在上面日誌輸出的程式碼中是否存在併發問題,或邏輯Bug:
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> keySet = parameterMap.keySet();
StringBuilder sb = new StringBuilder();

for(String key : keySet) {
    sb.append(key).append("=").append(Arrays.toString(parameterMap.get(key))).append(",");
}

log.info("request param : " + sb.toString()) ;
複製程式碼

通過上面的兩條日誌輸出,和以上程式碼的分析,可以得出以下結論:

  1. 以上程式碼不存在併發問題及邏輯Bug,POST引數是從原始request.getParameterMap()中獲取,獲取前後未做任何寫入、轉換處理;

  2. 通過不正常日誌輸出和以上程式碼邏輯來看,從request.getParameterMap()中獲取的引數,"body"這個Key已經丟失,且對於的Value也存在部分丟失,ParameterMap中的Key-Val混亂;

  1. 確認是否存在tomcat POST/GET引數長度限制,nginx POST/GET引數長度限制,導致請求引數截斷:

很快就排除了這種可能,因為引數不全是偶發性產生的,如果是由於引數長度限制導致請求引數截斷,而應該是100%產生引數不全的問題。

  1. 根據上面服務架構圖和由外到內的原則,通過tcpdump和Wireshark來分析,進入前端Nginx伺服器的請求引數是否存在不全:

Wireshark抓包分析

可以確認,使用者的請求從瀏覽器發出在到達Nginx之前,POST請求引數就已經丟失;

注意:想要了解更多tcpdump和Wireshark分析使用,請參考聊聊tcpdump與Wireshark抓包分析

3 解決問題

在上面排查問題的過程中,就已經確定了是使用者前端傳過來的引數問題,但從前端程式碼排查來看,其實也沒有發現問題,只是在前端做了個JSON序列化。所以為了避免問題再次發生,將前端序列化去掉,保持HTTP請求引數原始傳輸,由前端的代理服務再進行序列化後,提交給後端應用。

4 總結問題

其實對於問題的解決並不重要,有時或許只是一個空格、一個微小的配置等,重要的是在於問題的分析過程、分析思路,怎麼樣有個清晰的思路,快速的定位問題,才是解決問題的關鍵。

相關文章