在現代的大規模分散式系統中,身分驗證與會話管理(Session Management)始終是效能與安全之間的拉鋸戰。為了追求低延遲,許多系統採用無狀態的認證方式,例如將身分資訊加密後儲存在瀏覽器 Cookie 中,讓 API 閘道器(Gateway)能直接驗證請求而無需每次都查詢資料庫。然而,這種做法面臨一個核心挑戰:當使用者登出、密碼變更或權限被撤銷時,系統必須能近乎即時地讓這些已失效的會話(Session)失去效力。這就是所謂的會話撤銷(Session Revocation)問題。
根據 InfoQ 報導,設計平台 Canva 面臨著數以億計的活動會話管理壓力。在舊有架構中,Canva 將 12 小時內的撤銷清單儲存在記憶體中,但每當系統部署新版本或閘道器實例重啟時,數百個閘道器會同時向 MySQL 資料庫請求數百萬筆撤銷紀錄,導致資料庫瞬間承受巨大的協同負荷(Coordinated Load),嚴重影響部署速度與系統穩定性。
為了克服這個瓶頸,Canva 重新設計了其撤銷基礎設施,將 Amazon S3 從單純的物件儲存服務,轉化為一種協調原語(Coordination Primitive),用來分發不可變的撤銷紀錄。
核心架構與運作方式
Canva 的新方案不再讓每個閘道器直接向資料庫請求數據,而是引入了一個非同步工作者(Asynchronous Worker)機制。這個工作者會定期掃描資料庫中的新撤銷紀錄,將其合併到最新的數據塊中,並上傳至 Amazon S3。
為了優化儲存與傳輸,Canva 將 12 小時的撤銷窗口切割成每 30 分鐘一個的 S3 物件。每筆撤銷紀錄被簡化為 16 位元組(Byte)的二進位格式,包含主體識別碼(Principal)與時間戳記。由於這些數據是以排序陣列(Sorted Arrays)的形式儲存,閘道器下載後可以直接在記憶體中進行高效的二分搜尋,這使得撤銷快取的記憶體占用量大幅降低了 87.5%。
在數據同步方面,閘道器利用 S3 的條件式 GET(Conditional GETs)請求來判斷數據是否更新,僅在有變動時才下載對應的數據塊,並自動捨棄超過 12 小時的舊資料。而工作者在更新 S3 物件時,則使用條件式 PUT(Conditional PUTs)來實現樂觀並行控制(Optimistic Concurrency Control),確保多個工作者同時更新同一物件時不會發生數據覆蓋。雖然系統中使用了 ZooKeeper 進行領導者選舉(Leader Election)以減少更新衝突,但這僅是優化手段,並非確保正確性的必要條件。
技術權衡與實務意義
針對這種設計,業界曾有討論認為應該改用短效期的存取令牌(Access Token)搭配長效期的刷新令牌(Refresh Token),讓系統只需在刷新令牌時檢查資料庫,而不需要在記憶體中維護巨大的撤銷清單。但 Canva 的工程師 Llew Vallis 指出,頻繁的令牌刷新會增加資料庫的負載,且會使系統的可用性過度依賴於資料庫的運行狀態。
將撤銷數據分發至 S3 並儲存在閘道器記憶體中,提供了更好的權衡。首先,這將資料庫的壓力從讀取端移至寫入端。資料庫負載現在僅與撤銷紀錄的寫入吞吐量以及整體流量相關,而不再隨著閘道器實例數量的增加而線性增長。其次,這極大地提升了恢復與部署速度。當新閘道器啟動時,它只需從 S3 下載相關的二進位塊即可重建本地狀態,而不需要向 MySQL 發起大規模查詢。
影響與限制
這套架構證明了 S3 在處理大規模狀態分發時的潛力。即使是一個包含一百萬筆撤銷紀錄的數據塊,其二進位大小僅約 16 MB,對於現代伺服器的記憶體壓力極小。目前該系統的工作者每秒可處理超過 2,000 筆撤銷紀錄,足以應對 Canva 的業務需求。
在實施後,Canva 成功將撤銷資料庫縮減至僅剩兩個用於冗餘的讀取副本(Read Replicas),並使部署過程變得更加可預測且快速。然而,這種方案的限制在於它依然存在一定的同步延遲,因為數據需要經過 工作者 $\rightarrow$ S3 $\rightarrow$ 閘道器 這一路徑。對於要求絕對即時(Strong Consistency)的撤銷場景,可能仍需額外的同步機制。但對於絕大多數的 Web 應用而言,這種基於不可變物件的分發模式,在擴展性與運維成本之間取得了極佳的平衡。
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。