nginx負載下站點錯誤響應會導致其他節點重復響應問題的解決過程

前言:

這是我上周工作過程中的一次解決問題的過程。解決的是nginx負載下站點錯誤響應導致其他節點重復響應。 我在整理這個記敘文時,在給這個文檔命名時思考了一段時間。 從業務角度說,應該是“一次短信重復發送問題解決過程”,如果這樣命名,過于土氣;從技術角度說,應該是“nginx負載下站點錯誤響應會導致其他節點重復響應”,如果這樣命名,可能沒人會注意了;最后,我懶得再費腦汁了,從人類智慧的角度我把它命名為“復雜的問題,簡單的解,小處不謹慎,”。

問題來了

3月16日,有客服、銷售、運營人員反映,客戶在saas預定機票完成后,會連續收到3條重復的支付提醒短信。 ?很多客戶都投訴了這樣的問題,一直以來的正常情況是僅發1條的。

以下是短信平臺上的截圖:

前一天的3月15日是上線日,當晚saas上過線。

迫于壓力,當天下午不得不回滾3月15日的上線。回滾之后,問題不再重現。

3月15日saas的上線包括錦如和劉濤對saas所做的代碼改動。劉濤涉及到的代碼是審批接口,稱可能不會導致這樣的問題,錦如也肯定地表示不涉及到這塊。 我讓劉濤來排查原因,他在測試環境做了幾次測試,并未發現這樣的問題。我呢,由于最近忙于另一個項目,一直沒來得及親自和他一起查找原因。

問題又來了

3月17日是周四,上線日。要發布中新融創的對接程序。 晚上上線后,立即在線上訂票,發現訂單支付提醒短信還是會重復發3遍。

當時已經是晚上21點,我決定放下手頭的活兒,來跟劉濤一起排查原因。

問題分析

客戶在saas站點里預定機票,涉及到審批。審批是獨立的一個站點。

訂單的審批邏輯是這樣的:客戶在saas訂票成功后,會跳轉到統一審批頁,提交審批后,統一審批系統會把審批狀態通知給saas,然后重定向頁面到訂單流的下一個頁面(由saas提供)。

Saas提供了一個由一般處理程序(文件是HandlerAirOrderExamineStatus.ashx)實現的接口,用來接收審批狀態。內部大致邏輯是,修改訂單的審批狀態,然后會觸發相應的對客提醒短信。 客戶重復收到的短信是支付提醒短信,那么,意味著訂單不需要審批。不需要審批在系統里表現在這些企業配置審批流。 根據現有代碼邏輯,從填單頁跳轉到統一審批頁,統一審批頁初始化時沒有獲取到新審批,則會自動執行通知saas和頁面重定向。

要補充說明一下的是,線上的審批站點和saas站點均是通過nginx做的3臺服務器的負載。

通過查看線上日志,審批系統正常,即只會在其中一臺服務器節點來請求saas接口進行審批狀態的通知,并未發現異常日志。而saas呢,卻發現3臺服務器都記錄了同樣的日志。

為什么會出現這樣的情況呢? 審批在通知saas時,nginx接收到請求后應該分發給其中一個節點服務器來處理請求才對呀。

困惑

因為之前系統運行都是正常的,并未出現這種短信重發的情況,所以我們暫先不懷疑代碼邏輯。

馬上想到,記得運維說過,如果一個服務器處理時間超長,會自動分發給另一個節點服務器。 歷史原因,獲取訂單詳情和觸發短信通知這兩段代碼執行比較慢,那么,我在這兩段代碼外面加了個Stopwatch來診斷其執行時長。

publicvoidProcessRequest(HttpContext context)

{

Stopwatch sw=newStopwatch();

sw.Start();if(context.Request.Params.Count ==0)

{

context.Response.Write("{'returnCode':'2','returnMsg':'no parameters','notifiedSMSContent':'no parameters'}");return;

}stringparametersStr = context.Request.Params[0].AsToString();

SysLogToFile.WriteAuditMessage("dat修改訂單狀態傳入參數_"+parametersStr);//下面的是200行邏輯代碼,包括獲取訂單詳情和觸發短信通知...... ...... ...... ...... ...... ...... ...... ......

...... ...... ...... ...... ...... ...... ...... ......

...... ...... ...... ...... ...... ...... ...... ......

sw.Stop();

SysLogToFile.WriteAuditMessage("審批接口響應時間"+ (sw.ElapsedMilliseconds /1000));stringreturncode, returnmsg;if(flag)

{ returncode="1"; returnmsg ="success"; }else{

returncode="2"; returnmsg ="fail";

}

context.Response.Write("{'returnCode':'"+ returncode +"','returnMsg':'"+ returnmsg +"','notifiedSMSContent':'"+ returnmsg +"'}");

}

發布后經測試,發現3個節點的執行時長都長達7~8秒。

那么,我們接下來就優化程序吧,以期把duration降到最小。20分鐘后,我們把優化的代碼再發布到服務器。發現處理時間已經下降到了1~2秒。

然而,響應時間已經都優化到2秒了,依然是3個服務器節點上都做了處理。這帶給我們的是一個更大的問號。

轉機

為什么會有一個更大的問號呢? 因為我們線上的系統都是分布式部署的,一個流程邏輯會涉及到多個系統之間的交互訪問。 每個系統都是通過nginx做的3個節點的負載,并沒有出現過這種一個請求被3個服務器節點同時響應的情況。

在這種情況,我的一貫做法是釜底抽薪。當然,這次我依然堅持釜底抽薪。

Q:釜底抽薪是什么方式呢?

A:把接口里的代碼都注釋掉。響應時間應該接近于0毫秒,難道還會出現3個節點都響應的情況?

于是,我們注釋掉所有邏輯代碼,只保留了最后的輸出(context.Response.Write)語句,發布到服務器。

由于我們每次的測試步驟是:登陸saas,選擇航班,然后訂票下單,再看日志,這一系列的操作很耗時間,同時給線上系統帶來了很多無效訂單(垃圾數據)。這次呢,我讓劉濤直接訪問那個通知接口地址來測試性能。

轉機來了,在ie里直接訪問那個接口時,頁面直接拋出了大黃頁,報“System.FormatException:輸入字符串的格式不正確”,是由主方法里最后的這條語句產生的:

context.Response.Write(string.Format("{'returnCode':'{0}','returnMsg':'{1}','notifiedSMSContent':'{2}'}", returncode, returnmsg, returnmsg));

即在string.Format方法里,你是不能亂用‘{’的~。

于是,修復后(改成字符串拼接了)再次上線。

再次訪問那個接口,返回正常了。

這時,最大的驚喜是,只有一個服務器節點處理了請求,短信重發3次的問題得到了根治。

這時,我才想起來,nginx在接收到請求后,會分發給多個服務器節點中的一個節點來處理請求,但是,當出現錯誤響應時,nginx會自動分開給另一個節點來處理,直到沒有節點可供分發,即直到所有可用節點都被分發為止。(當然,這可能是我們運維對nginx的配置策略)

后續

我們解決完這個問題,已經午夜23:40,如釋重負的打車回家了。

在回去的路上,我的腦子像過電影似的過了一遍我們這一晚的處理過程。

l? 復雜的問題,在你用心解決時,往往產生自很簡單的一行代碼。很戲劇性的是,這行代碼可能是你不經意的疏忽寫錯了,也可能是技能受限寫錯的。如果,有做簡單的測試,這樣的問題完全是可以在開發時被發現的,而不至于花費那么長的時間來。

l? 另外,我又想到,審批系統調用接口時難道沒有判斷響應結果就做下一步的重定向了?這個疑問在第二天咨詢劉濤時得到了肯定。這樣的實現不夠嚴謹,于是,我讓他加上對結果的判斷。 如果事先有這個判斷,那么,這樣的問題在審批請求時就會被發現的,何至于經歷那么漫長的排查過程呢。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,818評論 18 139
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,740評論 24 1,002
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,330評論 11 349
  • 《老男孩Linux運維》筆記 隱藏Nginx軟件版本號 一般來說,軟件的漏洞都和版本有關。因此要盡量隱藏對訪問用戶...
    Zhang21閱讀 3,667評論 0 28
  • 丙申中秋,依舊客居江南,本欲邀月同飲,卻逢一場秋雨,作此詞以抒懷。 江南客醉他鄉路,乍寒夜,西風舞。 舊庭新顏花簇...
    南宮曉寒閱讀 440評論 0 1