由于 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 个通道作为传输消息的媒介.
