Wed Sep 10 2025
...
FastComments 現在已全球分佈
新聞
以前 FastComments 的網頁應用程式架構非常傳統。我們有我們的應用伺服器、數據庫和其他一些服務。這在兩個區域(美國西部和歐洲)中重複配置。如果您在法國並想查看一條托管在我們全球數據中心的客戶的評論線程,您的請求將不得不一路前往美國西部以獲取評論數據。
現在已經不需要這樣了!現在評論數據和所有媒體資產都在我們的全球部署中進行了全球複製,對於我們的歐洲部署,數據在歐盟的三個接入點中進行了複製。您的請求將發送到歐盟中最近的節點。
工作原理
除了在區域和雲提供商間擁有幾個實時副本的數據庫外,所有服務都在每種服務類型的一個實例上部署。這意味著每個區域有一個應用伺服器、一個 pubsub 伺服器和一個媒體伺服器。計劃是儘可能垂直擴展,因為這使事情變得簡單。編寫代碼很容易 - 您總是知道在訪問數據庫時可以「讀取自己的寫入」。基礎設施很簡單,唯一的例外是安全更新需要一分鐘的停機時間。
問題
問題顯然出現在達到容量時。我們會優化,然後最終不得不增大該服務的實例大小。
這在 Linode 上開始變得成本高昂,根據我們的通過標記測試,$144 的實例大約等於 $20 的 OVH 節點,即使我們更換主機提供商,我們也會在各地出現單點故障 - 而像 OVH 這樣的提供商在維護問題上的解決時間往往比 Linode 更長。
RiR :)
在最初的幾年中,FastComments 的 PubSub 和媒體服務是用 Java 編寫的。選擇 Java 是因為其在投入工作容量上性能相對較高,經過幾年的調整 GC,嘗試 G1GC、Shenandoah 和 Z1,我們決定不再使用 Java。內存佔用開銷實在太高,而且這些服務在完成後通常是非常靜態的,Java 的優勢漸漸消失。此外,這些服務往往需要處理「雷霆大軍」問題,這意味著 JVM 正在嘗試處理尚未啟動 JIT 的高峰流量。這些服務是轉向 C++ 或 Rust 的最佳候選。
選擇 Rust 是因為我們不是 C++ 專家,網絡代碼中的錯誤可能會將一個客戶的數據暴露給另一個客戶。Rust 幫助我們防止這類問題。
我們本來想整合這些服務,因此雖然我們可以用 GraalVM 進行 另一 次優化,我們決定轉向 Rust 並結束這件事。
遷移並非沒有問題。這些服務必須終止 SSL,支持 HTTP 1.1、HTTP/2 等等。它們執行許多數據流的並行管理,從邊緣的磁碟 LRU 緩存、S3、數據庫讀取媒體,並進行網格通信。Java 生態系統,Vertx 和 Netty,在這些方面非常出色。我們在推動庫生態系統的極限,且對 Rust 庫的經驗不多意味著我們經歷了一些試錯過程。這造成了一些停機,我們為此道歉。
我們還試驗了不同的內存管理器,最終選擇了 mimalloc 用於我們的自定義 DNS 伺服器,和 libc 用於傳輸層。我們不運行 Nginx 或 Apache,而是使用自定義 DNS 伺服器的組合,根據每週從 Maxmind 重建的內存索引在全球路由客戶端,還有我們用 Rust 建立的傳輸層,與其他傳輸實例維持網格連接。傳輸終止 SSL,處理 pubsub 任務,並作為我們的 CDN。這樣的好處是減少了在服務之間移動數據時的開銷,並減少了基礎設施開銷/抽象。缺點是可見性,因此良好的度量變得重要。
就產生的性能而言,Rust 服務使用的內存大約是 Java 服務的 10-30%,儘管我們進行了所有的努力。我為樂趣閱讀像《Java Concurrency in Practice》這樣的書籍,所以雖然不是專家,但我對編寫快速 JVM 服務有一點了解,使用 Rust 實現這一點簡直容易得多。此外,對大量訂閱者的大量消息的峰值會幾乎不影響 CPU 使用情況,而 JVM 服務會浪費 40% 的時間在 GC 上,儘管我們的代碼更像遊戲引擎,而不那麼像典型的伺服器。我不能說我是 Rust 的忠實粉絲,但對於進行大量工作且開發後變化不大的服務來說,它是完美的。我們的主要業務邏輯仍然在 TypeScript 中。
新架構
新架構不再有「寵物」節點。每個伺服器都是完整的克隆,擁有相同的服務和幾乎相同的配置。它們各自運行傳輸、DNS、應用伺服器和數據庫的副本。所有節點都維護全磁碟加密,並利用 Dropbear 進行自動解鎖。
每個伺服器運行路由傳輸,終止請求並將其處理為 websocket、http 流或 cdn 請求。這些伺服器彼此連接,任何給定伺服器提供全球網絡到其本地 DNS 伺服器的映射,以實時告訴 DNS 每個活動節點在全球的位置。
新架構的一個好處是冗餘。如果某個區域的客戶強烈訪問我們,其他區域仍然保持在線。
應用代碼現在必須非常清楚哪些查詢可以命中最近的節點,或哪些必須去數據庫主實例,該主實例可能運行在較遠的地方。犯錯會嚴重降低性能。這也意味著某些區域的寫入可能會很慢,這需要仔細調整和優化。我們現在在代碼內部遵循一種模式,所有對數據庫的訪問都需要一個 readPreference 參數,以便從調用者到頂部的人都必須明確決定如何查詢。
好處是讀取的橫向擴展非常好。FastComments 是非常以閱讀為主的,但我們不能忘記我們的版主!版主在全球範圍內日復一日地工作,我們希望他們的體驗保持良好。作為此次推出的一部分,我們一直在與其中幾位合作,以確保審核工具保持快速。
我們還可以手動選擇硬件,這既有趣又令人滿足。新伺服器是 i5-13500 和 Ryzen 5 5600X 的組合,歐洲使用一些舊的 Xeon。在我們的基準測試中,所有這些都比我們在其他提供商上探索的更昂貴的伺服器快得多。缺點是需要更多的設置工作,但我們已經自動化了這些工作,並且對故障進行了 SMART 磁碟監控等。
做這些事情意味著我們可以繼續提供具有競爭力的定價。
部署
在過去幾個月中,隨著我們重寫服務並轉移到新的主機提供商,部署過程相當波折,謝謝您的耐心。
在最初的部署中,我們的指標顯示超過 100 毫秒的請求數量有所增加。我們努力避免任何請求這麼長的時間。
我們仍在逐步改進某些區域的性能。感謝所有至今提供反饋的人。
使用 API 時的考量
API 保持強一致性 - 您可以讀取自己的寫入 - 以維持向後兼容性並保持對開發人員的簡單性。為了讓開發人員在性能和一致性之間做出選擇,我們計劃公開 readPreference 參數。好處是,我們也許還可以為這些 API 呼叫提供信用折扣。
所有公共端點,例如提供公共評論小部件的端點,始終從該節點上的最近(本地)數據庫中讀取。
為什麼不只是使用常規的 CDN
評論線程不是靜態的,它們是即時的,對過時的靜態數據應用實時流也不起作用,因為當您作為匿名用戶查看線程時,您將獲得一個「匿名會話」。在此匿名會話中,您可以執行阻止和標記其他用戶等操作,並且您必須顯示匿名用戶是否喜歡某條評論,等等。評論線程還可以鎖定在 SSO、身份驗證或用戶組後面。
最後,所謂的「漸進增強」中,動態數據映射到來自 CDN 的靜態數據會帶來糟糕的體驗,內容在幾秒鐘後會跳動或變化。我們不希望這樣做。
誰現在擁有我的數據
您的數據不再存儲在 Linode 上。它在 Hetzner 和 OVH 之間進行了實時複製,並且實施了全磁碟加密,後端伺服器之間的所有通信均使用 TLS 進行。我們維護幾個舊的 Linode 實例用於出站 webhook 代理,但不再存儲數據或媒體在 Linode 上。
總結
像所有主要版本一樣,我們很高興能夠花時間優化、測試和妥善釋放此更改。長期來看,這項工作應該使 FastComments 的擴展性更好,並且穩定性更高。如果您發現任何問題,請在下方告訴我們。
