遷移至更大的工作區,又不讓任何人等待
每個 Mythex 專案都有自己的工作區:一部小型雲端電腦,編碼代理在其中撰寫程式碼,而你的應用程式預覽則在其中運行。我們已把新工作區的記憶體由 1 GB 提升至 2 GB,但較舊的工作區仍停留在 1 GB;在我們檢查的那一天,大約四分之一的工作區是這樣。我們第一個修正,是在專案下次被開啟時,把它遷移到更大的工作區。在它首日上線時,就令一位用戶等了七分鐘。之後我們為它設定了硬性時限,然後乾脆把遷移從開啟專案的流程中完全移除。
舊工作區為何仍然很小
我們的沙盒供應商會在工作區建立時設定其大小,並在每次暫停和恢復時保留這個大小。更改範本(即新工作區所依據的配置藍本)只會影響更改之後才建立的工作區,不會調整已存在的工作區的大小。
這一點很重要。其中一個小型工作區在預覽啟動的同時執行 git push 時記憶體耗盡,之後 11 分鐘都沒有回應。一次發佈就因此失敗。
第一次嘗試:在工作區喚醒時遷移專案
當沒有人使用工作區時,它會暫停;當專案被開啟時,它會喚醒。喚醒的時候似乎是遷移專案的合適時機,因為那時還沒有人在工作。
遷移的運作方式如下:
- 檢查大小。 如果工作區小於 2 GB,就進行遷移。如果無法得知其大小,則不做任何事。
- 不干擾發佈。 發佈會讀取工作區的檔案,所以如果有發佈正在進行,就略過遷移。
- 打包專案。 將專案中的所有內容封存,包括其 git 歷史(即專案所有的檢查點),以及屬於擁有者的應用程式
.env檔案;但會排除已安裝的相依套件(node_modules),因為它們可以重新安裝。 - 直接複製過去。 把封存檔從舊工作區直接串流到一個全新的 2 GB 工作區,這樣它就永遠不需要放進我們自己伺服器的記憶體中。
- 切換前先比對。 在兩個工作區中分別計算檔案數量、讀取最新的檢查點,並計算檢查點數量。只有三者全部一致,才會切換。
- 任何失敗時保留舊工作區。 任何錯誤或任何不一致,都會捨棄新工作區,並像以前一樣在舊工作區中開啟專案。
比對中有一個細節比表面看來更重要。檢查以管理員帳戶執行,而 git 會拒絕讀取由其他使用者擁有的儲存庫。兩邊都沒有輸出任何內容,而「沒有內容」與「沒有內容」相符,因此檢查在沒有比對任何歷史紀錄的情況下就通過了。我們告訴 git 信任該目錄,並加入了一項測試,以免這個問題再次出現。
首日出了什麼問題
在它首日上線時,打包其中一個專案時,在喚醒過程中碰到了五分鐘的指令逾時。擁有者等了七分鐘,工作區才開啟。而且由於遷移已失敗,該專案仍然很小,因此下一次開啟時又會再試一次,令他們再次等待。
在用戶開啟自己的專案時令其等待的遷移,是很糟糕的取捨。在喚醒時進行遷移的全部意義,就是讓任何人都不會察覺。
第二次嘗試:設定硬性時間預算
同一天,我們改動了四件事:
- 整個遷移只限一分鐘。 每個步驟(檢查大小、打包、建立新工作區、複製、解壓、比對)共用同一個 60 秒的預算。預算用完時,專案會在舊工作區中開啟。
- 停止工作,而不只是停止等待。 如果在用戶即將使用的工作區內,封存仍在運行,那麼我們這一端放棄是不夠的。現在,每個封存指令都會在預算結束前不久,於工作區內部被終止。如果新工作區是在我們放棄之後才出現的,它會被丟棄。
- 不讓用戶等待清理。 刪除暫存封存檔的工作現在改為在背景進行。
- 不在每次開啟時都重試。 無法遷移的專案會被擱置 24 小時,因此一次失敗最多只會每天造成一次延遲,而不是每次開啟都延遲。
第三次嘗試:把遷移移出喚醒流程
這樣一來,最壞的情況已降至一分鐘。但一分鐘仍然是一分鐘,而我們意識到,遷移根本不需要放在任何人的使用路徑上。
現在已不會再建立 1 GB 的工作區。因此這並不是一個持續進行的過程,而是一項一次性的工作,對象是一份固定的工作區清單。把它放在喚醒流程中,意味著每一次緩慢的遷移都由真實的人來承受代價,而我們唯一得知某個工作區無法遷移的途徑,就是有人剛好在等待它。
因此,我們把遷移完全從喚醒流程中移除。開啟專案的行為與以前相同。剩下的小型工作區,改為以受監督的批次方式處理:沒有人需要等待,而無法遷移的工作區會出現在批次報告中,讓我們可以查看,而不是在擁有者面前出現。
我們從中學到的
- 調整大小並非總是可行。 當平台在建立時就固定了大小,提高預設值只對新的東西有幫助。對於舊的東西,要另作計劃。
- 「還沒有人在用」並不代表沒有人在等待。 在用戶進入產品的途中所做的工作,同樣是有人在旁觀的工作。
- 對用戶路徑上的任何工作都設定預算,並在預算用完時停止工作。 我們這邊逾時,而指令仍在其他地方繼續運行,只會令問題轉移而已。
- 一次性的遷移應該放在一次性的工作中。 把它藏在日常操作之中,會令它更容易編寫,但運行成本更高。
- 測試你的安全檢查。 一項什麼都沒有比對的比較,看起來和一項真正通過的比較一模一樣。
如果你在 Mythex 上建立應用程式,你無需做任何事:目標只是減少工作區因記憶體耗盡而出現的問題,同時讓開啟專案的速度維持與以前一樣快。工作區如何暫停和喚醒,可參閱文件中的私人工作區。如需另一個記憶體耗盡的故事,請參閱隱藏在進度標籤中的記憶體耗盡崩潰。