最近接触到websocket,需求很简单,利用websocket让用户参与一个1v1的小游戏。
环境是分布式部署,且每台服务器是多进程,web服务器使用nodejs,websocket框架选用了socket.io。
遇到的问题:
首先,在单服务器调研,在利用nodejs多进程(cluster)时,建立websocket时会出现400报错,后来发现了是多进程的问题,用户访问服务器时不能保证每次访问到相同的进程中,所以后台会报错"Session ID unknown",可能是socket.io为了保证偶尔有可能会变成long polling,必须保证前后台要传递一个session id,但是每次页面刷新时,重新发起websocket应该和上次的刷新前的websocket没关系了才对,也有可能是socket.io为了保证与服务器重连节省资源才引入了session id,不知道我的理解对不对。
在网上查找了大量的资料,也看了socket.io官网的推荐方案(http://socket.io/docs/using-multiple-nodes/),有两种:
nginx
利用配置ip_hash让用户每次都连接到固定的进程,没玩过nginx不太懂。
redis
看了网上最多的既成的推荐方案也是redis,之前没有接触过redis,不知道其运行原理,大概了解之后,发现他是一个key-value的持久化存储,与MemCache、mongoDB类似,官网给出的代码示例:
var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
示例很简单,把请求弄一个适配器转向到连接redis服务,但是原理是什么样的呢,共享内存的方案吗,不太懂所以也没下手。
最后我选用了一个比较傻的方案,在不同的子进程中启动websocket服务时选用了不同的端口,比如一台服务器8核,会有8个端口3001-3008,这样用户连接某个固定端口时就不会再出现400error了,但是用户命中到不同的端口后,相互之间如何通信仍然是个问题,这只是单台服务器实验,如果是集群,相互通信也是一个问题,而且关键是否需要每次用户都连接到同一个端口和同一台服务器呢?说到底,还是对websocket了解太少了,希望能在这里得到一点指导和帮助。
如果是用 Redis, 我猜测是使用 Redis 的订阅/发布功能实现,这样就能很好的解决不同服务器上用户相互通信的问题。