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

兩種流量方向,一個盒子

歡迎

大多數架構圖表顯示流量只有一個方向:客戶端在上方,伺服器在下方,箭頭指向下方。現實中流量有兩種方向。

入口:外部客戶通過這條路徑達到您的服務。您的網絡邊緣的反向代理終止TLS,路由請求並執行訪問策略。

出口:您的服務通過這條路徑達到外部服務。調用支付處理器的API,獲取網絡-hook目標,向夥伴發送請求。通常通過允許清單的前向代理或NAT閘道。

許多架構從一個盒子處理兩個開始。它們運行得好,直到有一天不再如此。失敗模式微妙,只有在內部服務足夠多時才會出現,並且教會了關注分離的重要教訓。

在這堂課的結束時,您將了解到:

- 為什麼入口和出口代表著根本不同的流量模式,具有不同的擴展軸和不同的失敗模式

- Hairpin NAT 和一個試圖連接到自己失敗的代理

- 架構分叉:一個盒子變成兩個,然後每個盒子獨自擁有

- 安全隔離的好處:每個側面都可以鎖定到其真正允許的對手

- 如何識別您的單一盒子設計已經跨越了分裂所必需的門檻

為什麼方向需要不同的工具

兩個不同的負載在一個網絡邊界上

入口流量特點

- 來自外部方(整個互聯網)

- 量與用戶基數成正比

- TLS終止,請求路由,源端限制

- 深度防禦關注:DDoS,濫用,抓取

- 公共IP需要接受來自任何人的連接

出口流量特點

- 來自您自己的服務(一個已知的,有限的客戶集)

- 量與服務之間的呼叫模式和外部API呼叫模式成正比

- 源 IP 允許清單 (您有一個固定出bounds IP,夥伴信任)

- 深度防禦關注點:資料外洩、內部服務被攻擊後呼叫出bounds

- 應拒絕來自您自己的服務之連接

關鍵不對稱性:入口接受世界上的流量;出口僅接受您自己的服務流量。將兩者放在同一機器上意味著該機器必須同時從世界(入口)和您自己的服務(出口)接收連接。滿足一方的防火牆規則會對另一方產生阻礙。

成長路線:一個微小的項目可以將兩者都藏在一個IP和一個工具後面,因為流量很小,夥伴IP允許清單也很短。隨著項目的成長,兩個角色的摩擦會增加,一天,特定的失敗模式(hairpin NAT)迫使分離。

入口與出口:不同來源,不同目的地,不同要求

一個小型創業公司將一切(入口反向代理,出口前向代理/NAT,內部服務)設置在一個單一VM上,使用一個公共IP。由於這看起來還好。隨著他們的成長,這個設計將遇到哪兩個具體的失敗模式或運營痛苦,對每一個情況下,解釋背後的原因。

那個bug迫使分離

一個清潔的停機故事

想象一個在生產環境中發生的實際架構分叉。以下的名字已經被更改;形狀與實際世界中團隊遇到的形狀相同。

一個組織在 203.0.113.5 上運行單個代理伺服器。它處理入口(對用戶的443端口)和出口(對內部服務呼叫出bounds的1080端口SOCKS5)。內部服務位於私有子網中,並將所有出bounds流量通過該SOCKS5代理 203.0.113.5:1080

在同一個 203.0.113.5 上主機的服務是 api.example.com。公共DNS將 api.example.com 解析為 203.0.113.5

現在,另一個內部服務需要呼叫 api.example.com。其出bounds路徑為:

1. 內部服務解析 api.example.com203.0.113.5

2. 內部服務將請求通過SOCKS5 egress代理在 203.0.113.5:1080 發送

3. 代理嘗試從自身到 203.0.113.5:443 打開一個連接

4. 連接被拒絕。該包必須exit並重新入同一個NAT,許多網絡堆棧將拒絕。代理無法通過其公眾IP將自己連接到自身。

這是 hairpin NAT:一個從 NAT 出口的包,需要通過相同的 NAT 才能到達其目的地。沒有在路由層面特別支持 hairpin,該包將會被丟棄。

為什麼它會在後面出現

在項目的早期,每個內部服務要么通過私有主機名(internal-api.local)與其他內部服務通信,要么不叫回自己的組織的公共服務。hairpin 路徑根本不存在。

然後,出現了一個新功能,服務 A 需要呼叫 api.example.com(一個公共主機名)。hairpin 路徑被激活。連接被拒絕。出現了中斷。

修復了症狀(強制解析器給出 api.example.com 的私有 IP,而不是公共 IP)。根據原因:一個單獨的盒子在做太多的工作。

Hairpin NAT:包從 NAT 出口離開,無法重新進入相同的 NAT

架構分叉

一個盒子變成兩個

清潔的修復:將代理分成兩個機器。

Ingress 服務器(公共 IP 203.0.113.5):

- Caddy / 反向代理,埠 80, 443

- 公共 DNS 記錄指向這裡

- 主持 api.example.comapp.example.com

Egress 服務器(不同的公共 IP 203.0.113.99):

- SOCKS5 / 直接代理,埠 1080

- 防火牆限制進入連接至內部子網 IP 的連接

- 內部服務器將所有出bounds 連接通過這個地址進行路由

這買到了什麼

1. Hairpin 已解決。 內部服務呼叫 api.example.com 會通過 203.0.113.99(egress)路由,然後正常連接到 203.0.113.5(ingress,不同的 IP)。NAT 循環消失,因為這兩個 IP 住在不同的機器上。

2. 安全隔離。 egress 服務器的防火牆可以鎖定在一個有限的內部 IP 集合上。ingress 服務器的防火牆保持對外世界開放。兩個獨立的規則集,各自清晰地表達一個角色。

3. 獨立擴展。 Ingress 的帶寬與用戶數量成比例;egress 的帶寬與內部服務活動成比例。升級一個沒有觸及另一個。

4. 故障隔離。 如果 egress 配置錯誤,公共站點不會被破壞。對公共站點進行 DDoS 攻擊也不會讓 egress 帶寬枯竭。

5. 更清晰的mental模型。 每台机器都有一项工作。工程师不用考虑egress,而是reason about ingress concerns & vice versa.

在分裂後,內部服務仍然需要呼叫 `api.example.com`。從內部服務到 api backend 的新包路徑進行走讀。包括:內部服務首先連接到的 IP,該機器如何處理請求,接下來連接到的 IP,以及響應的去向。

两个轴,两个-sizing决策

独立扩展

在分裂之前,两者方向的增长都压力在同一台机器上。在分裂之后,每个方向都有自己的provisioning。

Ingress sizing: 根据用户规模扩展。容量决策位于公共面向层(更多的反向代理实例,更大的VM,CDN在前面)。带宽预算根据峰值用户流量计算。

Egress sizing: 根据内部服务到外部API调用量扩展。通常由webhook传递,支付处理器调用或第三方数据抓取主导。带宽预算根据内部调用模式计算。

故障隔离: 公共ingress上的DDoS不再吃egress带宽(那些支付处理器调用仍然通过)。egress proxy失效不再导致公共站点下线(用户仍然可以访问站点;只有内部出bounds调用失败)。

不同的SLO: ingress可用性对用户重要(可见的站点中断);egress可用性对操作员重要(后台失败可能需要更长时间检测)。每个侧都可以承担自己的SLO。

多个egress服务器

一旦egress角色成为自己的机器,下一个明显的动作就是在负载均衡器后面运行几个egress机器以实现HA。每个新的内部服务都指向egress主机名(哪个解析为负载均衡池)而不是单个IP。

与分布式系统的其余部分一样:一旦一层无状态且有自己角色的,它便可以廉价地增加。

一个新的合作伙伴集成

您的组织按照设计运行ingress / egress分裂。egress服务器具有一个固定的公共IP (203.0.113.99),您已将其allowlisted与三个现有合作伙伴API(支付处理器,短信网关,电子邮件提供商)。

一個產品團隊想要添加一個第四個整合:一個回呼傳遞系統,該系統會將回呼傳遞給全球各地的客戶端。預測的流量量為每分鐘10,000個呼叫,峰值達到30,000個。

决定:这个新的集成是否应放在现有的egress服务器上,还是需要一个单独的egress路径?理由包括带宽,故障隔离以及无论哪种方式都需要更新现有的合作伙伴allowlists。

為一個逐漸擴大的服務設計網絡邊界

結合

你已經學會了為什麼入口和出口需要不同的工具,實際部署中的髮夾NAT失效強制分離,以及在分離落地後,獨立擴展、安全隔離和故障隔離是如何累積的。

應用所有四個。

一家中型的SaaS公司為他們的用戶提供三個產品子域名(appapiadmin),以及四個出bounds整合(Stripe,Twilio,SendGrid,一個客戶回呼系統)。今天,所有東西都位於一個公共IP的單一代理機器後面。他們已經開始收到髮夾NAT失效的中斷報告,當內部服務嘗試調用api.example.com時。他们想要設計一個持久的解決方案。

為這家公司提出入口/出口架構。解決方案包括:有多少機器、哪些IP服務什麼角色、每個子域名的DNS指向哪、哪些出bounds整合共享出口路徑(並且哪些應該分開)以及新的設計比舊設計能夠實現的具體監控問題。

這個課程的下一步

下一步

你現在已經看到了分佈式系統中的一個最清晰的分擔重任重構:一個盒子變成了兩個,每個都有明確的角色,系統在此過程中獲得了擴展、安全性和故障隔離的好處。

下一個課程(cs_distsys_failure_modes_and_blast_radius)將故障隔離推理擴展。你將閱讀一個清潔的DNS-SERVFAIL後 mortem,識別出瀰漫的故障模式,並撰寫無罪的行動項目,目標是系統而不是人們。

陪讀課: geometry_of_ingress_egress_separation 將分裂視為一個雙部圖並探討切點、網絡分區以及圖論對於網絡邊界的解釋。

好極了。繼續前進。