水平扩展
现在我们的应用程序已经能够应对临时的网络中断,让我们看看如何通过水平扩展来支持数千个并发客户端。
备注
- 水平扩展(也称为“扩展出”)是指向基础设施中添加新的服务器以应对新的需求
- 垂直扩展(也称为“扩展上”)是指为现有基础设施添加更多资源(处理能力、内存、存储等)
第一步:利用主机的所有可用核心。默认情况下,Node.js 在单线程中运行 JavaScript 代码,这意味着即使有 32 核 CPU,也只会使用一个核心。幸运的是,Node.js 的 cluster
模块 提供了一种方便的方法来为每个核心创建一个工作线程。
我们还需要一种方法在 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 modules
index.js
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();
// 为每个可用核心创建一个工作线程
for (let i = 0; i < numCPUs; i++) {
cluster.fork({
PORT: 3000 + i
});
}
// 在主线程上设置适配器
return setupPrimary();
}
async function main() {
const app = express();
const server = createServer(app);
const io = new Server(server, {
connectionStateRecovery: {},
// 在每个工作线程上设置适配器
adapter: createAdapter()
});
// [...]
// 每个工作线程将监听不同的端口
const port = process.env.PORT;
server.listen(port, () => {
console.log(`server running at http://localhost:${port}`);
});
}
main();
index.js
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();
// 为每个可用核心创建一个工作线程
for (let i = 0; i < numCPUs; i++) {
cluster.fork({
PORT: 3000 + i
});
}
// 在主线程上设置适配器
setupPrimary();
} else {
const app = express();
const server = createServer(app);
const io = new Server(server, {
connectionStateRecovery: {},
// 在每个工作线程上设置适配器
adapter: createAdapter()
});
// [...]
// 每个工作线程将监听不同的端口
const port = process.env.PORT;
server.listen(port, () => {
console.log(`server running at http://localhost:${port}`);
});
}
完成了!这将在您的机器上为每个可用的 CPU 生成一个工作线程。让我们看看它的实际效果:
如您在地址栏中所见,每个浏览器标签页连接到不同的 Socket.IO 服务器,适配器只是简单地在它们之间转发 chat message
事件。
提示
目前有 5 种官方适配器实现:
您可以选择最适合您需求的那个。不过,请注意某些实现不支持连接状态恢复功能,您可以在这里找到兼容性矩阵。
备注
在大多数情况下,您还需要确保 Socket.IO 会话的所有 HTTP 请求都到达同一服务器(也称为“粘性会话”)。不过这里不需要这样,因为每个 Socket.IO 服务器都有自己的端口。
更多信息请查看这里。
这就完成了我们的聊天应用程序!在本教程中,我们学习了如何:
- 在客户端和服务器之间发送事件
- 向所有或部分连接的客户端广播事件
- 处理临时断线
- 扩展
您现在应该对 Socket.IO 提供的功能有更好的了解。现在是您构建自己的实时应用程序的时候了!
信息
- CommonJS
- ES modules
您可以在浏览器中直接运行此示例:
您可以在浏览器中直接运行此示例: