水平スケーリング
アプリケーションが一時的なネットワーク中断に対して回復力を持つようになったので、数千の同時接続クライアントをサポートできるように、水平にスケールする方法を見てみましょう。
- 水平スケーリング (「スケールアウト」とも呼ばれます) とは、新しい需要に対応するためにインフラストラクチャに新しいサーバーを追加することを意味します。
- 垂直スケーリング (「スケールアップ」とも呼ばれます) とは、既存のインフラストラクチャにさらに多くのリソース (処理能力、メモリ、ストレージなど) を追加することを意味します。
最初のステップ: ホストで使用可能なすべてのコアを使用しましょう。デフォルトでは、Node.js は JavaScript コードをシングルスレッドで実行します。つまり、32 コア CPU を搭載していても、使用されるのは 1 つのコアだけです。幸いなことに、Node.js の cluster
モジュールは、コアごとに 1 つのワーカー スレッドを作成する便利な方法を提供します。
また、Socket.IO サーバー間でイベントを転送する方法も必要になります。このコンポーネントを「アダプター」と呼びます。


そこで、クラスター アダプターをインストールしましょう
- NPM
- Yarn
- pnpm
npm install @socket.io/cluster-adapter
yarn add @socket.io/cluster-adapter
pnpm add @socket.io/cluster-adapter
次に、プラグインしましょう
- CommonJS
- ES モジュール
const express = require('express');
const { createServer } = require('node:http');
const { join } = require('node:path');
const { Server } = require('socket.io');
const sqlite3 = require('sqlite3');
const { open } = require('sqlite');
const { availableParallelism } = require('node:os');
const cluster = require('node:cluster');
const { createAdapter, setupPrimary } = require('@socket.io/cluster-adapter');
if (cluster.isPrimary) {
const numCPUs = availableParallelism();
// create one worker per available core
for (let i = 0; i < numCPUs; i++) {
cluster.fork({
PORT: 3000 + i
});
}
// set up the adapter on the primary thread
return setupPrimary();
}
async function main() {
const app = express();
const server = createServer(app);
const io = new Server(server, {
connectionStateRecovery: {},
// set up the adapter on each worker thread
adapter: createAdapter()
});
// [...]
// each worker will listen on a distinct port
const port = process.env.PORT;
server.listen(port, () => {
console.log(`server running at http://localhost:${port}`);
});
}
main();
import express from 'express';
import { createServer } from 'node:http';
import { Server } from 'socket.io';
import sqlite3 from 'sqlite3';
import { open } from 'sqlite';
import { availableParallelism } from 'node:os';
import cluster from 'node:cluster';
import { createAdapter, setupPrimary } from '@socket.io/cluster-adapter';
if (cluster.isPrimary) {
const numCPUs = availableParallelism();
// create one worker per available core
for (let i = 0; i < numCPUs; i++) {
cluster.fork({
PORT: 3000 + i
});
}
// set up the adapter on the primary thread
setupPrimary();
} else {
const app = express();
const server = createServer(app);
const io = new Server(server, {
connectionStateRecovery: {},
// set up the adapter on each worker thread
adapter: createAdapter()
});
// [...]
// each worker will listen on a distinct port
const port = process.env.PORT;
server.listen(port, () => {
console.log(`server running at http://localhost:${port}`);
});
}
以上です!これにより、マシンで使用可能な CPU ごとに 1 つのワーカー スレッドが生成されます。実際に動作している様子を見てみましょう。
アドレス バーでわかるように、各ブラウザ タブは異なる Socket.IO サーバーに接続されており、アダプターはそれらの間で チャット メッセージ
イベントを転送しているだけです。
現在、5 つの公式アダプター実装があります
したがって、ニーズに最も適したものを選択できます。ただし、一部の実装では接続状態の回復機能がサポートされていないことに注意してください。互換性マトリックスはこちらにあります。
ほとんどの場合、Socket.IO セッションのすべての HTTP リクエストが同じサーバーに到達するようにする必要があります (「スティッキー セッション」とも呼ばれます)。ただし、ここでは各 Socket.IO サーバーに独自のポートがあるため、これは必要ありません。
詳細についてはこちらをご覧ください。
これで、チャット アプリケーションが完成しました。このチュートリアルでは、次の方法を説明しました。
- クライアントとサーバー間でイベントを送信する
- 接続されているすべてのクライアントまたは一部のクライアントにイベントをブロードキャストする
- 一時的な切断を処理する
- スケールアップする
これで、Socket.IO によって提供される機能の概要をよりよく把握できたはずです。さあ、あなた自身のリアルタイム アプリケーションを構築する時です!
- CommonJS
- ES モジュール
この例は、ブラウザで直接実行できます
この例は、ブラウザで直接実行できます