簡體   English   中英

在網絡庫nodejs中獲取請求的客戶端ip

[英]get client ip of the request in net library nodejs

我在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;

正如mef所指出的那樣,sticky-session目前在反向代理后面工作,其中remoteAddress始終相同。 盡管我尚未進行自我測試,但上述問題中的請求請求以及早期的請求請求確實可以解決該問題。

但是,這些修補程序依賴於部分解析數據包,進行低級路由,同時窺探較高級別的標頭...正如對pull請求的注釋所表明的那樣,它們很不穩定,取決於未記錄的行為,存在兼容性問題,可能會降低性能,等等。

如果您不想依靠這樣的實驗性實現,則一種選擇是將負載平衡完全交給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根據從客戶端(或您的情況下的X-Forwarded-For標頭)獲取的IP選擇要訪問的端口,因此同一會話中的所有請求將始終以相同的進程結束。

當然,這種方法的一個主要缺點是工人的數量動態性大大降低。 如果在nginx配置中對端口進行了“硬編碼”,則節點服務器必須確保始終准確地監聽這些端口,不少於也不再多。 在沒有良好的系統來同步nginx配置和Node服務器的情況下,這會引入錯誤的可能性,並使得動態擴展到例如環境中的內核數更加困難。

再說一次,我想可以通過以編程方式生成/更新nginx配置來克服此問題,因此它總是反映所需的進程數,或者可能通過為nginx配置大量端口,然后讓Node worker分別偵聽根據需要提供多個端口(因此您仍然可以擁有與內核數量完全相同的工作人員)。 但是,到目前為止,我還沒有親自驗證或嘗試實現這兩種方法。


關於代理后面的Nginx服務器的說明

在您提供的nginx配置中,您似乎已經使用了ngx_http_realip_module。 盡管您未在問題中對此進行明確提及,但請注意,在nginx本身位於某種代理(例如ELB)后面的情況下,這實際上可能是必要的。

然后需要使用real_ip_header指令來確保它是真實的客戶端IP(例如X-Forwarded-For),而不是其他代理的IP,這些哈希經過散列以選擇要訪問的端口。

在這種情況下,nginx實際上起到了與請求粘滯會話的拉取請求嘗試實現的目的相當相似的目的:使用標頭做出負載平衡決策,並特別確保始終將相同的真實客戶端IP定向到同樣的過程。

當然,主要的區別在於,nginx作為專用的Web服務器,負載均衡器和反向代理,其設計恰好可以執行這些類型的操作。 解析和操作協議棧的不同層是它的基礎。 更重要的是,雖然尚不清楚有多少人實際使用過這些拉取請求,但nginx穩定,維護良好並且幾乎在任何地方都可以使用。

您正在使用的模塊似乎還不支持反向代理源。

看看這個Github問題 ,一些拉請求似乎可以解決您的問題,因此您可以使用模塊的派生解決方案(您可以從package.json文件在github上指向它 )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM