首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >获取请求在网库nodejs中的客户端ip

获取请求在网库nodejs中的客户端ip
EN

Stack Overflow用户
提问于 2015-06-08 18:12:41
回答 2查看 1K关注 0票数 0

我在nginx后面的nodejs中使用粘滞会话。粘滞会话通过检查连接的remoteAddress来执行负载均衡。现在的问题是总是取nginx服务器的ip

代码语言:javascript
复制
 server = net.createServer({ pauseOnConnect: true },function(c) {

  // Get int31 hash of ip
  var worker,
      ipHash = hash((c.remoteAddress || '').split(/\./g), seed);

  // Pass connection to worker
  worker = workers[ipHash % workers.length];
  worker.send('sticky-session:connection', c);
});

我们可以使用网库获取客户端ip吗?

Nginx配置:

代码语言:javascript
复制
 server {
    listen       80 default_server;
    server_name  localhost;
    root         /usr/share/nginx/html;
    #auth_basic "Restricted";
#auth_basic_user_file /etc/nginx/.htpasswd;
    #charset koi8-r;

    #access_log  /var/log/nginx/host.access.log  main;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
   set_real_ip_from 0.0.0.0/0;
   real_ip_header X-Forwarded-For;
  real_ip_recursive on;
    proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://socket_nodes;
    proxy_read_timeout 3000;
EN

回答 2

Stack Overflow用户

发布于 2016-01-15 11:14:22

正如mef指出的那样,粘滞会话目前不能在反向代理后面工作,因为反向代理的remoteAddress总是相同的。上述问题中的pull request,以及早期的pull request,可能确实解决了这个问题,尽管我自己还没有测试过。

然而,这些修复依赖于部分解析数据包,执行低级路由,同时偷看较高级别的报头...正如对pull请求的评论所表明的,它们不稳定,依赖于未记录的行为,存在兼容性问题,可能会降低性能,等等。

如果你不想依赖这样的实验实现,一种替代方案是将负载平衡完全留给nginx,nginx可以看到客户端的真实IP,因此保持会话粘性。你所需要的就是nginx内置的ip_hash负载均衡。

然后,您的nginx配置可能如下所示:

代码语言:javascript
复制
upstream socket_nodes {
    ip_hash;
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
    server 127.0.0.1:8004;
    server 127.0.0.1:8005;
    server 127.0.0.1:8006;
    server 127.0.0.1:8007;
}

server {
    listen       80 default_server;
    server_name  localhost;
    root         /usr/share/nginx/html;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
        # Note: Trusting all addresses like this means anyone
        # can pretend to have any address they want.
        # Only do this if you're absolutely certain only trusted
        # sources can reach nginx with requests to begin with.
        set_real_ip_from 0.0.0.0/0;

        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://socket_nodes;
        proxy_read_timeout 3000;
    }
}

现在,为了让它正常工作,您的服务器代码还需要进行一些修改:

代码语言:javascript
复制
if (cluster.isMaster) {
    var STARTING_PORT = 8000;
    var NUMBER_OF_WORKERS = 8;

    for (var i = 0; i < NUMBER_OF_WORKERS; i++) {
        // Passing each worker its port number as an environment variable.
        cluster.fork({ port: STARTING_PORT + i });
    }

    cluster.on('exit', function(worker, code, signal) {
        // Create a new worker, log, or do whatever else you want. 
    });
}
else {
    server = http.createServer(app);

    // Socket.io initialization would go here.

    // process.env.port is the port passed to this worker by the master.
    server.listen(process.env.port, function(err) {
        if (err) { /* Error handling. */ }
        console.log("Server started on port", process.env.port);
    });
}

不同之处在于,不是使用集群让所有工作进程共享一个端口(由集群本身进行负载平衡),每个工作进程都有自己的端口,nginx可以在不同的端口之间分配负载,以获得不同的工作进程。

由于nginx根据从客户端获取的IP (或在您的示例中为X-Forwarded-For头部)选择要转到哪个端口,因此同一会话中的所有请求都将始终在同一进程中结束。

当然,这种方法的一个主要缺点是,工作人员的数量变得不那么动态。如果端口在nginx配置中是“硬编码的”,Node服务器必须确保始终侦听那些端口,不能少于也不能超过这些端口。在缺乏用于同步nginx配置和Node服务器的良好系统的情况下,这引入了出错的可能性,并使得动态扩展到例如环境中的核心数量变得更加困难。

然后,我想可以通过以下两种方式克服这个问题:以编程方式生成/更新nginx配置,使其始终反映所需的进程数量,或者可能通过为nginx配置非常多的端口,然后根据需要让每个Node工作进程侦听多个端口(因此,您仍然可以拥有与内核数量一样多的工作进程)。然而,到目前为止,我还没有亲自验证或尝试实现这些方法中的任何一个。

关于代理后面的nginx服务器的说明

在您提供的nginx配置中,您似乎使用了ngx_http_realip_module。虽然你在问题中没有明确提到这一点,但请注意,在nginx本身位于某种代理之后的情况下,这实际上可能是必要的,例如ELB。

然后需要real_ip_header指令来确保它是真实的客户端IP (例如,在X-Forwarded-For中),而不是其他代理的IP,它被散列以选择要转到哪个端口。

在这种情况下,nginx实际上服务的目的与粘性会话的pull请求试图实现的目的非常相似:使用headers来做出负载平衡决策,特别是确保相同的真实客户端IP总是指向相同的进程。

当然,关键的区别是,nginx作为一个专用的web服务器、负载均衡器和反向代理,正是为了执行这些类型的操作而设计的。解析和操作协议栈的不同层是它的主要工作。更重要的是,虽然还不清楚有多少人实际使用过这些pull请求,但nginx是稳定的,维护良好,几乎在任何地方都可以使用。

票数 3
EN

Stack Overflow用户

发布于 2015-06-08 19:41:28

您正在使用的模块似乎还不支持反向代理源代码。

看看this Github issue,一些拉取请求似乎可以解决你的问题,所以你可以通过使用模块的分支(你可以使用point at it on github from your package.json file)来解决这个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30706420

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档