Nodejs socket.io负载均衡问题

Nodejs socket.io负载均衡问题

想使用nginx进行负载均衡,因为想做一个消息中心,想专门问nodejs做一个负载均衡。网上资料基本都看遍了。现在nginx也开始支持websocket的反向代理了,就不用使用那个tcp组件了。看了网上的教程,我的nginx配置是这样的 upstream nginx_test { server 10.22.7.171:7000; keepalive 20; } server { listen 8001; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection “Upgrade”; proxy_pass http://nginx_test; } } 当upstream里只有一个服务器时都是正常的。但一旦里面添加另外一个服务器之后,引用页面就一直报错: XHR finished loading: “http://10.22.7.171:8001/socket.io/1/?t=1382959945782”. socket.io.js:1659 重复出现上述代码,一直到最后出现: Uncaught Error: InvalidStateError: DOM Exception 11 我想是不是心跳包也被均衡了,导致无法进行长连接了? 具体应该怎么配置socket.io的负载均衡了,请大神讲解帮忙讲解一下~~~


5 回复

在使用 Node.js 和 Socket.IO 进行负载均衡时,确实会遇到一些挑战,尤其是与 Nginx 配合使用时。你的问题可能是因为 WebSocket 的连接状态没有正确传递给后端服务器。Nginx 默认情况下不会将 WebSocket 连接的 session 信息传递给后端服务器,这会导致连接断开。

解决方案

1. 使用 sticky sessions(粘性会话)

粘性会话确保来自同一个客户端的所有请求都被路由到同一个后端服务器。这样可以保证 WebSocket 连接不会被意外地断开。

2. 配置 Nginx

你需要在 Nginx 中启用 sticky sessions。可以通过第三方模块如 ngx_http_upstream_check_module 来实现。

以下是一个示例配置:

http {
    upstream websocket_backend {
        ip_hash; # 启用粘性会话
        server 10.22.7.171:7000;
        server 10.22.7.172:7000;
    }

    server {
        listen 8001;

        location / {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-NginX-Proxy true;
        }
    }
}

在这个配置中,ip_hash 指令用于启用粘性会话。这会确保来自同一个客户端的所有请求都被路由到同一个后端服务器。

3. 配置 Socket.IO

在后端服务器上,你需要确保每个实例都能处理 WebSocket 连接。Socket.IO 提供了一些选项来帮助你处理这种情况。

const io = require('socket.io')(server, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"]
    }
});

io.on('connection', (socket) => {
    console.log('A user connected');

    socket.on('disconnect', () => {
        console.log('A user disconnected');
    });
});

总结

通过使用 ip_hash 指令,你可以确保 WebSocket 连接不会被错误地路由到不同的服务器,从而避免连接断开的问题。同时,确保你的 Socket.IO 实例能够正确处理 WebSocket 连接。这样可以有效解决负载均衡中的 WebSocket 问题。


自己顶一下~~

能说的具体一点吗?还有为什么要用到session呢?

我只想实现最简单的负载均衡就行了。对半分就可以

你的问题主要在于Nginx配置时,由于HTTP请求在不同的服务器之间分配,导致Socket.IO的握手阶段出现问题。解决这个问题的方法是确保每个客户端与一个特定的后端服务器建立持久连接。

解决方案

你可以通过使用Nginx的ip_hash来解决这个问题。ip_hash会根据客户端的IP地址分配请求到相同的后端服务器,从而保证每个客户端与同一个后端服务器保持长连接。

Nginx配置修改

upstream nginx_test {
    ip_hash;  # 使用ip_hash来保证每个客户端连接到同一个后端服务器
    server 10.22.7.171:7000;
    server 10.22.7.172:7000;
    keepalive 20;
}

server {
    listen 8001;
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://nginx_test;
    }
}

示例代码

假设你有两个Node.js服务器实例分别运行在10.22.7.171:700010.22.7.172:7000上,并且都已经安装了socket.io模块。以下是一个简单的示例代码:

// server.js
const http = require('http');
const io = require('socket.io')(8000);

io.on('connection', (socket) => {
    console.log('A user connected:', socket.id);
    
    socket.on('disconnect', () => {
        console.log('User disconnected:', socket.id);
    });
});

console.log('Server running on port 8000');

确保两个服务器实例都监听不同的端口(例如8000和8001)。

总结

通过使用ip_hash,你可以确保每个客户端始终连接到同一个后端服务器,从而避免由于请求被不同服务器处理而导致的连接问题。这将解决心跳包和WebSocket连接的问题。

回到顶部