深入解析 Round Robin DNS
探索瀏覽器與 Cloudflare 如何挑選伺服器
作者: Zsolt Ero
我為 OpenFreeMap 專案採用 Round Robin DNS 後端的伺服器。本文將探討瀏覽器和 CDN 如何選擇要使用的伺服器。
什麼是 Round Robin DNS?
一般來說,當你使用 Digital Ocean 或 Hetzner 等 VPS 架設網站時,會在 DNS 供應商的管理介面中新增一筆 A 紀錄。
這表示 rr-direct.hyperknot.com
的資料會由 5.223.46.55
這台伺服器提供。
而 Round Robin DNS 則允許你為同一個子網域設定多個伺服器,如下所示:
這樣做不但能分散多台伺服器的負載,還能自動偵測離線的伺服器,並改用其他在線的伺服器。
這是一個非常簡單又好用的解決方案,不需要使用負載平衡器。而且它完全免費,任何 DNS 供應商都能設定。相較之下,負載平衡器的費用可能非常高昂(即使是價格相對合理的 Cloudflare 也是如此)。
理論上的運作方式
我對它的運作原理非常好奇。表面上看起來很簡單,但瀏覽器究竟是如何決定要連到哪一台伺服器的呢?
理論上,RFC 8305 規範的 Happy Eyeballs 機制(也關聯到 RFC 6724)說明了客戶端應該如何排序連線的位址。
這對我來說有點太深奧,但 這段內容 看起來最能解答我的疑問:
如果客戶端具有狀態,並記錄了連線各個位址的往返時間(RTT),應該在規則 8 和 9 之間加入一條規則,優先選擇 RTT 較低的位址。
我的理解是,大致流程如下:
- 檢查伺服器是否在線。
- 依照連線延遲時間,排序在線的伺服器。
實際測試
接著,讓我們看看實際的運作情況。
我在世界各地建立了 3 台 VPS:美國、歐盟和新加坡各一台。並在 Cloudflare 設定了 3 個有代理和 3 個無代理的 A 紀錄。
這些伺服器都使用 nginx,設定如下:
server {
server_name rr-direct.hyperknot.com rr-cf.hyperknot.com;
# 這裡使用萬用字元設定
# 所以 /a/b/c 都會返回相同的 color.png 檔案
location / {
root /data;
rewrite ^ /color.png break;
}
location /server {
alias /etc/hostname;
default_type text/plain;
}
}
所以這些伺服器會提供一個 color.png
(一個 1 像素的紅、綠或藍色 PNG 檔案),以及各自的主機名稱,分別是 test-eu
、test-us
和 test-sg
。
伺服器在線時的客戶端行為
我建立了一個 HTML 測試頁面,以隨機圖片填滿一個 10x10 的網格。
伺服器的顏色對應如下:
- 美國:綠色
- 歐盟:藍色
- 新加坡:紅色
重點是:我的測試地點在歐洲,歐盟伺服器離我最近,美國伺服器其次,新加坡伺服器最遠。照理來說,我應該會看到藍色的方塊!
Chrome 瀏覽器
Chrome 似乎會隨機選擇其中一個伺服器,並持續使用該伺服器。它會在數小時後才重新評估選擇。以這次的測試結果來說,Chrome 選擇了新加坡的伺服器,而且持續使用數小時,儘管它對我來說是最慢的伺服器。
另外,當 Chrome 不使用 HTTP/2 時,會出現一個有趣的現象:有時它會在兩台伺服器之間隨機切換,產生如下的圖案。這裡 Chrome 在歐盟和美國伺服器之間隨機選擇。
Firefox 瀏覽器
Firefox 的行為和 Chrome 類似,它會在啟動時隨機選擇一個伺服器,然後持續使用該伺服器。如果重新啟動瀏覽器,它會選擇另一個隨機的伺服器。
Safari 瀏覽器
最讓我驚訝的是,Safari 總是能正確選擇最近的伺服器。即使伺服器暫時離線,只要重新整理幾次,它總是能再次找到歐盟伺服器!
curl 命令
curl
命令也能正常運作。第一次執行時可能不會選擇最近的伺服器,但只要執行第二次,它總是會連到最近的伺服器。
如果你在世界各地有多台 VPS,可以透過 SSH 執行這個命令,看看會選擇哪一台伺服器:
curl https://rr-direct.hyperknot.com/server
test-us
curl https://rr-direct.hyperknot.com/server
test-eu
Cloudflare
Cloudflare 會根據客戶端的 IP 位址隨機選擇一個伺服器,然後持續使用該伺服器(它的行為類似於 client_ip_hash
除以伺服器數量取餘數)。
如圖片所示,右邊的方塊總是綠色的。在我的家用網路 IP 位址下,無論我怎麼做,Cloudflare 都會連到美國的伺服器。curl
命令也顯示相同的結果。
curl https://rr-cf.hyperknot.com/server
test-us
但如果我改用手機熱點,它總是會連到歐盟的伺服器。
如果我登入幾台 VPS 並執行相同的 curl
命令,就能看到這個現象在全球各地都存在。每台 VPS 都會連到世界各地隨機的一個位置,但總是連到同一個位置。
curl https://rr-cf.hyperknot.com/server
test-sg
部分伺服器離線時的客戶端行為
當其中一台伺服器離線時,會發生什麼事? 假設我停止美國的伺服器:
service nginx stop
Chrome 瀏覽器
Firefox 瀏覽器
Safari 瀏覽器
curl 命令
curl https://rr-direct.hyperknot.com/server
test-eu
如你所見,所有客戶端都能正確偵測到伺服器離線,並改用其他的伺服器。
實際上,它們的故障轉移機制非常優秀,即使我在網頁載入時關閉伺服器,它們也能在 1 秒內切換到其他伺服器!以下是在 Safari 瀏覽器上,以 50x50 網格呈現的動畫:
Cloudflare
那 Cloudflare 呢?如上面的截圖所示,Cloudflare 並不會偵測伺服器是否離線。它會持續連線到它為你的 IP 位址所選擇的伺服器,無論該伺服器是否在線。
如果伺服器離線,使用者會無法連線。使用 curl
命令時,會出現如下的錯誤訊息:
curl https://rr-cf.hyperknot.com/server
error code: 521
我一直在嘗試理解這個行為,我高度懷疑這是他們網路中的一個 bug。我在他們的官方文件中找到一段相關描述:
根據這份文件,以及常理判斷,我認為 Cloudflare 的行為應該和瀏覽器以及 curl
命令一樣。
Cloudflare 的願望清單
- 最基本的要求,應該要能偵測離線的伺服器。
- 更進一步來說,如果能像 Safari 一樣選擇延遲最低的伺服器,那就更棒了!
我的意思是,現在的狀況是,如果你在美國和紐西蘭各有一台伺服器,那麼將會有 50% 的美國使用者連到紐西蘭的伺服器,這完全不合理。而且對 Safari 使用者來說,使用 Cloudflare 反而比不使用還要慢!
目前在 Hacker News 上有一個討論串,Cloudflare 的執行長和技術長都已經回覆了!
註 1:我已盡力理解 Matthew Prince 在 X 上 指出給我 的文章 1、2、3。我的理解是,他們提到的「伺服器」指的是 Cloudflare 的伺服器,而不是 A 紀錄後端的用戶伺服器。此外,我也沒有找到任何與 Round Robin DNS 相關的內容。
註 2:如果你有任何方法,可以讓我不用花錢就能繼續進行這個實驗(不需要在全球各地租用 3 台 VPS),請在下方留言。我很想讓這個實驗繼續下去。是否有任何支援 HTTPS 和 Round Robin DNS 的無伺服器平台?