睿文小說 > 兵法程式設計師:從小白到CTO > 第3章 深夜的計時器

第3章 深夜的計時器

⬅ 上一章 📋 目錄 ⚠ 報錯 下一章 ➡
⭐ 加入書籤
推薦閱讀: 花都風流第一兵王 代嫁寵妻是替身 天鋒戰神 穿越古代賺錢養娃 我覺醒了神龍血脈 我的老婆國色天香 隱婚嬌妻別想跑 遲遲也歡喜 全職獵人之佔蔔師

淩晨兩點,林夕的電腦螢幕上是密密麻麻的測試日誌。

他重新搭建了一個完整的本地測試環境——資料庫、快取、訊息佇列,甚至模擬了生產環境的網路延遲。彈窗功能本身已經沒問題,但趙磊那條微信像根刺,紮在腦子裏。

“三年前陳啟明離職前,最後一次提交就是改那裏。”

林夕開啟SVN的提交曆史,時間軸拉到三年前。會員積分係統的前端模組,最後一次大改動確實在2019年11月12日,也就是“雙十一”後的第二天。

提交人是Qiming.Chen。

他點開那個提交的差異檔案。改動很大,幾乎重構了整個兌換流程的前端程式碼。在兌換按鈕的點選處理函式裏,陳啟明加了一段注釋,用英文寫的:

`java

// WARNING: Async request chain may drop data under extreme concurrency.

// Need distributed lock or idempotent design. Temporary fix applied.

// TODO: Re-architect before next major promotion.

`

(警告:非同步請求鏈在極端並發下可能丟失資料。需要分散式鎖或冪等設計。已應用臨時修複方案。TODO:在下一次大型促銷前重構。)

林夕的目光落在“Temporary fix applied”上。這個臨時修複是什麽?

他繼續往下看程式碼。陳啟明在發起兌換請求前,增加了一個本地儲存的timestamp(時間戳),並把這個timestamp作為請求引數傳送到後端。後端會在處理請求時校驗這個timestamp,如果與上一次請求的時間戳過於接近(小於500毫秒),就拒絕重複請求。

這是一種簡單的防重複提交方案。但問題在於——這個時間戳儲存在瀏覽器的localStorage裏,而兌換成功後,程式碼裏並沒有清除它。

林夕在本地模擬了這個場景:使用者點選兌換,彈出廣告,確認後請求傳送。但如果使用者手快,在請求還沒返回時又點了一次兌換按鈕——這時候彈窗會再次彈出,但時間戳還是同一個,第二個請求會被後端拒絕。

這看起來沒問題,甚至是個安全的設計。

但接著,林夕發現了一個細節:陳啟明在程式碼裏設定的時間戳有效期是5秒。5秒後自動失效。這意味著,如果使用者第一次請求因為網路問題卡住了,5秒後他再次點選,會被視為新請求,而不是重複請求。

“那麽真正的bug在哪裏?”林夕自言自語。

他繼續往下翻,看到了陳啟明提交後的第二天,另一個提交記錄。提交人是Zhou.Kai。

這個提交隻有一行改動:把時間戳的有效期從5秒改成了60秒。

備注寫的是:“延長防重複提交視窗,避免促銷期間使用者體驗問題。”

林夕盯著這行改動,手指在桌麵上輕輕敲擊。

5秒改60秒。在普通場景下沒什麽區別,但在“極端並發”的場景下——比如“雙十一”零點,成千上萬人同時點選兌換——這意味著什麽?

他開啟計算器,開始推算:

假設兌換介麵的處理能力是每秒1000次請求。如果每個使用者因為彈窗、網路延遲等原因,在60秒內平均發起1.5次有效請求,那麽……

數字跳出來的瞬間,林夕明白了。

這不是bug。這是一個容差設計缺陷被一個臨時修複方案掩蓋,而這個臨時修複又被一個看似合理的引數調整削弱了效果。

陳啟明看到了根本問題,但來不及重構,隻能加個臨時補丁。周凱延長了補丁的有效期,讓它在非極端情況下更“友好”,但也讓它在高並發場景下更脆弱。

而這個“脆弱”的點,現在正要加上一個新的彈窗——一個會增加使用者等待時間、可能讓更多人重複點選的因素。

林夕看了眼時間,淩晨三點半。

他做了三件事:

第一,在本地模擬高並發場景。寫了一個指令碼,模擬1000個使用者同時點選兌換按鈕,其中30%的使用者會因為彈窗而誤操作二次點選。

第二,監控在這種情況下,後端的響應時間、錯誤率和資料一致性。

第三,檢查現有生產環境的監控資料,看看曆史上這個介麵在促銷期間的真實表現。

前兩個測試結果印證了他的推測:當並發量超過800時,錯誤率開始上升,出現了少數“兌換成功但積分未扣除”的資料不一致情況。

第三個任務遇到了障礙——他沒有生產環境監控係統的完整許可權。隻能看到最近7天的基本指標,曆史資料需要申請。

他寫了一份簡短的申請郵件,說明需要分析會員積分兌換介麵的曆史效能資料,用於評估新功能的影響。傳送給運維組的李工,抄送周凱。

郵件發出去時,窗外天色已經矇矇亮。

林夕趴在桌上睡了兩個小時。七點半,被手機震動吵醒——是李工的回複:

“小林,資料已發你郵箱。另外,提醒一下,那個資料庫單點故障的問題,我昨晚檢查了,確實如你所說。已經安排今晚淩晨三點做主從複製重建,屆時兌換功能會有幾分鍾隻讀。你的新功能上線最好避開這個時間。”

郵件附件裏有三年的監控資料圖表。

林夕用冷水洗了把臉,開始分析。

圖表很清晰地顯示了規律:每年“雙十一”“618”等大促期間,兌換介麵的錯誤率都會有一個小峰值。但最異常的是——三年前的“雙十一”,錯誤率並沒有特別高,反而是平穩的。從兩年前開始,錯誤率峰值纔出現。

那個時間點,恰好是陳啟明離職半年後。

他繼續往下翻,看到一張更詳細的圖表:介麵響應時間分佈。正常情況下,95%的請求在200毫秒內完成。但在高並發時,會出現一些“長尾請求”——超過5秒甚至10秒才返回。

而這些長尾請求,很多最終是失敗的。

林夕的腦海裏開始拚接碎片:

1. 陳啟明的臨時方案(5秒有效期)能cover住大多數長尾請求——如果請求卡住超過5秒,使用者重試會被視為新請求。

2. 周凱改成60秒後,長尾請求如果卡住,使用者重試會被拒絕,隻能幹等。

3. 但使用者不會幹等——他們會重新整理頁麵、重新進入,這會產生全新的會話和全新的時間戳,繞過防重複機製。

4. 於是,同一個兌換請求,可能在後端被處理兩次。

而資料庫的單點故障,會讓這種重複處理的問題雪上加霜——在高負載下,事務可能無法正常回滾。

九點,公司晨會。

林夕帶著黑眼圈走進會議室。周凱已經在了,正在和產品經理討論什麽,看到他時點了點頭。

會上,周凱特意提到了彈窗需求:“小林做得不錯,方案很細致,測試也通過了。今天上午走發布流程,趕在午間流量高峰前上線。”

產品經理是個短發幹練的女生,叫蘇晴,她問:“這個改動會影響兌換成功率嗎?下週我們有個小促銷。”

“理論上不會。”周凱說,“小林做了完整測試,對吧?”

所有人的目光看向林夕。

“功能本身沒問題。”林夕頓了頓,“但我昨晚分析曆史監控資料時,發現兌換介麵在高並發下存在一些長尾請求問題。彈窗會增加使用者等待時間,可能會放大這個效應。我建議,如果要在促銷期間上線,最好配合後端做一些優化。”

會議室安靜了幾秒。

“什麽優化?”蘇晴追問。

“比如在防重複提交機製裏,加入會話級別的鎖,或者把時間戳有效期調回原來的5秒。”林夕說得很謹慎,“這個需要後端配合,改動不大,但能降低風險。”

周凱笑了:“小林,你很嚴謹,這很好。但我們不能因為理論上的風險,就過度設計。現有的機製執行兩年了,沒出過大問題。這次隻是加個前端彈窗,不會影響後端邏輯。”

他說得有理有據,周圍幾個程式設計師點頭附和。

“可是監控資料顯示——”

“資料顯示的是過去的情況。”周凱溫和地打斷他,“這樣吧,你的擔憂也有道理。咱們折中:今天先正常上線彈窗功能,同時你寫個技術方案,提出完整的優化建議,我們下週評審。這樣既不影響業務,也能係統性地解決問題。”

話說到這個份上,林夕隻能點頭:“好。”

散會後,趙磊湊過來,小聲說:“你提陳啟明的方案了?”

“沒提名字,隻說了調引數的建議。”

“聰明。”趙磊拍拍他的肩,“那事兒是個敏感話題。不過……你真覺得會出問題?”

“不知道。”林夕實話實說,“但資料不會說謊。”

上午十點半,彈窗功能順利上線。發布過程很平穩,監控曲線一切正常。周凱在團隊群裏發了大拇指表情:“小林第一週就獨立完成需求上線,很棒。”

林夕盯著監控大盤,看著兌換介麵的實時資料。請求量、成功率、響應時間……所有指標都在綠色區間。

也許真的是自己多慮了。

下午,他按照周凱的要求,開始寫技術優化方案。檔案剛開了個頭,蘇晴忽然從產品區走過來,臉色不太好。

“林夕,有使用者反饋,兌換積分時彈窗出現兩次。你們前端是不是有什麽快取問題?”

林夕心裏一緊:“複現路徑是什麽?”

“使用者說,第一次點選兌換,彈窗出來,他點了確認。頁麵卡了一會兒,沒跳轉,他就又點了一次兌換按鈕,結果又彈出一個一模一樣的彈窗。”蘇晴把手機遞過來,上麵是使用者的反饋截圖,“第二次他點了取消,然後頁麵顯示兌換成功。但他查記錄,積分被扣了兩次。”

林夕接過手機,那股熟悉的寒意又從脊背爬上來。

“使用者操作時間間隔大概多久?”

“使用者說就幾秒鍾,他以為頁麵卡死了。”

林夕開啟自己的測試環境,開始複現。當他模擬網路延遲,讓第一次請求卡住5秒以上時——使用者第二次點選,確實會彈出第二個視窗。

而如果使用者第二次點了取消,前端邏輯會終止流程,但那個已經發出去的第一次請求呢?

它還在路上,正在前往那個單點故障的資料庫。

“我需要查一下這個使用者的資料。”林夕站起來,“可能需要後端配合。”

蘇晴點頭:“我已經通知後端負責人了。但……”她壓低聲音,“周凱說先別聲張,可能是使用者誤操作,讓我們私下查清楚再說。”

林夕看著她:“如果這不是個例呢?”

蘇晴沒說話。她的眼神告訴林夕,她也想到了同樣的可能性。

傍晚六點,林夕還在和後端的同事一起查日誌。那個使用者確實被扣了兩次積分,但隻有一條兌換記錄——另一條積分扣減,沒有對應的業務記錄,像是直接操作了資料庫。

更蹊蹺的是,兌換介麵的監控顯示,從下午兩點開始,錯誤率有微小的上升,從0.01%升到了0.05%。幅度很小,還在正常波動範圍內。

但林夕拉出了曆史同期對比——平時這個時間的錯誤率,通常在0.005%以下。

“會不會是發布後的正常波動?”後端同事問。

“可能。”林夕說,“但我想看一下更詳細的資料,比如錯誤型別分佈。”

“那個需要更高許可權,得找李工或者周凱批。”

林夕看了眼周凱辦公室的方向。燈亮著,門關著。

他拿起手機,又放下。

《孫子兵法·軍形篇》:“故善戰者,立於不敗之地,而不失敵之敗也。”

善於作戰的人,先確保自己立於不敗之地,同時不放過任何擊敗敵人的機會。

現在,他還不知道敵人在哪,甚至不知道敵人是不是真的存在。

但他知道,有些東西,已經開始轉動了。

而第一塊倒下的骨牌,可能已經被人輕輕推了一下。

隻是此刻,所有人都還沒聽見它墜落的聲音。

第 1 頁
⬅ 上一章 📋 目錄 ⚠ 報錯 下一章 ➡
升級 VIP · 無廣告 + VIP 章節全解鎖
👑 VIP 特權 全站去廣告清爽閱讀 · VIP 章節無限暢讀,月卡僅 $5
報錯獎勵 發現文字亂碼、缺章、內容重複?點上方「章節報錯」回報,審核通過立獲 3天VIP
書單獎勵 前往 個人中心 投稿你的私藏書單,審核通過立獲 7天VIP
⭐ 立即升級 VIP · 月卡僅 $5
還沒有帳號? 免費註冊 | 登入後購買