週五晚上十一點,“星課堂”第一次全鏈路壓測。
會議室裏擠滿了人:楊帆、老陳、小雨、前後端開發、測試、運維。四塊大螢幕分別顯示著:伺服器監控、資料庫監控、應用日誌、壓測平台實時資料。
林夕坐在楊帆旁邊,手裏拿著壓測計劃書。這是他容災方案設計的第一場實戰演練——不是真的故障,而是模擬故障下的係統表現。
“各係統就位。”楊帆的聲音很平靜,“開始第一階段:正常流量峰值。”
測試工程師按下啟動鍵。壓測平台開始模擬使用者行為:登入、瀏覽課程、報名、觀看視訊、參加測驗、領取證書。使用者量從0開始爬升,1000,5000,10000……
監控螢幕上的曲線開始跳動。CPU使用率、記憶體占用、網路IO、資料庫QPS(每秒查詢數)——所有指標都在綠色區間。
“使用者量到三萬了。”測試工程師匯報。
“響應時間有變化嗎?”楊帆問。
“平均響應時間從50ms升到80ms,還在可接受範圍。”
“繼續加到五萬。”
使用者量繼續攀升。當到達五萬時,資料庫的CPU使用率跳到了70%,記憶體使用率到了85%。
“資料庫連線數滿了。”運維工程師匯報,“連線池設定的最大連線數是200,現在已經199。”
“應用側呢?”楊帆看向林夕。
林夕快速檢查使用者服務的監控:“使用者服務的執行緒池也快滿了,80%的執行緒在處理資料庫查詢。”
“瓶頸在資料庫。”楊帆說,“停一下。”
壓測暫停。所有人看向楊帆。
“這就是典型的設計問題。”他走到白板前,“你們把大部分業務邏輯都放在應用層,但資料層沒有做足夠的優化。使用者查詢課程資訊時,為什麽要連表查使用者和報名狀態?”
老陳解釋:“因為需要判斷使用者是否已經報名,才能決定顯示‘立即報名’還是‘繼續學習’。”
“這個判斷不能在前端做嗎?後端隻返回課程資訊和使用者報名狀態兩個獨立介麵?”
“可以……但那樣會增加一次請求。”
“增加一次請求,和拖垮資料庫,哪個代價大?”楊帆問。
沒人回答。
“第二階段。”楊帆說,“模擬資料庫主節點故障。”
運維工程師開始操作。幾秒鍾後,資料庫主節點的監控變紅了——連線中斷,QPS歸零。
幾乎同時,使用者服務的錯誤率飆升到30%。螢幕上跳出大量告警:資料庫連線失敗、查詢超時、事務回滾。
“降級策略生效了嗎?”楊帆問林夕。
“生效了。”林夕盯著監控,“使用者服務檢測到資料庫連線失敗,自動切換到降級模式:隻讀快取資料,寫操作排隊等待。課程列表和使用者資訊還能正常展示,但報名和證書生成功能已禁用。”
“快取命中率?”
“85%.剩下的15%請求返回‘服務暫時不可用’的友好提示。”
楊帆點點頭:“還可以。但快取資料可能過時,如果使用者看到自己沒報名的課程顯示‘繼續學習’,會投訴。”
“我們在降級頁麵做了明顯提示:‘資料可能延遲,部分功能暫不可用’。”林夕調出設計圖。
“好。恢複資料庫。”
主節點恢複,錯誤率迅速下降。但新的問題出現了:在資料庫宕機的兩分鍾裏,積壓了三千多個寫操作。現在資料庫恢複,這些操作開始並發執行。
資料庫監控再次報警:CPU使用率衝上90%,鎖等待數量激增。
“第三個問題:災後恢複時,積壓請求的洪峰。”楊帆說,“你們的佇列有做限流嗎?”
“沒有。”老陳承認,“我們以為降級就夠了……”
“降級是止損,不是解決方案。”楊帆轉向林夕,“你的容災方案裏,有提到這個問題嗎?”
“提到了,但還沒具體設計。”林夕快速翻看檔案,“我計劃用漏桶演演算法控製恢複時的請求速率,同時優先處理重要業務——比如支付成功回撥、證書生成。”
“把這個方案寫出來,下週評審。”楊帆說,“繼續第三階段:模擬某個微服務完全不可用。”
這次模擬的是證書服務宕機。證書服務負責生成和發放學習證書,是“星課堂”的核心賣點之一。
證書服務掛掉的瞬間,報名流程卡住了——因為使用者完成課程後,需要同步生成證書才能算報名成功。
“同步呼叫問題。”楊帆一眼看出症結,“為什麽要同步生成證書?不能非同步嗎?”
小雨解釋:“產品需求要求使用者完成課程後立刻看到證書,增強成就感。”
“立刻是多快?5秒?10秒?還是必須實時?”
“最好在3秒內。”
“那就用非同步,但給使用者一個‘證書生成中’的狀態,後台非同步處理,完成後推送通知。”楊帆說,“技術上,使用者完成課程後,先更新報名狀態為‘已完成’,然後發訊息到佇列。證書服務消費訊息,生成證書,再更新狀態為‘已獲證’。使用者可以立刻看到已完成,稍後收到證書。”
“如果證書生成失敗呢?”
“重試。超過重試次數轉人工。”楊帆看向林夕,“這也是你需要設計的部分——重要非同步任務的可靠投遞和補償。”
壓測繼續。第四階段模擬了網路分割槽:使用者服務能訪問資料庫,但不能訪問課程服務。第五階段模擬了快取雪崩:Redis集群全部重啟,快取全部失效。
每一個故障場景,都暴露出設計上的薄弱點。楊帆的問題像手術刀,精準地剖開每一個假設,每一個“想當然”。
淩晨兩點,壓測結束。所有人都筋疲力盡,但收獲巨大。
“今天暴露的問題,列成清單。”楊帆做總結,“每個人負責自己模組的整改。林夕負責整理全域性容災方案,下週三我要看到完整的設計和排期。”
散會後,人們揉著發酸的眼睛離開會議室。林夕還在整理監控資料,楊帆走過來:“今天表現不錯。發現問題很快,應對思路也清晰。”
“謝謝楊老師。”
“但還不夠。”楊帆看著他,“你今天設計的降級策略,都是基於‘我們知道哪裏會出問題’的前提。但真實的線上故障,往往發生在你最想不到的地方。”
他頓了頓:“你知道三年前積分係統事故,最根本的教訓是什麽嗎?”
林夕心裏一動:“是什麽?”
“不是資料庫單點,不是沒有降級。”楊帆說,“沒有人敢做決定。當監控告警時,值班的人不敢切流量,不敢降級,不敢回滾,因為沒人授權。他們一層層打電話請示,等領導決策——但故障不等人。”
“所以您的意思是……”
“容災方案裏,不僅要設計技術措施,還要設計決策機製。”楊帆說,“明確什麽情況下,誰可以做什麽決定,許可權是什麽,責任是什麽。而且這些要寫成檔案,全員培訓,定期演練。”
林夕明白了。這是比技術更深層的問題:組織能力。
“我會加進去。”
“好。”楊帆拿起包,“對了,下週一,海量資料的人來做技術分享,在孵化部。你可以聽聽。”
“他們不是已經在技術部分享過了嗎?”
“這次是專門針對孵化部的新專案。”楊帆意味深長地看了他一眼,“周凱推薦的,說他們的分散式資料庫很適合咱們這種從零開始的專案。”
林夕心裏一緊。海量資料的手,伸到孵化部了?
“好了,早點回去休息。”楊帆拍拍他的肩,“路還長,別把身體熬垮了。”
楊帆離開後,林夕一個人在會議室坐了很久。螢幕上的監控資料已經歸零,但那些跳動的曲線還在他腦海裏回放。
他開啟電腦,開始整理今天的發現。寫檔案寫到淩晨三點,眼睛發澀,大腦卻異常清醒。
關掉電腦,走出公司。深夜的街道空無一人,隻有路燈投下孤獨的光圈。他走到常去的便利店,買了個飯團,坐在窗邊的高腳椅上吃。
手機震動,是陳啟明回複的郵件——距離他上次回複已經一週。
“林夕,抱歉現在纔回。最近在忙一個新專案。
看了你提到的容災設計,方向是對的。但我想提醒你一點:任何容災方案,最終都要麵對一個殘酷的現實——資源有限。
你可以設計完美的降級、熔斷、限流、切換,但當真正的災難發生時,你可能沒有足夠的機器、頻寬、人力來執行這些方案。那時候,你要做的是選擇:保核心業務,棄邊緣業務;保新使用者,棄老使用者;保收入,棄體驗。
這些選擇,在技術檔案裏往往被美化。但真實情況是,每個選擇背後都有代價。
所以,在設計容災時,不要隻想著‘怎麽讓係統不掛’,要想著‘如果一定要掛,怎麽掛得損失最小’。
另外,關於海量資料:我在新加坡這邊也聽說過他們。技術不錯,但還年輕,沒有經過大規模生產的長期考驗。如果你們要用,建議從小場景開始,別一上來就替換核心資料庫。
祝好。
陳啟明”
林夕看著郵件,慢慢嚼著飯團。米粒有點硬,海苔有點潮。
陳啟明的話像冷水,澆醒了他因為今天“成功”演練而產生的些許興奮。是啊,資源有限,選擇殘酷。他設計的那些完美方案,真到了生產環境,可能要大打折扣。
而海量資料……周凱在技術部推,現在又推薦給孵化部。是真的看好技術,還是有別的考慮?
他吃完最後一口,收拾垃圾準備離開。便利店的門開了,進來一個人——是張維。
兩人都愣了一下。
“這麽晚?”張維先開口,走到冰櫃前拿了一瓶水。
“剛加班做完壓測。”
“楊帆的壓測?”張維擰開瓶蓋,“聽說很魔鬼。”
“是挺魔鬼的,但學到了很多。”
張維點點頭,付了錢,卻沒走。他靠在收銀台邊,看著窗外空蕩蕩的街道:“海量資料的分享會,楊帆跟你說了吧?”
“說了,下週一。”
“會去吧?”
“會。”
“嗯。”張維喝了口水,“聽聽也好。不過記住,技術分享會上的資料和真實生產環境的資料,可能是兩回事。”
這話裏有話。
“張總……張維,”林夕改口,“您對海量資料怎麽看?”
張維笑了笑:“我是投資部的,看任何公司都先看三樣東西:團隊背景、技術壁壘、商業模式。海量資料這三樣都不錯,所以我們在接觸。”
“那風險呢?”
“風險?”張維看著他,“最大的風險,不是技術不行,而是人。初創公司為了拿訂單,什麽承諾都敢做。大公司為了出成績,什麽風險都敢冒。兩邊一碰,就容易出事。”
他說得很直白。
“周凱在積極推動這件事。”林夕試探道。
“我知道。”張維放下水瓶,“他需要亮點,為年底晉升做準備。引入顛覆性技術解決曆史包袱,是很漂亮的成績單。”
“但積分係統還沒重構完成……”
“所以要先在你們孵化部試點啊。”張維笑了,“新專案,新架構,沒有曆史包袱,成功了就是範例。然後再推廣到技術部的老係統,順理成章。”
林夕明白了。孵化部成了試驗田。成功了,功勞是周凱的;失敗了,責任是孵化部的——畢竟新專案有風險是正常的。
好一局棋。
“這些話,本來不該跟你說。”張維看著林夕,“但我覺得,你有權利知道自己在什麽樣的棋局裏。”
“為什麽告訴我這些?”
“因為三年前,沒人告訴陳啟明。”張維的聲音低了下去,“等他明白時,已經來不及了。”
便利店的門又開了,進來幾個夜班結束的年輕人,吵吵鬧鬧地買啤酒。
張維直起身:“我走了。你自己小心。”
他推門出去,消失在夜色裏。
林夕站了一會兒,也離開了便利店。走在回出租屋的路上,腦海裏反複回響著今天聽到的話:
楊帆說:“真實的線上故障,往往發生在你最想不到的地方。”
陳啟明說:“如果一定要掛,怎麽掛得損失最小。”
張維說:“你有權利知道自己在什麽樣的棋局裏。”
還有那些監控螢幕上跳動的曲線,那些模擬故障下的係統呻吟,那些設計檔案裏看似完美但可能脆弱的假設。
他抬頭看天。城市的夜空看不到星星,隻有厚重的雲層,映著地麵的光。
快下雨了。
他想。
而他,這個剛在孵化部站穩腳跟的新人,已經不知不覺間,被推到了另一場風暴的邊緣。
這一次,風暴的名字不叫“曆史問題”,而叫“新技術引進”。
但他知道,本質上是一樣的:都是利益、風險、責任、選擇的博弈。
回到出租屋,他開啟電腦,在容災方案的最後加了一章:
“第八章:組織與決策
1. 明確各級故障的決策許可權和響應流程。
2. 建立故障演練製度,每月至少一次。
3. 所有關鍵操作的SOP(標準作業程式)檔案化。
4. 故障後的複盤必須包含技術和管理兩個維度。”
寫完,他儲存檔案。
窗外的雨,終於開始下了。
淅淅瀝瀝,打在玻璃上。
他看著雨滴滑落,想起《孫子兵法》裏的一句話:
“知彼知己,百戰不殆;不知彼而知己,一勝一負;不知彼,不知己,每戰必殆。”
現在,他知道了一些“彼”——海量資料的潛在風險,周凱的動機,張維的提醒。
也知道一些“己”——自己在設計容災方案,在楊帆手下學習,在孵化部立足。
但還不夠。
遠遠不夠。
因為真正的戰場,從來不是明麵上的。
而是那些決策會議、技術評審、資源分配、功勞歸屬的暗處。
而他現在,才剛剛摸到那個戰場的邊緣。
雨越下越大了。
他關掉電腦,躺到床上。
閉上眼睛,卻睡不著。
腦海裏全是今天壓測時的監控曲線,那些跳動的數字,那些報警的紅點。
像某種預兆。
像線上的幽靈,在係統深處遊蕩。
等待著,某個時刻,
現身。