アジアのリアルタイム: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)から、アジア各地の都市までの下限は次のとおりです。
| 香港から | 大圏距離 | 最短の往復時間 |
|---|---|---|
| 台北 | 810 km | 8 ms |
| マニラ | 1,120 km | 11 ms |
| バンコク | 1,730 km | 17 ms |
| ソウル | 2,090 km | 21 ms |
| シンガポール | 2,590 km | 26 ms |
| 東京 | 2,880 km | 29 ms |
| ジャカルタ | 3,270 km | 33 ms |
| 米国バージニア州アッシュバーン(米国東部) | 13,090 km | 131 ms |
これはベンチマークではなく物理の限界です。どんなネットワークもこれより速くはならず、実際の数字はもっと遅くなります。最後の行は比較のためのものです。米国の多くのサービスはリアルタイム基盤を米国東部に置いており、Pusher のデフォルトのクラスター mt1 もそこにあります。Pusher にもアジアのクラスターはあるので、Pusher を使っているなら、アプリがどのクラスターで作られたか確認してみてください。
リアルタイムが Web ページ以上に遅延を気にする理由
Web ページは読み込み時に何回か往復するだけです。リアルタイム機能は操作のたびに往復します。
- 入力中表示やカーソルは 1 秒に何度もクライアントイベントを送ります。往復が遅いと、ユーザーの動きに追いつきません。
- チャットは、あるユーザーからあなたのサーバー、WebSocket サービス、そしてほかの全員へと届きます。区間ごとに距離が加わります。
- プレゼンス(誰がオンラインか)はメンバーの参加と退出で更新されます。更新が遅いと、退出した人がまだオンラインに見えます。
- 再接続はスマートフォンがネットワークを切り替えたときに起こり、TLS ハンドシェイクと再購読で何度も続けて往復します。
すべての区間を数える
バックエンドがイベントを配信すると、イベントは次の区間を通ります。
- ユーザーの操作からあなたのバックエンドへ
- バックエンドから WebSocket サービスの HTTP API へ
- WebSocket サービスから購読しているすべてのクライアントへ
区間 1 と 3 はユーザーの場所で、区間 2 はバックエンドの場所で決まります。東京のバックエンドがバージニアの WebSocket サービス経由で配信すると、台北にいる 2 人のユーザー間のイベントが太平洋を 2 回横断します。WebSocket サービスはユーザーの近くに置き、できればバックエンドもその近くに置きましょう。
自分で測る
このテストの測定対象: 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 プランで上のスクリプトを自分のアプリに対して実行できます。