當您鍵入 things.news 時會發生什麼?
本文首次發表在Matters Engineering Wiki上。
在之前的文章中,我們先睹了 Matters.news 的架構、我們用於構建網站和 API 的技術堆棧,以及我們如何設計組件並使它們順利協同工作的詳細信息。
在本文中,我們從另一個角度出發,從網絡請求開始。首先,我們簡要概述了服務器如何響應用戶請求,然後,我們更深入地研究了性能優化。
網絡請求概述
客戶
客戶端(通常是 Web 瀏覽器)通過 HTTP 請求與服務器通信。
當用戶在地址欄中輸入matters.news
時,瀏覽器首先會聯繫 DNS 解析器並獲取該域後面的 IP 地址,然後向該 IP 地址發送請求,等待響應,並將結果呈現在瀏覽器。
邊緣
在網絡邊緣,我們使用 Cloudflare 來加速網絡請求並保護我們的源服務器,所有 DNS 查找和請求首先由 Cloudflare 處理。
DNS 查找將解析到最近的 Cloudflare 反向代理,而不是我們的源服務器。反向代理可以過濾掉惡意請求,並通過緩存和智能路由提供性能優勢。
源服務器
SSR(服務器端渲染)服務器將預渲染的 HTML 發送到客戶端。在內部,許多 API 調用代表客戶端發送到 API 服務器。
一旦 API 請求 ( server.matters.news
) 到達源 API 服務器,如果之前緩存了相同的請求,則由緩存服務器提供服務,否則由數據庫提供服務。
端到端
讓我們把它們包起來。
- 用戶打開一個以things.news域開頭的 URL;
- 瀏覽器發出 HTTP 請求,該請求通過 Cloudflare 邊緣網絡發送到我們的SSR 服務器;
- SSR 服務器發送 HTML 並由瀏覽器呈現;
- 用戶開始瀏覽其他頁面或與網站交互;
- 瀏覽器進行後續 API 調用,通過 Cloudflare 邊緣網絡到我們的API 服務器;
網絡分析
網絡性能是網站性能的核心。要進行優化,我們首先需要了解網絡流量。發送了多少請求?服務器的響應速度有多快?...
我們將介紹一些隨著時間的推移不斷監控和改進的關鍵指標。
總請求
一段時間內的總請求是了解網絡狀態的最基本和最直觀的指標。
Cloudflare Analytics 顯示有多少請求發送到邊緣,而 AWS Elastic Beanstalk 和 Apollo Studio 顯示有多少請求到達源服務器。
響應時間
響應時間是服務器為 API 處理請求並響應客戶端所花費的時間。
我們可以知道所有請求或單個請求類型(GraphQL 操作)的響應時間百分比(例如 P50、P95)。這對於識別哪個 GraphQL 操作是響應時間慢的“受害者”非常有幫助。
緩存命中率
Cache Hit Ratio 告訴我們有多少百分比的請求在沒有命中原始 API 服務器或數據庫的情況下得到了服務。越高,響應越快。
資源利用率
我們的原始服務器和數據庫不是無限自動擴展的,因此 CPU 和內存利用率對性能和可靠性很重要。
性能優化
許多工具和服務可以幫助我們提高網絡性能,尤其是在應用層,以下是我們採取的一些行動。
防火牆和智能路由
在網絡邊緣,我們使用Cloudflare WAF過濾惡意流量並保護我們的源站服務器。防火牆規則可以通過基於地理位置、IP 地址、HTTP 標頭過濾請求來控制傳入流量。和速率限制以限制最大頻率。
由於 API 響應是動態實時數據,很難被 Cloudflare CDN 緩存,因此我們啟用Cloudflare Argo根據網絡條件路由流量,選擇最快和最可靠的網絡路徑到我們的源服務器。
內容分發網絡
與 API 不同,許多用戶生成的內容 (UGC) 是靜態的,例如圖像,這些內容一旦創建就不會更改。我們的靜態內容分發到 AWS CloudFront 的全球網絡,緩存並根據地理位置提供給用戶。
內存緩存
API 請求命中源服務器,響應數據將被緩存到緩存(Redis)服務器,然後再發送回客戶端。
我們使用AWS ElastiCache for Redis作為內存緩存,以實現最佳 IOPS 和吞吐量性能。
在 Apollo 的 GraphQL 插件之上,我們還構建了一組工具來控制緩存和失效。我們在計算機科學中兩件困難的事情之一上做出了努力。
公共/私人拆分
API 請求(GraphQL 操作)由訪問者或登錄用戶發送。來自訪問者的請求被公開緩存,而登錄用戶被私下緩存。由於私有數據只能由單個登錄用戶訪問,因此我們通過帶有用戶 ID 的自定義緩存鍵來緩存 API 響應。
此外,由於matters.news是一個公共平台,大部分用戶登陸的都是公共頁面,比如首頁和文章頁面,這些頁面由公共數據和少量私人數據(例如我是否關注作者)組成。我們將 API 請求一分為二,一是查詢公共數據,二是查詢私有數據。
現在,提高了公共查詢的緩存命中率,減少了源站處理私有查詢的負載。
深度限制
根據複雜性,不同的請求需要不同的處理時間。我們通過深度限制 GraphQL 查詢的複雜性,它還保護了我們的 API 服務器。
索引
最後,如果一個請求是緩存未命中,它需要從數據庫中查詢數據。我們會持續監控最高負載查詢並添加索引以提高性能並減輕負載。
概括
優化網絡性能的方法還有很多,但我們不會在這裡介紹它們。最終,這一切都歸結為要實現的目標:最小化請求數量和復雜性,最大化緩存命中率,以及最小化處理時間。
喜歡我的作品嗎?別忘了給予支持與讚賞,讓我知道在創作的路上有你陪伴,一起延續這份熱忱!
- 來自作者