由于 nodejs 天生只支持单进程,虽然 nodejs 使用非阻塞 异步事件驱动,在单进程下性能足够优秀,但是在用户量多的时候也是不行的
使用 socket.io
默认把用户连接数据保存在内存中的,假如我们的服务器是多核服务器,开了多个进程,或者是多个服务器之间多个进程,那么每个进程间是不存在数据共享的,即在不同的进程下连接的用户是不能够给其它用户发送消息的,同样如果部署在 Serverless 上更是如此 (一个连接一个实例)
所以需要有个适配器解决这一问题,适配器作为一个组件,负责将事件广播到所有或部分客户端.
socket.io
提供了以下 4 个适配器供使用
- Redis 适配器
- MongoDB 适配器
- Postgres 适配器
- Cluster 适配器
由于 Redis 数据库的特性,显然它是作为 socket.io
适配器的最佳选项!
# 安装必要模块
$ npm install -S @socket.io/redis-adapter @socket.io/redis-emitter |
# 集成 @socket.io/redis-adapter
使用了 nestjs-redis-plus
, 作者帮我们集成好了 @socket.io/redis-adapter
, 只需要在 main.ts
中加入声明即可
//main.ts | |
import { NestFactory } from '@nestjs/core'; | |
import { VersioningType } from "@nestjs/common"; | |
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; | |
import { AppModule } from './app.module'; | |
// 引入模块 | |
import { IoRedisAdapter, getAdapterConstructorToken } from 'nestjs-redis-plus'; | |
async function bootstrap() { | |
const app = await NestFactory.create(AppModule); | |
app.setGlobalPrefix('api');// 统一前缀 | |
app.enableVersioning({ | |
type: VersioningType.HEADER, | |
header: 'ApiVersion', | |
}); | |
const config = new DocumentBuilder() | |
.setTitle('管理系统API文档') | |
.setDescription('管理系统API文档') | |
.setVersion('0.0.1') | |
.addTag('api') | |
.build(); | |
const document = SwaggerModule.createDocument(app, config); | |
SwaggerModule.setup('api', app, document); | |
// 指定使用 IORedis 适配器 | |
const adapterConstructor = app.get(getAdapterConstructorToken()); | |
const adapter = new IoRedisAdapter(app, adapterConstructor); | |
app.useWebSocketAdapter(adapter); | |
await app.listen(9000); | |
console.log("server listen on 9000!"); | |
} | |
bootstrap(); |
//app.module.ts | |
RedisModule.forRootAsync({ | |
useFactory: async (config: ConfigService) => config.get('redis'), | |
inject: [ConfigService] | |
}), | |
// 引入适配器控制器 | |
RedisModule.forAdapterConstructor(), |
至此,非常简单的就集成好了 Redis 适配器,这样使用多个服务端可以把消息广播到所有客户端,用户增多只需要增加服务端即可.
使用 Redis-cli
工具查看
$ redis-cli | |
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. | |
127.0.0.1:6479> pubsub channels | |
1) "socket.io-request#/#" | |
2) "socket.io-response#/#" | |
3) "socket.io-response#/#IzmXZC#" | |
127.0.0.1:6479> |
默认在 Redis 中创建了 3 个通道作为传输消息的媒介.