← ブログ

アジアのリアルタイム:WebSocket サーバーの場所が重要な理由

· Hibira

距離がリアルタイム通信の遅延に下限を設ける理由、香港からアジア各地までの下限、そして自分のユーザーの往復時間を測る方法。

チャットのメッセージ、価格の更新、「入力中」の表示は、およそ 0.1 秒以内に届けば即時に感じられます。その時間の大半はネットワークに使われ、ネットワークの時間の大半はあなたが選ぶひとつのこと、つまり WebSocket サーバーをどこに置くかで決まります。

距離が下限を決める

光ファイバーの中の光は 1 ミリ秒に約 200 km 進みます。真空中の光速のおよそ 3 分の 2 です。したがって 1,000 km 離れたサーバーとの往復には、ルーティングやキューイング、処理を除いても最低 10 ms かかります。実際の海底ケーブルは大圏ルートを通らず、ルーターも遅延を加えるため、実測の往復時間はこの下限の 2〜4 倍になることがよくあります。香港から台北までの実測は約 30 ms で、下限は 8 ms です。

Hibira が現在稼働している香港(AWS ap-east-1)から、アジア各地の都市までの下限は次のとおりです。

これはベンチマークではなく物理の限界です。どんなネットワークもこれより速くはならず、実際の数字はもっと遅くなります。最後の行は比較のためのものです。米国の多くのサービスはリアルタイム基盤を米国東部に置いており、Pusher のデフォルトのクラスター mt1 もそこにあります。Pusher にもアジアのクラスターはあるので、Pusher を使っているなら、アプリがどのクラスターで作られたか確認してみてください。

台北8 msマニラ11 msバンコク17 msソウル21 msシンガポール26 ms東京29 msジャカルタ33 msアッシュバーン(米国東部)131 ms
香港からの最短往復時間(光ファイバー中の光速で決まる下限)

リアルタイムが Web ページ以上に遅延を気にする理由

Web ページは読み込み時に何回か往復するだけです。リアルタイム機能は操作のたびに往復します。

  • 入力中表示やカーソルは 1 秒に何度もクライアントイベントを送ります。往復が遅いと、ユーザーの動きに追いつきません。
  • チャットは、あるユーザーからあなたのサーバー、WebSocket サービス、そしてほかの全員へと届きます。区間ごとに距離が加わります。
  • プレゼンス(誰がオンラインか)はメンバーの参加と退出で更新されます。更新が遅いと、退出した人がまだオンラインに見えます。
  • 再接続はスマートフォンがネットワークを切り替えたときに起こり、TLS ハンドシェイクと再購読で何度も続けて往復します。

すべての区間を数える

バックエンドがイベントを配信すると、イベントは次の区間を通ります。

  1. ユーザーの操作からあなたのバックエンドへ
  2. バックエンドから WebSocket サービスの HTTP API へ
  3. WebSocket サービスから購読しているすべてのクライアントへ

区間 1 と 3 はユーザーの場所で、区間 2 はバックエンドの場所で決まります。東京のバックエンドがバージニアの WebSocket サービス経由で配信すると、台北にいる 2 人のユーザー間のイベントが太平洋を 2 回横断します。WebSocket サービスはユーザーの近くに置き、できればバックエンドもその近くに置きましょう。

ユーザーメッセージを送る
①
バックエンド
② HTTP API
WebSocket サービス
③ WebSocket
すべての購読者
イベントは 3 区間を通る。①と③はユーザーの居場所で決まる

自分で測る

このテストの測定対象: pusher:ping/pusher:pong は接続済み WebSocket とリアルタイムエンドポイント間の往復時間です。バックエンドから購読者への配信遅延、初回接続、ファンアウト、ブラウザー描画は含みません。実際の利用者に近いネットワーク(モバイル回線も含む)で複数回測り、中央値と p95 を比較してください。DNS、TLS、経路、混雑でも結果は変動します。

表は出発点にすぎず、大事なのはユーザーのネットワークです。Pusher プロトコルには、サーバーがすぐに応答する ping メッセージがあるので、何も配信せずに往復時間を測れます。次を ping.mjs として保存し、WebSocket を標準で備えた Node.js 22 以降で実行してください。

// node ping.mjs YOUR_APP_KEY [host]
const [key, host = 'ws.hibira.io'] = process.argv.slice(2);
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();
};

ユーザーのいる場所から実行してください。サービスを提供する国ごとのクラウドサーバーや、自宅回線につないだ同僚のノート PC などです。比べるべきは中央値で、最良値はルートが下限にどれだけ近いかを示します。モバイル回線はさらに遅延を加えるので、スマートフォンのテザリングでも試してみてください。

実際のユーザーの数字を見るには、pusher-js が connecting から connected になるまでの時間を計り、ユーザーの国と一緒に分析ツールへ送ります。

私たちの取り組み

Hibira が現在香港で稼働しているのは、東アジアと東南アジアのほぼ中央にあるからです。次に準備しているリージョンは東京、その次がシンガポールです。アプリはひとつのリージョンに固定されるので、ユーザーの大半に最も近いリージョンを選べます。

移行する前に自分のユーザーの数字を見たい場合は、Free プランで上のスクリプトを自分のアプリに対して実行できます。