兩個流程鏈路問題的排查和總結

程式設計一生發表於2020-09-21

兩個流程鏈路問題的排查和總結

亂碼問題

 

現象

 

 

在一類簡單的業務場景下發起http請求的測試案例,返回的時候會100%有亂碼。如果跳過跟廠商定製的7層負載均衡裝置,直接連後端一臺機器,則100%無亂碼。在其他測試場景,則100%無亂碼。

 

注意,此處的100%是那段時間實際發起請求的情況中亂碼的佔比,與SLA無關。

 

 

大家猜一猜,產生亂碼的原因在哪一層?

 

處理過程

首先自證清白,我負責處理1。直連是無亂碼的。其他場景是無亂碼的。程式碼和線上穩定執行的版本是一套,線上是無亂碼的。這個場景和其他場景唯一不同的是返回資料的模板是放在測試資料庫中的。所以我將測試庫中的模板換成其他無亂碼場景的資料(避免編碼問題,直接拷貝),仍然不起作用。將模板資料改成12,也能返回一個亂碼。所以亂碼應該是和[處理1]程式無關。

 

與自己這邊無關,再看是上游的問題還是下游的問題?

 

下游[處理2]是新邏輯,像SSL和處理3都是線上穩定執行的。但是從日誌裡看,通過[處理1]的時候還不是亂碼,只是回到發起端才有亂碼的,說[處理2]有問題不合邏輯。

 

上游[跟廠商定製的7層負載均衡裝置],因為有兩個場景的對比,所以還是有理由找負責的同事查一查的。他們調查的結果是沒有地方進行編碼轉換。

 

再往上游[案例發起端],要證明和案例發起模擬程式本身有沒有關係。因為是http請求我採用直接將請求頭和body使用在其他伺服器上使用curl模擬請求的方式,結果與案例平臺的結果一致:使用7層負載均衡裝置會有亂碼,不使用則無亂碼。看來與模擬程式本身無關。

 

我們團隊內部也有一個模擬工具,可以模擬請求,將http請求的body體複製進去,無論是否使用7層負載均衡裝置都沒有亂碼。

 

我們團隊內部模擬工具和案例發起端的區別 應該在請求頭上。這時我注意到了http請求頭的引數,裡面有accept-encoding: gzip, deflate, br 。將這個引數去掉,果然無論是否使用7層負載均衡裝置都沒有亂碼。

 

分析

通過處理過程,瞭解到問題原因是如果設定了accept-encoding: gzip, deflate, br。返回的資料在7層負載均衡裝置會有處理。導致亂碼。我看了他們的官網,使用的裝置是支援gzip壓縮解壓的。

 

 

我猜測是它將沒有加密的請求作為gzip解密處理了。找到7層負載均衡裝置廠商的技術支援。已經將問題反饋給他們,請他們確認是根據哪個請求引數來確認是否加解密的。

 

這個問題更合理的步驟應該是這樣:

 

亂碼問題核心是要確認引起亂碼的變數:有可能是一個引數,也有可能是一個系統內部問題。

 

使用案例平臺發起請求亂碼,然後使用我們團隊內部模擬工具發起相同的請求不是亂碼。這樣可以定位和案例平臺的某個變數有關係。變數分為引數和系統。使用curl代替系統自動發起來驗證是否和系統有關。

 

使用curl模擬案例平臺的請求亂碼。使用curl模擬我們團隊內部模擬工具發起相同的請求不是亂碼。確認和系統無關,問題在引數上。

 

找到兩個請求引數的差異,其中一個差異在accept-encoding上,並且這個引數和編碼有關。調整這個引數,確認相關性。

 

socketTimeOut問題

 

現象

 

 

測試案例發起端和執行程式分佈在兩個機房,有防火牆。已經請網路組的同事將鏈路中的機器對應埠的防火牆開啟。但是發起的請求,有大約80%可以正常執行返回結果。另外20%直接返回socketTimeout,在[處理1]上確認,並沒有收到請求。

 

大家猜一猜,問題出在哪一個環節?

 

處理過程

首先自證清白,我負責處理1。從日誌上看沒有收到請求並不能證明請求沒有到達,因為有可能是在請求在排隊,沒有到達處理環節就直接被丟棄了。因為用的是jetty,所以首先調大work執行緒數。再次發起請求,失敗比例沒有變化。用top命令檢視cpu、mem使用都很低。執行中執行緒數遠遠低於設定的work執行緒數閾值。調大jvm記憶體再次發起請求,失敗比例沒有變化。所以socketTimeout的請求應該沒有到達[處理1]。

 

如果[處理1]沒有收到,則一定不是下游的問題。要向前來排查。在之前沒有經過防火牆的時候,併發量更大的情況下,都可以正常處理,應該與7層負載均衡裝置無關。

 

再看防火牆這一層,部分請求不正常,是否是限流造成的?搜尋了一下防火牆的相關文件,防護牆是可以配置限流策略的。所以諮詢了配置防火牆的同事,回覆說沒有限流策略。

 

再往前看發起端。查到發起端共10臺機器。用linux命令grep socketTimeout | wc -l 發現異常主要集中在其中兩臺機器上。將請求數和socketTimeout數做對比,發現這兩臺機器都是失敗的。並且這兩臺機器與其他機器是不同的網段。

 

禁用了有問題的兩臺機器,問題解決。

 

分析

通過處理過程,問題已經很清楚了。部分網段網路不通。這個問題的更合理的排查步驟應該是這樣:

 

案例發起時返回socketTimeout,那先要判定到底是什麼問題。因為socketTimeout有兩種可能。一種是網路不通,一種是等待超時。如果從找出問題根因這個角度出發,從一開始就應該先看案例發起的機器與連線方網路是不是通的。如果使用的是ansible運維工具,可以用下面命令批量檢視

ansible -i  hosts XX -m shell -a "curl http://XXXX:8080/健康檢查介面 --connect-timeout 5"

 

 

這樣很快就能診斷出問題原因。

 

總結反思

在兩個問題的處理過程一開始,都是以自證清白開始的,而不是以解決問題開始的。我在反思這個思路是不是存在格局上的問題。

 

之所以以自證清白開始,是出於兩方面的考慮。第一,吃過虧。我之前總是解決問題就好,把問題查清楚了,但是本著有問題大家一起擔的原則,結果很多問題責任都被算在我們團隊身上。這樣會造成我們團隊總有問題的表象。第二,我也剛做這個專案,很多環節並不清楚。對最終能不能解開這個問題也沒有信心。所以至少要證明自己團隊沒有問題。

 

先來分析一下自己的兩點考慮是否是正確的思路。對於第一點,達則兼濟天下,窮則獨善其身。首先需要先讓別的團隊對我們團隊建立信任。如果不是我們團隊的問題,是一定需要明白的表述清楚的。有個詞叫:現實理想主義者,看網上意思說要胸懷理想,但是接受現實。用在這件事上,我理解就是自己心懷著有問題是大家一起的問題,一起解決就好這是對的理念,是要堅持的。但是為了實現正確的理念,方法是問題事實結論還是要擺清楚。讓別人對自己或自己團隊建立信任和影響力。

 

對於第二點,我所謂的自證清白實際上不能證明清白。這兩個問題,特別是第一個問題,據說在我來這邊之前很久了,一直沒能解決。很大一個原因是大家都認為自己這邊沒有問題,所以就不管了。所謂的沒有問題有可能是自己的知識盲區,只有真正找到唯一的真相,才能證明清白。

 

所以總的來說要做到兩點:第一:一開始就要以查清楚問題為目標。第二:查清楚問題之後要把結論讓大家知道,建立好自己團隊的形象。

 

這個認知的明確和排查問題的快慢有直接的關係。如果兩個問題不是從先看自己的部分開始向外輻射,就能運用更科學的流程來解決,速度會更快。如果一開始就以整體大局的思路來看問題,在整個鏈路上花的時間會更均勻,而不是偏重於自己負責的專案。對整個鏈路的理解會更清晰深刻。這也是格局對人的結果產生重大影響的原因之一吧。

相關文章