English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

guest
1 / ?
back to lessons

位於幾乎所有網路服務之前的元件

歡迎

當您在瀏覽器中輸入 example.com 時,您幾乎從未直接連接到實際執行應用程式的機器。您連接到的是另一台機器,該機器會將請求轉發給執行應用程式的機器。這台負責轉發的機器有一個名稱:反向代理。

本課程將教授反向代理的功能、為何幾乎所有公開網路服務都隱藏在其後,以及邊緣層同時處理的三項任務。

課程結束後,您將理解:

- 客戶端、代理與源站之間的差異

- 為什麼在源站前放置代理能實現保護、擴展,並讓您在無人察覺的情況下替換組件

- 反向代理同時處理的三項職責:隱藏源站、終止 TLS,以及在各副本間分發負載

- 請求如何從瀏覽器到代理,再到上游,最後返回,逐跳(hop by hop)的過程

課程結束後,您將能自信地推理代理的部署位置、邊緣的關注點分離,以及為什麼無狀態的代理層可以低成本地倍增,而單一源站卻無法做到。

正向代理與反向代理

兩種代理方向

這兩種代理都站在兩方之間並轉發流量。它們的區別在於代表哪一方。

正向代理:位於一組用戶端的前方。用戶端知道代理的存在;外部伺服器看到的是代理的地址,而非用戶端的地址。企業出口代理、內容過濾器及 SOCKS 代理都符合此模式。

反向代理:位於一組伺服器的前方。外部世界(用戶端)與代理地址通訊;用戶端完全不知道背後隱藏著真實的伺服器。幾乎所有的公開網路服務都使用反向代理。

記憶口訣:正向代理隱藏用戶端以對付伺服器。反向代理隱藏伺服器以對付用戶端。

為什麼要關心方向? 任務、故障模式及安全邊界皆有所不同。正向代理關心的是其用戶端聯絡了誰;反向代理關心的是誰聯絡了其伺服器。

若用戶端同時透過這兩種代理發送流量,路徑為:client -> forward_proxy -> internet -> reverse_proxy -> origin。

一家小型公司營運一個聊天應用程式。他們希望所有外部用戶端的請求都落在某台機器上,該機器能隱藏後方的實際聊天伺服器。他們需要哪種代理?外部用戶端實際上是連線到哪裡?

為何如此多的功能都位於邊緣

邊緣層證明其價值

反向代理同時承擔三項職責。其中任何一項都足以證明該層的必要性;而在同一個位址同時承擔這三項職責,解釋了為何幾乎所有生產級 Web 架構的前端都呈現出相同的結構。

職責 1:隱藏源站。 代理在公開 IP 上回應。後端位於網際網路無法觸及的私有 IP 上。想要攻擊源站的攻擊者,必須先攻破代理。

職責 2:終止 TLS。 代理伺服器持有 example.com 的憑證,並解密傳入的 HTTPS 請求。後端服務透過受信任的網路區段,以純 HTTP(或較簡單的內部 TLS)與代理伺服器通訊。憑證輪換、更新及加密演算法策略皆集中於此處管理。

職責 3:分發負載。 代理伺服器決定由哪個後端處理每個請求。位於同一代理伺服器後方的後端組成一個池(pool);代理伺服器依據特定策略(如輪詢、最少連線數、基於標頭的雜湊)為每個請求挑選一個後端。擴充容量只需向池中新增後端,無需通知所有客戶端新的位址。

每個職責都是一個小型程式。它們共同解釋了為何像「在 Python 應用程式前部署 Caddy」這樣簡單的層級,其設計權重甚至超過 Python 應用程式本身。

反向代理承擔三項職責:隱藏源頭、終止 TLS、分發負載

針對三項職責進行設計

您的團隊在單一 VM 上執行一個小型 API,該 API 由單一 Python 程序執行,監聽 8000 埠。流量已增長到單一 VM 無法負荷的程度,且安全審查指出該 VM 具有公開 IP 並自行執行 TLS 憑證。

您決定在前方部署一個反向代理。請繪製佈局草圖:DNS 指向哪裡、憑證存放於何處、負載如何到達後端,以及原始 VM 有何變化?

請闡述新的架構。涵蓋所有四個部分:DNS 目標、TLS 終止位置、負載分發策略,以及原始 VM 保留或失去了什麼。

無縫替換元件

間接性帶來自由度

電腦科學界有一句老話:任何問題都可以透過增加一層間接層來解決(除了間接層過多這個問題本身)。反向代理(Reverse Proxy)是分散式系統中最實用的間接層之一。

它為您帶來的優勢:

- 可替換的後端。 將應用程式從 Python 遷移到 Go?從一個資料中心遷移到另一個?零停機時間推出新版本?這些操作都在穩定的公網地址背後進行。對使用者而言,一切保持不變。

- 獨立擴展。 代理層在 TLS 層根據頻寬與 CPU 進行擴展。後端層則根據應用程式負載進行擴展。由於它們運行在不同的機器上,因此可以各自沿著不同的軸線獨立增長。

- 故障隔離。 後端的錯誤部署不會導致公網地址中斷。代理層保持運行;您可以推送修復或回滾;當後端恢復時,外部世界即可重新連接。

- 橫切關注點集中於一處。 速率限制、地理封鎖、請求日誌、標頭重寫、快取、回應壓縮:這些功能全部位於代理層。後端程式碼可以專注於應用程式邏輯。

沒有代理時,上述每個問題都必須在應用程式程序內部處理。有了代理,這些問題則集中在由一個團隊負責的單一層級處理。

代價:多了一個需要運維的層級。成熟的團隊接受這個代價,因為代理層本身是無狀態的且可水平擴展;將一個代理替換為兩個不需要任何協調。

透過代理進行藍/綠部署

您的團隊在反向代理後方的三台後端 VM(藍色池)上運行 API 版本 1。您希望部署版本 2,並確保若發生問題,能在三十秒內完成回滾。

您啟動了三台運行版本 2 的新後端 VM(綠色池),與藍色池並行運行,但尚未將任何流量路由至它們。

請解釋反向代理如何讓您從藍色池切換到綠色池並快速回滾,並說明若應用程式直接暴露給客戶端而沒有代理,哪些操作將無法實現。

從瀏覽器到後端再返回

跟隨單一請求的端到端流程

追蹤一個針對 https://api.example.com/users/42 的 HTTPS GET 請求,透過位於後端池前方的反向代理進行處理。

第 1 跳:DNS 解析。 瀏覽器向解析器查詢 api.example.com。解析器返回代理的公開 IP(例如 203.0.113.10)。瀏覽器向 203.0.113.10:443 開啟 TCP 連線。

第 2 跳:TLS 握手。 代理出示其針對 api.example.com 的憑證。瀏覽器驗證憑證,雙方協定會話金鑰,並開啟加密通道。

第 3 跳:TLS 內的 HTTP 請求。 瀏覽器發送 GET /users/42 HTTP/1.1\nHost: api.example.com\n...。代理解密請求位元組。

第 4 跳:後端選擇。 代理伺服器查詢 api.example.com 的上游池,並使用其負載平衡策略選擇一個後端(例如 10.0.0.21:8000)。

第 5 跳:上游請求。 代理伺服器開啟(或重用)到 10.0.0.21:8000 的純 HTTP 連線並轉發請求。代理伺服器在過程中可能會重寫標頭:新增 X-Forwarded-For: <client-ip>,正確設定 Host:,並移除如 Connection 等逐跳(hop-by-hop)標頭。

第 6 跳:後端處理。 後端應用程式讀取請求,查詢其資料庫,並構建 JSON 回應。

第 7 跳:上游回應。 後端將回應以純 HTTP 形式發回給代理伺服器。

第 8 跳:邊緣回應。 代理伺服器可能會重寫或壓縮回應,透過 TLS 會話將其重新加密,並發送至瀏覽器。

第 9 跳:連線生命週期。 TLS 會話通常會保持開啟狀態以處理下一個請求(HTTP/2 可在單一連線多重複用許多請求)。代理伺服器到後端的連線通常會進行池化(pooling)以供重用。

每個公開的 Web 服務都遵循此結構的某種變體。了解這些跳躍(hops)能讓你能夠推理延遲在哪裡累積、日誌應記錄在哪裡,以及故障可能隱藏在哪裡。

請求生命週期:瀏覽器、DNS、代理、TLS、上游、後端、回應

時間都去哪了?

使用者抱怨 API 感覺很慢。你進行測量,發現請求從開始到結束共耗時 850 毫秒。後端伺服器日誌顯示,應用程式處理該請求僅花了 40 毫秒。代理伺服器(Proxy)日誌則顯示,代理端在其負責的部分(TLS 握手 + 路由 + 回應寫入)花了 50 毫秒。

剩下的 760 毫秒去哪了?請至少列出兩個存在於代理與後端處理時間之外的候選原因,並解釋每一項會如何在測量數據中呈現。

為新服務設計最小化邊緣架構

綜合應用

你已學會正向代理與反向代理的區別、反向代理同時處理的三項核心職責、隱藏源站為何能在每次變更時帶來長期效益,以及請求如何逐跳(hop by hop)流經邊緣節點。

現在,請將所學應用於實務。

一個小型團隊計畫推出名為 notes.example.com 的新服務。使用者將可讀取與撰寫個人筆記。團隊在上線初期將運行兩台後端虛擬機器(VM),並預期在一年內擴展至十台。他們希望為使用者提供 HTTPS、支援新版本的漸進式發布(gradual rollout),且後端 IP 不得對公網暴露。

請為 `notes.example.com` 設計邊緣架構。需涵蓋以下要點:DNS 指向何處、TLS 憑證存放於何處、請求如何到達後端、當後端從兩台擴展至十台時需要做哪些調整,以及一項橫切關注點(cross-cutting concern,例如:速率限制、日誌記錄、標頭重寫等)——你會在邊緣層而非應用程式內部處理該事項。

本課程接下來要講什麼

本課程接下來要講什麼

本節確立了邊緣層的形狀。本課程中還有四節課程將在此基礎上展開:

- 無狀態水平擴展:為什麼代理層(及其後端的後端)可以低成本地倍增,以及在流量激增時計算副本數量的數學方法。

- 入站/出站分離:為什麼單台同時處理入站和出站流量的代理伺服器最終會以意想不到的方式失敗,以及如何拆分這些層級。

- 故障模式與影響範圍:單一設定變更如何連鎖引發中斷,以及如何撰寫無責任歸咎的行動項目以防止問題重演。

- 可觀測性與容量:在邊緣節點應測量哪些指標,以便在用戶發現問題之前,您就能察覺系統異常。

每堂課程皆獨立完整。綜合起來,它們能為您建立一個關於 Web 規模機群(web-scale fleet)的實用心智模型。

配套課程:geometry_of_proxies_and_origins 將本課程的所有內容重新詮釋為有向圖,並探討圖論對請求路徑的啟示。

做得很好。繼續前進。