Nginx TCP AND UDP LOAD BALANCER


前言

Nginx从Nginx Plus(商业授权版) 1.7.7 开始支持 TCP和UDP的负载均衡;Nginx开源版本从1.9.0起开始支持TCP的负载均衡,从1.9.13版本开始支持UDP和UNIX-domain sockets。

Nginx开源版本默认没有开启TCP负载均衡,开启需要在编译构建的时候新增–with-stream 参数,而Nginx Plus则默认就已经开启不需要额外参数。

下面是几个简单的Nginx配置(Example Configuration)

  • TCP

      server {
          listen 127.0.0.1:12345;
          proxy_pass 127.0.0.1:8080;
      }
    
      server {
          listen 12345;
          proxy_connect_timeout 1s;
          proxy_timeout 1m;
          proxy_pass example.com:12345;
      }
    
  • UDP

      server {
          listen 53 udp;
          proxy_responses 1;
          proxy_timeout 20s;
          proxy_pass dns.example.com:53;
      }
    
  • UNIX-domain sockets

      server {
          listen [::1]:12345;
          proxy_pass unix:/tmp/stream.socket;
      }
    

Nginx TCP负载均衡算法

与Nginx http负载均衡一样,Nginx TCP负载均衡也支持如下负载均衡算法:

  1. Round Robin: 对所有的backend轮询发送请求,算是最简单的方式了,也是默认的分配方式;例如:

     upstream stream_backend {
         server backend1.example.com:12345;
         server backend2.example.com:12345;
         server backend3.example.com:12346;
         ...
     }
    
  2. Least Connections(least_conn): 跟踪和backend当前的活跃连接数目,最少的连接数目说明这个backend负载最轻,将请求分配给他,这种方式会考虑到配置中给每个upstream分配的weight权重信息;例如:

     upstream dns_servers {
         least_conn;
         server 192.168.136.130:53;
         server 192.168.136.131:53;
         ...
     }
    
  3. Least Time(least_time): 请求会分配给响应最快和活跃连接数最少的backend;(该算法目前仅在Nginx Plus上支持);例如:

     upstream stream_backend {
         least_time first_byte;
    
         server backend1.example.com:12345;
         server backend2.example.com:12345;
         server backend3.example.com:12346;
     }
    
  4. Hash(hash key): client-server基于hash key计算hash值后,根据得到的hash值通过某种映射分配到backend。key值可以包括text, variables。例如:

     upstream stream_backend {
         hash $remote_addr;
    
         server backend1.example.com:12345;
         server backend2.example.com:12345;
         server backend3.example.com:12346;
     }
    

Nginx TCP健康检查

开源版本的Nginx软件可以对上游服务器(upstream servers)的响应执行基本检查,尽可能重试失败的请求(也称为Passive Health Checks)。 NGINX Plus则额外增加了对外部应用程序运行状况检查(也称为Active Health Checks)和检查缓慢启动功能(slow‑start),可以对负载平衡组中新增和恢复的服务器正常添加。

Passive Health Checks:

Passive Health Checks (被动健康检查)意味着NGINX或NGINX Plus会监控服务通信是否可用,如果不可用,NGINX将尝试恢复。如果仍然无法恢复,NGINX会考虑该服务不可用,并暂时停止向该服务器发送请求,直到被再次被视为活动。

Nginx和Nginx Plus都支持下面指令,来判断服务是否不可用:

  • fail_timeout - 设置考虑服务器不可用的多次失败尝试的时间,以及服务器不可用的时间(默认为10秒)。
  • max_fails - 在fail_timeout时间内设置失败尝试次数,以考虑服务器不可用(默认为1连接)尝试。

例1

该示例显示,如果NGINX无法向某个服务器发送请求或至少三次未收到此服务器的响应,则立即认为该服务器不可用30秒:

upstream backend {
    server backend1.example.com;
    server backend2.example.com max_fails=3 fail_timeout=30s;
}

例2

在该例显示,假设有7个连接,那么有5个连接将转到backend1.example.com:12345(因为权重为5,weight=5),剩下的连接到第二和第三个服务器。如果在与服务器通信期间发生错误,则连接将被传递到下一个服务器,依此类推,直到所有正在运行的服务器都将被尝试。 如果与所有服务器的通信失败,则连接将关闭。

upstream backend {
    server backend1.example.com:12345 weight=5;
    server 127.0.0.1:12345            max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend2;
    server backend3.example.com:12345 resolve;

    server backup1.example.com:12345  backup;
}

Active Health Checks

NGINX Plus可以通过使用health_check指令包含在位置块中来配置最简单的运行状况检查。,并检查响应。

例1

以下示例 - 向每个服务发送带自定义的TCP请求。 返回良好的200的服务器被认为是健康的; 否则它们被标记为失败。

stream {
    ...
    upstream   stream_backend {
        zone   upstream_backend 64k;
        server backend1.example.com:12345;
    }

    match http {
        send      "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n";
        expect ~* "200 OK";
    }

    server {
    listen       12345;
    health_check match=http;
    proxy_pass   stream_backend;
    }
}

更多health-check参考资料

http-health-check

tcp-health-check


简单测试

都在一个机器上, Nginx监听30003端口,然后开两个窗口,用nc监听 7773,7774端口。思路如下:

                          / nc -l 7773
telnet--> Nginx(30003) -->
                          \ nc -l 7774

使用nc监听端口

$  nc -l 7773
$  nc -l 7774

Nginx配置

stream {
    upstream backend {
        server 127.0.0.1:7773;
        server 127.0.0.1:7774;
    }
    server {
        listen 127.0.0.1:30003;
        proxy_timeout 20s;
        proxy_pass backend;
    }
}

测试

$ telnet 127.0.0.1 30003

第一次访问会代理到 7773端口,第二次访问会到7774端口。


线上配置文件

stream {
    upstream stream_backend {
        least_conn;
        server 127.0.0.1:8801 max_fails=2 fail_timeout=30s;
        server 127.0.0.1:8802 max_fails=2 fail_timeout=30s;
        server 127.0.0.1:8803 max_fails=2 fail_timeout=30s;
    }
    server {
        listen 8800;
        proxy_timeout 10m;
        proxy_connect_timeout 60;
        proxy_pass stream_backend;
    }
}

PS: 如果upstream组中只有一个服务器,max_fails,fail_timeout和slow_start参数都将被忽略,并且这样的服务器将永远不会被视为不可用。

参考文档

官方文档 1: ngx_stream_proxy_module

官方文档 2: tcp-load-balancing

Nginx的TCP负载均衡介绍

nginx-database-load-balancer-mysql-or-mariadb-galera-cluster