我在nginx后面的nodejs中使用粘滞会话。粘滞会话通过检查连接的remoteAddress来执行负载均衡。现在的问题是总是取nginx服务器的ip
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配置:
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;发布于 2016-01-15 11:14:22
正如mef指出的那样,粘滞会话目前不能在反向代理后面工作,因为反向代理的remoteAddress总是相同的。上述问题中的pull request,以及早期的pull request,可能确实解决了这个问题,尽管我自己还没有测试过。
然而,这些修复依赖于部分解析数据包,执行低级路由,同时偷看较高级别的报头...正如对pull请求的评论所表明的,它们不稳定,依赖于未记录的行为,存在兼容性问题,可能会降低性能,等等。
如果你不想依赖这样的实验实现,一种替代方案是将负载平衡完全留给nginx,nginx可以看到客户端的真实IP,因此保持会话粘性。你所需要的就是nginx内置的ip_hash负载均衡。
然后,您的nginx配置可能如下所示:
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;
}
}现在,为了让它正常工作,您的服务器代码还需要进行一些修改:
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是稳定的,维护良好,几乎在任何地方都可以使用。
发布于 2015-06-08 19:41:28
您正在使用的模块似乎还不支持反向代理源代码。
看看this Github issue,一些拉取请求似乎可以解决你的问题,所以你可以通过使用模块的分支(你可以使用point at it on github from your package.json file)来解决这个问题。
https://stackoverflow.com/questions/30706420
复制相似问题