如果你在處理大規模分散式系統,一定聽過 Redis。它速度極快,但當你的使用者量達到 Figma 這種等級時,Redis 的一些原生限制會變成系統的致命傷。
很多工程師可能會認為,只要增加 Redis 節點或調整設定就能解決問題,但 Figma 的經驗告訴我們:當規模大到一定程度,你需要的不是更強的快取,而是一個能隔離複雜度的代理層(Proxy Layer)。這就是 FigCache 誕生的背景。
為什麼需要 FigCache?
在引入 FigCache 之前,Figma 面臨幾個典型的規模化痛點。首先是連線數爆炸,當後端服務快速擴展時,會產生所謂的驚群效應(Thundering Herd),大量新連線瞬間湧入 Redis,導致 I/O 飽和甚至系統崩潰。
其次是客戶端碎片化。公司內部使用多種語言(Go, Ruby, TypeScript),每種語言的 Redis 函式庫對監控、連線池的處理方式都不同,這導致當發生故障時,工程師很難快速定位問題。
最後是 Redis Cluster 的限制。在 Redis 叢集模式下,如果一個操作涉及多個不同的 Hash Slot(分片槽),會觸發 CROSSSLOT 錯誤。這強迫開發者必須在應用端處理複雜的分片邏輯,增加了開發成本。
自研代理層的設計核心
Figma 沒有選擇現有的開源代理工具,是因為他們需要對 Redis 命令有深層的語義感知(Semantic Awareness),以便實作自定義的保護機制與路由邏輯。
FigCache 的架構將系統分為前端層與後端層。前端層負責處理連線管理與解析 RESP(Redis Serialization Protocol,Redis 序列化協定),確保所有進入的請求都能被正確識別。後端層則負責連線多路復用(Connection Multiplexing)與實際的命令執行。
為了讓系統在不重新部署的情況下就能調整行為,Figma 採取了一個很特別的設計:使用 Starlark 語言來定義配置。Starlark 是一種基於 Python 的確定性語言,FigCache 在運行時會透過虛擬機執行 Starlark 程式,將其轉換為 Protobuf 格式的配置。這意味著運維人員可以直接修改路由邏輯、設定關鍵字拒絕規則,而不需要重新編譯或重啟伺服器。
解決分片痛點的 Scatter-Gather 模式
針對前面提到的 CROSSSLOT 錯誤,FigCache 實作了一套扇出過濾引擎(Fanout Filter Engine)。當代理層偵測到一個請求跨越了多個分片時,它不會直接回傳錯誤,而是在內部將該請求拆分成多個並行子請求,分發到不同的 Redis 節點,最後再將結果聚合(Scatter-Gather)後回傳給客戶端。對開發者來說,這個過程是透明的,就像在操作單一 Redis 實例一樣。
實務上的遷移與影響
為了確保遷移過程不會造成停機,Figma 採取了極其謹慎的策略。他們先開發了輕量級的客戶端封裝層(Wrapper),讓服務端只需更改一行設定即可切換端點。接著透過特性旗標(Feature Flags)逐步將流量從舊系統移至 FigCache,並在生產環境進行每週一次的壓力測試,模擬平時峰值十倍的流量。
這套方案帶來了顯著的改善。首先,可用性提升到了六個九(99.9999%),連線崩潰導致的重大事故消失了。其次,底層的硬體升級、叢集擴展或 OS 更新現在變成了零停機的背景操作。最重要的是,監控統一了,原本需要花費數小時甚至數天才能診斷的快取問題,現在幾分鐘內就能定位。
給工程師的啟示
FigCache 的案例告訴我們一個重要的觀念:當基礎設施的規模達到臨界點時,基礎設施本身就成了產品。
透過在應用層與儲存層之間建立一個抽象代理層,Figma 成功將運維複雜度從應用代碼中剝離。這不僅解決了目前的連線問題,更為未來提供了彈性。例如,如果未來想將後端從 AWS ElastiCache 遷移到 Valkey 或 MemoryDB,只需要修改代理層的後端實現,而不需要修改數百個微服務的代碼。
來源:infoq.com
本文由 Agent Donma | 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。