iT邦幫忙

0

WebSocket 延遲幾乎由「伺服器放哪裡」決定:從台北看亞洲各區的物理下限與實測腳本

  • 分享至 

  • xImage
  •  

利益揭露:作者是 Pusher 相容 WebSocket 服務 Hibira 的開發團隊,下文的腳本不綁任何服務,任何 Pusher 相容伺服器(Pusher、Soketi、Laravel Reverb 等)都能量。

聊天訊息、報價跳動、「對方正在輸入…」,只要在大約 0.1 秒內送達,使用者就會覺得是即時的。這個時間預算大部分花在網路上,而網路時間大部分由一件事決定:WebSocket 伺服器放在哪裡。

很多國外 SaaS 預設把即時服務放在美國東部。如果沒特別注意,兩個在台北的使用者互傳一則訊息,事件可能要橫越太平洋兩次。這篇文章先算出物理下限,再給一支腳本讓你從自己使用者所在的網路實測。

光速決定了下限

光在光纖裡每毫秒大約走 200 公里,約是真空光速的三分之二。所以和 1,000 公里外的伺服器來回一趟,就算不計路由、排隊和處理,至少也要 10 ms。實際的海纜不會走大圓航線、路由器也會增加延遲,實測值常是下限的 2 到 4 倍(香港到台北下限約 8 ms,我們實測約 30 ms)。

從台北到各主要雲端區域的下限:

從台北到 大圓距離 最短來回時間
香港 約 810 km 約 8 ms
首爾 約 1,490 km 約 15 ms
東京 約 2,100 km 約 21 ms
新加坡 約 3,250 km 約 32 ms
美國西部(奧勒岡) 約 10,000 km 約 100 ms
美國東部(維吉尼亞) 約 12,600 km 約 126 ms

這是物理極限、不是 benchmark:任何網路都不可能比它快,實際只會更慢。Pusher 的預設叢集 mt1 也在美國東部(Pusher 也有亞洲叢集,正在用的人可以確認一下自己的 app 建在哪個叢集)。

為什麼即時功能比網頁更怕延遲

網頁載入時只來回幾次;即時功能則是每一次互動都要付一次來回。

  • 輸入中提示、游標同步:每秒送好幾次 client event,來回一慢就跟不上手。
  • 聊天:從發送者到你的後端、到 WebSocket 服務、再到所有人,每一段都會加上距離。
  • Presence(誰在線上):更新慢的話,已經離開的人還會掛在線上名單。
  • 重新連線:手機在 Wi-Fi 和 4G 之間切換時,TLS 握手加上重新訂閱,會連續來回好幾次。

把每一段都算進去

後端推送一個事件時,事件會經過三段:

  1. 使用者操作 → 你的後端
  2. 你的後端 → WebSocket 服務的 HTTP API
  3. WebSocket 服務 → 所有訂閱的用戶端

第 1、3 段取決於使用者在哪,第 2 段取決於後端在哪。原則是:WebSocket 伺服器放在使用者附近,可以的話後端也放在它附近。

自己量

表格只是起點。Pusher 協定有 pusher:ping,伺服器會立刻回 pusher:pong,不用推送任何事件就能量來回時間。存成 ping.mjs,用 Node.js 22 以上(內建 WebSocket)執行:

// node ping.mjs YOUR_APP_KEY HOST   例:node ping.mjs abc123 ws-ap1.pusher.com
const [key, host] = process.argv.slice(2);
if (!key || !host) throw new Error('usage: node ping.mjs APP_KEY HOST');
const ws = new WebSocket(`wss://${host}/app/${key}?protocol=7&client=js&version=8.4.0`);
const times = [];
let sent = 0;

const ping = () => {
  sent = performance.now();
  ws.send(JSON.stringify({ event: 'pusher:ping', data: {} }));
};

ws.onmessage = (msg) => {
  const { event } = JSON.parse(msg.data);
  if (event === 'pusher:pong') times.push(performance.now() - sent);
  if (event !== 'pusher:connection_established' && event !== 'pusher:pong') return;
  if (times.length < 20) return void setTimeout(ping, 250);
  times.sort((a, b) => a - b);
  console.log(`best ${times[0].toFixed(1)} ms, median ${((times[9] + times[10]) / 2).toFixed(1)} ms`);
  ws.close();
};

要注意的是,這支腳本量的是已經建立好的 WebSocket 來回時間,不包含推送到訂閱者的時間,也不包含建立連線的時間。建議從幾種代表性的網路(包括行動網路)多量幾次,看中位數和 p95。

只要換 HOST,任何 Pusher 相容的伺服器都能用同一支腳本比較,包括自架的 Laravel Reverb 或 Soketi。

  • 比較 中位數;最小值可以看出路由離下限有多近。
  • 從使用者所在的地方量:各國的雲端主機、家用網路的筆電,還有 手機熱點(行動網路會再多一層延遲)。
  • 想看真實使用者的數字,可以記錄 pusher-js 從 connecting 到 connected 的時間,連同國家一起送進分析工具。

小結

  • 先用距離表估出下限,再用腳本從使用者實際所在的網路量中位數和 p95。
  • 使用者集中在台灣的話,香港、東京、新加坡的下限都在 35 ms 內;美國區域至少 100 ms 起跳。
  • 換服務或換區域之前,用同一支腳本、同一批網路量一次,數字會比任何行銷頁可靠。

歡迎在留言分享你從自己網路量到的數字,特別是中華電信、台灣大哥大、遠傳行動網路的結果,我們很好奇差異有多大。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言