第 7 章:第7章:爆發
第7章:爆發
星期五早上七點,方佑廷到了公司。
他看到林哲翰已經在位子上,有點驚訝。「你幾點來的?」
「六點多。」
「你昨晚幾點走的?」
「一點。」
方佑廷推推眼鏡。「你這樣會累死。」
「把這個看完。」林哲翰把螢幕轉向他。
螢幕上是session管理的code。方佑廷坐下來,開始看。看了幾分鐘,他的眉頭皺了起來。
「這個session merge的邏輯……」他指著螢幕上的一段code,「這裡用的是session ID來判斷是不是同一個user。但session ID是client端生成的,如果兩個不同租戶的client用了相同的session ID——」
「就會被當成同一個user。」
方佑廷的臉色變了。「但session ID是UUID,重複的機率很低——」
「在低流量的時候很低。但在高並發下,如果client端沒有正確生成UUID,而是用時間戳加隨機數,那重複的機率會大幅上升。」
方佑廷沉默了。
「這個問題在demo的時候一定會被發現,」林哲翰說,「投資方會跑壓力測試。只要並發數夠高,這個問題就會出現。」
「你怎麼知道?」
林哲翰沒有回答。
方佑廷看著他,眼神裡有一種林哲翰很熟悉的東西——不是恐懼,是信任。他相信林哲翰知道他在說什麼。
「怎麼修?」方佑廷問。
「session ID不能只用client端生成的。Server端要驗證。如果發現重複的session ID,要強制重新生成。」
「但這樣會增加server的負擔——」
「用cache來存session ID的對應關係。每次client帶session ID來的時候,先查cache。如果發現這個session ID已經被另一個租戶用了,就回傳錯誤,要求client重新登入。」
方佑廷想了一下。「這樣client端要處理重新登入的邏輯——」
「我來改client端。你改server端。」
方佑廷點頭。「好。我現在開始。」
他轉回螢幕,開始敲鍵盤。
林哲翰站起來,走到陳立偉的位子。「立偉,你今天有空嗎?」
陳立偉抬頭看他。「什麼事?」
「session管理的client端需要改。方佑廷在改server端,我需要有人改client端。」
陳立偉看了他幾秒。「這不是我的模組。」
「我知道。但你是我們最好的前端工程師。」
陳立偉沉默了一下。「好。」
林哲翰把改動的需求告訴他。陳立偉聽完,點個頭,開始工作。
林哲翰回到位子上,打開Slack,看到趙品睿在工程群組裡問:「大家準備好了嗎?demo兩點開始。」
方佑廷回了:「正在做最後調整。中午前會完成。」
趙品睿回了個「好」。
林哲翰看著這個對話。在原始時間線,方佑廷沒有做最後調整。因為在原始時間線,session管理的問題沒有被發現。
但這次被發現了。而且正在被修。
他不知道這算不算改變了時間線。或者說,他已經改變了這麼多,他不知道哪一個改變才是關鍵。
上午十點,方佑廷說server端改好了。
林哲翰走過去看。Code看起來正確——server端現在會驗證session ID的唯一性,如果發現重複,會回傳401要求client重新登入。
「跑一下測試。」林哲翰說。
方佑廷跑了unit test。通過。跑了整合測試。通過。
「壓力測試呢?」
「要跑一個多小時。」
「跑。」
方佑廷設定了壓力測試的參數。林哲翰在旁邊看,確認並發數設為五百,租戶數量設為五十——比demo預期的更高。
「中午看結果。」林哲翰說。
他回到位子上,看到陳立偉正在改client端的code。螢幕上開著React的component,陳立偉正在處理401錯誤的邏輯——當server回傳401的時候,client端要自動清除session,然後導向登入頁面。
「怎麼樣?」林哲翰問。
「差不多了。再半小時。」
林哲翰點個頭。他打開自己的code repository,開始看其他模組。
但他看不進去。他的腦子裡一直在想一件事。
在原始時間線,demo出了問題。但問題不是session management——而是tenant isolation的query問題。那個問題他已經在星期四修掉了。
但現在他發現了session management的問題。這個問題在原始時間線也存在,但沒有被發現。因為在原始時間線,投資方沒有現場跑壓力測試。
那為什麼這次投資方會跑壓力測試?
因為他在星期四的排練中提到了壓力測試。他告訴趙品睿:「我們跑過壓力測試,五百並發,平均回應時間三百毫秒。」
然後趙品睿在跟投資方的溝通中,可能提到了這件事。然後投資方決定現場驗證。
他改變了時間線。但時間線也改變了他。
他修掉了一個問題,但暴露了另一個問題。
他不知道這是好事還是壞事。
中午十二點,方佑廷的壓力測試跑完了。
他看著報告,臉色很凝重。
「怎麼了?」林哲翰走過去。
「五百並發的時候,session ID重複的機率是百分之零點三。」方佑廷指著報告上的一個數字。「看起來很低,但如果同時有五百個user在線,平均會有1.5個user受到影響。」
「在demo的時候,投資方最多同時開三十個連線。」
「三十個連線,session ID重複的機率是百分之零點零一八。大約是五百分之一。」
「五百分之一。」
「對。很低,但不是零。」
林哲翰沉默了。
在原始時間線,demo的時候沒有測session management。所以這個問題沒有被發現。但這次,因為他在排練中提到了壓力測試,投資方可能會測。
五百分之一的機率。很低。但不是零。
「如果被發現了,」方佑廷慢慢地說,「會怎樣?」
林哲翰看著他。
「我是說,」方佑廷推推眼鏡,「如果demo的時候這個問題被發現了,品睿會怎麼處理?」
「他會說這是已知問題,我們正在修復。」
「然後呢?」
「然後他會找一個人來扛責任。」
方佑廷沉默了。
「這個code是你寫的。」林哲翰說。
「我知道。」
「但問題不是你的code有錯。問題是client端生成session ID的方式不夠安全。這是架構設計的問題,不是實作的問題。」
「但品睿不會這樣想。」
「我知道。」
方佑廷低下頭,看著自己的手。「哲翰哥,你覺得我會被開除嗎?」
林哲翰看著他。這個24歲的年輕人,戴著眼鏡,臉很圓,笑起來有酒窩。他看起來很年輕,像一個大學生。
在原始時間線,他回答了這個問題。他的回答是:「不會。我會保護你。」
然後他出賣了他。
「不會,」林哲翰說。「這次不會。」
方佑廷抬頭看他。「你怎麼知道?」
「因為我會確保這件事不會發生。」
方佑廷看了他幾秒,然後笑了。那個笑容裡有信任,也有一種林哲翰不知道該怎麼形容的東西——像是鬆了一口氣,又像是更深的擔憂。
「好,」方佑廷說。「我相信你。」
下午一點半,投資方的人到了。
三個人。一個合夥人,四十幾歲,穿著西裝。一個技術顧問,三十出頭,背著一個筆電包。一個分析師,看起來很年輕,手裡拿著一個平板。
趙品睿帶他們進會議室。林哲翰站在門口,看著他們坐下。
在原始時間線,他坐在會議室的角落,很少說話。趙品睿負責所有的簡報,他只在被問到的時候才回答。
但這次不一樣。
趙品睿在簡報開始之前,看了他一眼。那個眼神是什麼意思?林哲翰不確定。也許是「不要多話」。也許是「準備好」。也許是「這是你的場」。
簡報開始了。趙品睿站在投影幕前面,用他一貫的慢條斯理的語氣介紹公司、產品、市場。投資方的人聽著,偶爾點頭。
然後趙品睿說:「接下來讓我們的技術主管林哲翰來展示系統。」
林哲翰站起來,走到會議室前面。
他接過許湘芸手中的筆電,連上投影幕。螢幕上顯示系統的登入頁面。
「我先展示核心流程,」他說。「登入。」
他輸入了測試帳號。系統登入成功。
「對話。」
他點擊「對話」頁面。系統載入,顯示預設的對話紀錄。
「資料查詢。」
他輸入查詢條件。系統回傳結果。正確。
投資方的人看著螢幕。技術顧問在筆電上記錄什麼。
「好,」合夥人說,「基本功能沒問題。那tenant isolation呢?」
林哲翰看了趙品睿一眼。趙品睿的表情沒有變。
「我來展示,」林哲翰說。
他開了兩個瀏覽器,分別用A租戶和B租戶登入。然後在A租戶的瀏覽器裡,嘗試存取B租戶的資料。
系統回傳了「權限不足」的錯誤。
技術顧問點點頭。「那高並發呢?」
來了。
「我們跑過壓力測試,」林哲翰說,「五百並發,平均回應時間三百毫秒。Tenant isolation在高並發下也通過了。」
「能現場測一下嗎?」
林哲翰看了趙品睿一眼。趙品睿微微點個頭。
「可以,」林哲翰說。
他打開壓力測試的工具,設定了參數。三十個並發——跟投資方的人數一樣。五十個租戶。持續五分鐘。
「這個測試會跑五分鐘,」他說。「我現在開始。」
他按下了開始鍵。
會議室裡安靜了。所有人看著螢幕上的數據。
並發數:30。回應時間:平均280毫秒。錯誤率:0%。
一分鐘。兩分鐘。三分鐘。
數據穩定。沒有錯誤。
四分鐘。
然後螢幕上跳出了一行紅色文字。
「Session conflict detected. Tenant ID mismatch.」
會議室裡安靜了。
林哲翰看著那行紅色文字。五百分之一的機率。三十個並發。四分鐘。
被觸發了。