【问题标题】:Socket.IO Maximum call stack size exceededSocket.IO 超出最大调用堆栈大小
【发布时间】:2013-01-10 13:41:14
【问题描述】:

我编写了一个小型 Socket.IO 服务器,它工作正常,我可以连接到它,我可以发送/接收消息,所以一切正常。此处仅提供代码的相关部分:

var RedisStore = require('socket.io/lib/stores/redis');
const pub = redis.createClient('127.0.0.1', 6379);
const sub = redis.createClient('127.0.0.1', 6379);
const store = redis.createClient('127.0.0.1', 6379); 

io.configure(function() {
  io.set('store', new RedisStore({
    redisPub    : pub, 
    redisSub    : sub, 
    redisClient : store
  }));
});

io.sockets.on('connection', function(socket) {
 socket.on('message', function(msg) {
    pub.publish("lobby", msg);
  });


  /*
   * Subscribe to the lobby and receive messages.
   */
  var sub = redis.createClient('127.0.0.1', 6379);
  sub.subscribe("lobby");
  sub.on('message', function(channel, msg) {
    socket.send(msg);
  });
});

我还编写了一个如下所示的脚本,它连接到服务器并在 setInterval 函数中产生连接,该函数每 10 毫秒产生一个新连接,因此它产生了相当多的连接。

#!/usr/bin/env node

var io = require('socket.io-client');
var reconn = {'force new connection': true};
var sockets = [];

var num = 1000;

function startSocket(i) {
  sockets[i] = io.connect("http://127.0.0.1:8080", reconn);
  sockets[i].on('connect', function() {
    console.log("Socket["+i+"] connected.");
  });
  sockets[i].on('message', function(msg) {
    console.log("Socket["+i+"] Message received: "+msg);
  });
}



/*
 * Start number of sockets.
 */
for(var i=0; i<num; i++) {
  startSocket(i);
}



/*
 * Send messages forever.
 */
setInterval(function() {
    for(var i=0; i<num; i++) {
      sockets[i].send("Hello from socket "+i+".");
    }
}, 10);

此脚本是一个基准测试工具,可生成 1000 个与服务器的连接,但在运行几分钟后,服务器会因以下错误消息而死机:

node.js:0 // 版权所有 Joyent, Inc. 和其他 Node 贡献者。 ^ RangeError: 超出最大调用堆栈大小

我知道没有足够的可用堆栈空间,所以会发生异常并终止进程,但是即使我使用 --stack-size 变量扩大堆栈,这实际上并不能解决问题,因为我可以总是产生更多的连接,这最终会杀死服务器。

我的问题是:我该如何防止这种情况发生。这是一个有效的 DoS 场景,任何人都可以破解这个小脚本并强制节点服务器终止,但我想防止这种情况发生。我希望 Node 服务器永远不会终止,只是慢慢地处理消息。

如果可以防止这种情况的任何想法。我不确定我是否要阻止IP,因为我也希望手机登录系统,其中许多使用相同的IP,因此节点服务器可能会错误地认为DoS正在到位移动网络操作并阻止其 IP。

谢谢

【问题讨论】:

  • 一个快速而肮脏的解决方案是将服务器隐藏在代理/负载平衡器后面

标签: node.js webserver socket.io benchmarking


【解决方案1】:

如果您希望您的节点服务器永远运行,无论如何,请使用https://github.com/nodejitsu/forever

至于异常——我的直觉是var sub = redis.createClient('127.0.0.1', 6379); 可能会在每次建立连接时在堆栈中分配一个变量。

我会首先尝试将var subs = [] 放在全局范围内,然后 subs[socket.id] = redis.createClient('127.0.0.1', 6379);

或者像socket.sub = redis.createClient('127.0.0.1', 6379); 这样的东西来搭载现有的,希望是基于堆的,socket.io 数据结构。

如果不起作用,请尝试通过删除 Redis 的使用来隔离问题...

【讨论】:

    猜你喜欢
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    • 2015-12-29
    • 2017-12-27
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多