測試環境的搭建花了三天。
海量資料那邊派來了一個技術支援工程師,叫小劉,看起來也就二十七八歲,戴著黑框眼鏡,話不多但幹活利索。林夕和他一起在公司的測試機房部署了三節點的集群,配置和未來生產環境完全一致。
週五下午,環境終於跑通了。小劉在控製台執行了幾條命令,確認所有節點狀態正常,資料同步正常。
“可以開始測試了。”小劉說,“我們提供的benchmark工具在/opt/benchmark目錄下,檔案在這裏。”他遞給林夕一個U盤。
林夕接過U盤,插入電腦。檔案很詳細,從基礎效能測試到壓力測試,從一致性驗證到故障恢複,都有現成的指令碼和說明。
但他沒打算直接用。
“謝謝,我們先自己寫測試用例。”林夕說,“這樣更能模擬我們真實的業務場景。”
小劉愣了一下:“自己寫?那會慢很多。我們的工具已經覆蓋了大部分場景……”
“我們需要測的不隻是通用場景。”林夕開啟自己寫的測試計劃,“還有我們業務特有的資料模式和訪問模式。”
小劉看了看計劃書,眉頭皺了起來:“異常操作模擬、網路分割槽、髒資料處理……這些在生產環境中都會盡量避免吧?”
“但難免會發生。”林夕說,“我們要知道當意外發生時,係統會怎麽樣。”
小劉沒再堅持:“好吧,有需要隨時找我。”
他離開後,林夕和老陳、小雨開了個小會。
“測試分三個階段。”林夕在白板上畫圖,“第一階段,功能驗證:確保所有基礎CRUD操作正常,事務ACID特性符合預期。第二階段,效能壓測:模擬真實業務負載,評估吞吐量、延遲、資源消耗。第三階段,容錯測試:模擬各種故障,觀察係統行為和恢複能力。”
“時間呢?”老陳問。
“功能驗證三天,效能壓測一週,容錯測試五天。總共兩周半。”林夕說,“下週五先出第一階段報告。”
“周凱那邊催得挺緊的。”小雨提醒,“他希望月底前能有初步結論。”
“月底是下週三,我們隻能給到第一階段報告。”林夕堅持,“效能資料不全,不能下結論。”
老陳點頭:“就按林夕說的。技術評估不能趕時間。”
分工確定:林夕負責所有測試用例編寫和執行,老陳負責監控資料收集,小雨負責記錄使用者體驗層麵的發現。
週末,林夕加班寫測試程式碼。他沒用海量資料提供的工具,而是用公司內部的測試框架,自己模擬業務請求。使用者註冊、課程瀏覽、報名、學習記錄、證書生成——每一個業務流程都寫成自動化測試用例。
他寫得極其細致,連“使用者註冊時網路超時重試”“並發報名同一課程”“證書生成服務宕機後恢複”這些邊界情況都覆蓋了。
寫到週日晚上的時候,他已經完成了兩百多個測試用例。眼睛酸澀,肩膀僵硬,但他沒停。
因為每寫一個測試用例,他就在想:如果這個環節出問題,使用者會怎麽樣?業務會損失什麽?係統能自己恢複嗎?
這些問題讓他保持清醒。
週一,第一階段測試正式開始。
測試機房裏的三台伺服器開始轟鳴。監控螢幕上,CPU、記憶體、網路、磁碟的曲線開始跳動。
林夕坐在控製台前,一行行日誌滾動過去:
`
[INFO] 測試用例001:使用者註冊_正常流程_通過
[INFO] 測試用例002:使用者註冊_重複手機號_返回錯誤
[INFO] 測試用例003:使用者註冊_非法手機號格式_返回錯誤
`
前一百個測試用例都很順利。海量資料庫表現穩定,響應時間在預期範圍內。
下午兩點,測試進行到“並發報名”場景。模擬一百個使用者同時報名同一個熱門課程。
第一個測試輪次通過。但第二個輪次,林夕發現了一個異常:有兩個使用者的報名請求,返回了“操作成功”,但在資料庫裏隻找到一條記錄。
他立刻暫停測試,檢查日誌。
日誌顯示,兩個請求幾乎同時到達(時間戳相差不到10毫秒),都被資料庫接受,返回了成功。但在最終的報名錶裏,隻插入了一條資料,使用者ID是第二個請求的。
第一個請求的使用者,收到了成功響應,但資料沒存下來。
“資料丟失?”老陳湊過來看螢幕。
“不像丟失。”林夕皺眉,“更像是……唯一約束衝突被靜默處理了。”
他檢查了資料庫配置。報名錶的主鍵是`(user_id, course_id)`確保一個使用者隻能報名一次同一課程。當並發插入同一對鍵時,後一個請求應該報“唯一鍵衝突”錯誤。
但日誌裏沒有衝突錯誤,隻有成功響應。
林夕寫了個簡單的複現指令碼:用兩個執行緒同時插入相同的主鍵。執行十次,有三次出現了同樣的問題——兩個執行緒都返回成功,但隻有一條資料。
“這是bug。”他得出結論。
小劉被叫過來,看了複現步驟,臉色變了:“我馬上聯係研發。”
一個小時後,海量資料那邊回了電話。技術負責人解釋:這是他們優化過的一個“特性”——當檢測到唯一鍵衝突時,如果衝突發生在同一毫秒內,係統會選擇後一個請求成功,前一個請求也返回成功,但實際資料以後者為準。
“為什麽這麽做?”林夕問。
“為了效能。”電話那頭說,“在超高並發場景下,唯一鍵衝突檢查會帶來很大的鎖競爭。我們優化了這個流程,讓衝突處理更快。從業務角度,使用者收到成功響應,但實際上報名沒成功——這種情況很少見,隻在極端並發下出現。”
“但使用者以為自己報名成功了。”
“是的,這是一個trade-off(權衡)。我們會在檔案裏註明。”
掛掉電話,林夕、老陳、小雨麵麵相覷。
“這能接受嗎?”小雨問,“使用者以為自己報上名了,但實際上沒報上,等開課時發現自己不在名單裏——這會是嚴重的客訴。”
“而且很難排查。”老陳補充,“日誌裏沒有錯誤,使用者端顯示成功,隻有資料庫裏少一條資料。除非做資料核對,否則發現不了。”
林夕在測試報告裏記下這個問題,分類為“嚴重問題”。
測試繼續。
第二天,又發現了一個問題:在模擬網路抖動時,有時候事務會部分提交。比如使用者報名課程並同時生成學習記錄——這兩個操作應該在一個事務裏,要麽都成功,要麽都失敗。但網路不穩定時,出現過報名成功但學習記錄沒生成的情況。
海量資料的解釋是:他們的分散式事務實現基於兩階段提交,在網路分割槽時確實可能出現中間狀態。建議業務層做補償或重試。
又是一個“trade-off”。
第三天,發現了第三個問題:批量匯入資料時,如果某個節點響應慢,整個匯入會卡住,直到超時。而超時後,已經匯入的部分資料不會回滾——因為部分資料已經提交到其他節點了。
林夕把這些都記錄下來。到週五第一階段結束時,他列出了七個問題:兩個嚴重,三個一般,兩個建議優化。
週五下午,第一階段報告評審會。
周凱、楊帆、老陳、小雨、林夕,還有海量資料的王浩,通過視訊連線參加。
林夕匯報發現的問題,每個都有詳細的複現步驟、日誌截圖、影響分析。
王浩聽完,表情嚴肅:“感謝這麽細致的測試。這些問題我們大部分都知道,在後續版本中有修複計劃。但我想強調的是——任何分散式係統都有trade-off,關鍵看業務是否能接受。”
“我們的業務不能接受資料不一致。”楊帆說,“教育產品,使用者花錢買課,報名狀態必須100%準確。”
“那可能需要調整業務設計。”王浩說,“比如在應用層做去重,或者用更寬鬆的唯一性約束。”
“那樣就失去了用分散式資料庫的意義。”周凱插話,“我們引入新技術,就是為瞭解決這些問題,不是把問題推回應用層。”
會議陷入僵局。
最後,楊帆說:“這樣吧,第二階段效能壓測繼續做。但這些問題必須列入風險評估。最終是否采用,要看整體評估結果。”
會議結束。王浩下線前,特意對林夕說:“你的測試非常專業,感謝。”
林夕隻是點點頭。
散會後,周凱把林夕叫到一邊。
“測試做得很仔細。”他說,“但有時候,咱們也要考慮大局。海量資料是公司戰略合作夥伴,投資部那邊很看重。如果因為一些小問題就否定,可能會影響合作。”
“資料一致性不是小問題。”林夕說。
“我知道。”周凱拍拍他的肩,“但技術問題總有解決方案。你可以把問題提出來,然後也想想怎麽解決——比如在應用層加個校驗,或者業務上做個降級。這樣報告看起來就更全麵,不是單純挑刺。”
林夕明白了。周凱要的不是“發現問題”,而是“解決問題”——或者至少,看起來在解決問題。
“我會考慮的。”
“好。”周凱笑了,“對了,積分重構專案組那邊,最近也在做技術選型。如果你有興趣,我可以讓你過去幫忙,那邊更需要你這種細致的人。”
這是第二次遞出橄欖枝——或者說,第二次嚐試調走他。
“我在孵化部還有測試任務。”林夕說。
“測試很快會結束的。”周凱意味深長地說,“到時候,你可以有更多選擇。”
他離開後,林夕站在原地,很久。
回到工位,他開啟第一階段測試報告。七個問題,白紙黑字。
他想起周凱的話:“想想怎麽解決。”
是的,他可以給每個問題都加上“建議解決方案”——比如在應用層做額外校驗,比如修改業務邏輯,比如接受偶爾的資料不一致。
那樣報告看起來就“平衡”了:既指出了問題,又提供了方案。
然後,決策者可以選擇接受方案,推進試點。
皆大歡喜。
但那些被“解決”的問題,真的解決了嗎?還是隻是被掩蓋了?
就像三年前的積分係統,陳啟明指出了問題,周凱給出了“臨時方案”,然後問題被擱置,直到再次爆發。
曆史在重複。
林夕盯著螢幕,手指放在鍵盤上。
他可以按照周凱的意思修改報告。那樣對大家都好:周凱能推進試點,楊帆能看到“全麵”的評估,海量資料能繼續合作,他自己也能獲得“善於解決問題”的評價。
但他沒有動。
他開啟一個新的檔案,標題:“關於海量資料測試發現問題的深度分析”。
然後開始寫:
本文旨在從技術原理層麵,分析測試中發現的問題根因,而非提供表層解決方案。
問題一:毫秒級唯一鍵衝突靜默處理。
根因:資料庫為了效能優化,犧牲了強一致性。這不是配置問題,是架構設計選擇。
影響:在業務高峰期,會出現使用者端成功但資料丟失的情況,且難以排查。
真正的解決方案:要麽修改資料庫核心(海量資料已承諾在後續版本優化),要麽業務層接受這種不一致性並建立複雜的補償機製。
問題二:網路分割槽下的分散式事務中間狀態。
根因:CAP理論下的必然取捨。海量資料選擇了可用性(A)和分割槽容忍性(P),犧牲了一部分一致性(C)。
影響:分散式事務可能部分提交,需要業務層做大量狀態管理和補償。
真正的解決方案:要麽使用更嚴格的共識演演算法(效能下降),要麽業務層設計成冪等且可補償。
問題三:批量操作部分失敗不回滾。
根因:分散式係統難以實現原子的、跨節點的回滾。
影響:資料清洗、遷移、歸檔等批量操作風險極高。
真正的解決方案:要麽業務層設計分段提交和重試,要麽接受髒資料並定期修複。
結論:上述問題不是‘bug’,而是分散式資料庫在設計上的必然取捨。是否采用,取決於業務是否能接受這些取捨帶來的複雜性和風險。
建議:如果決定采用,必須:
1. 重寫所有涉及資料一致性的業務邏輯,增加狀態機、補償任務、核對機製。
2. 建立更完善的監控和告警,及時發現資料不一致。
3. 定期進行資料核對和修複。
如果不接受這些複雜度,建議維持現有架構,通過優化應用層和中介軟體來解決效能問題。
他寫得很冷靜,很客觀。沒有情緒,隻有事實和分析。
寫完,他儲存檔案,但沒有立刻發出去。
他需要等一個合適的時機。
窗外,天色漸暗。又是週末了。
他關掉電腦,收拾東西。手機震動,是陳啟明發來的郵件。
隻有一句話:“測試時,注意看慢查詢日誌裏那些被標記為‘優化’的操作。有時候,所謂的優化,是掩蓋問題的開始。”
林夕盯著這句話,心裏一動。
他重新開啟電腦,登入測試環境,檢視慢查詢日誌。
果然,在那些出現問題的操作附近,都有日誌標記著:“[OPTIMIZATION] Duplicate key conflict handled by last-write-win policy.”
最後寫入者獲勝策略。
所以,海量資料知道這些問題,他們稱之為“優化”。
而周凱也知道,他稱之為“trade-off”。
所有人都知道,但所有人都選擇繼續推進。
除了他。
這個固執的、不懂變通的、在挑刺的新人。
他關掉日誌,再次看向自己寫的那篇深度分析。
這一次,他按下了傳送鍵。
收件人:楊帆、老陳、小雨。
抄送:周凱、張維。
主題:海量資料第一階段測試問題根因分析。
傳送。
螢幕提示傳送成功。
他坐在黑暗的辦公室裏,隻有顯示器的光映在臉上。
像等待審判的囚徒。
又像舉起火把的人。
他不知道這份報告會帶來什麽。
但他知道,有些話,必須有人說。
而今天,他選擇了做那個人。
窗外的城市華燈初上,車流如織。
每個人都在回家的路上。
隻有他,剛剛點燃了一簇火。
火會照亮什麽?
也會燒毀什麽?
他不知道。
但他知道,從今天起,
棋局,不一樣了。