Nginx代理转发
Nginx 现在的代理转发功能已经日趋完善, 可以用来进行大规范的数据负载转发, 比较知名的方案就是 Nginx-Tomcat/Nginx-Jar 的转发负载架构.
常见的 Java 高并发负载也是通过 Nginx 挂起代理转发到不同 Jar 服务进行处理.
Nginx 有两种转发方式:
- HTTP转发: 只针对 HTTP 数据转发, 可以通过设置代理头转发源客户端数据.
- Stream转发: 针对 TCP/UDP 的数据流转发, 目前转发的时候无法识别源IP.
如果仅仅作为流量不需要做任何日志和IP判断可以采用
Stream转发, 剩下只要不涉及这种情况完全不推荐( 应该采用专门的 HAProxy 转发数据 )
Stream转发
这里说明 Stream 转发两种方式: TCP/UDP:
# 注意 Stream 转发不会涉及 HTTP 模块, 所以不需要在 HTTP 之中编写
http{
.......
}
# 这里直接和 http 模块一样, 创建出新的模块
stream {
# 这里可以追加其他默认配置, 比如重设日志输出格式
log_format proxy '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
# 设置默认的日志访问
access_log /var/log/nginx/proxy.log proxy;
# 直接手动引入配置, 这里会默认加载目录下所有 xxxx.conf 后缀的配置文件
include /etc/nginx/stream.d/*.conf;
}
TCP转发
这里就是文件配置, 用于加载主文件获取加载目录下面的配置, 这里演示如何配置 TCP 和 UDP 的转发, 首先是 TCP 转发:
# 这里假设采用转发 SSH 的 TCP 协议来演示转发端口数据.
# sudo vim /etc/nginx/stream.d/ssh.conf
upstream ssh_proxy {
# 注意这里有几种并发请求分配算法设置, 不含NGINX商业版本算法.
# `backup` 这个是备份服务, 当所有的服务器宕机无法访问的时候就会转发到该服务.
# 默认轮流算法, 请求会轮流切换分配访问的服务器
server server1.example.com:22;
server server2.example.com:22;
server server4.example.com:22 backup;
# 权重分配算法, 按照权重来选择权重最高的服务器
server server1.example.com:22 weight=3;
server server2.example.com:22 weight=5;
# 客户端IP的哈希算法, 比较老版本暂时不推荐( 不支持 IPv6 和版本不支持 )
ip_hash;
server server1.example.com:22;
server server2.example.com:22;
# 自动分配最少请求服务器, 这种方式最简单方便
least_conn;
server server1.example.com:22;
server server2.example.com:22;
# 手动哈希分配算法, 对指定的某项客户端配置进行哈希分配服务器( 这里采用访问IP地址 )
# `consistent` 参数可有可无如果设置则默认采用一致性哈希, 能够更快命中某些缓存服务( Memcache/Redis )
hash $remote_addr consistent;
server server1.example.com:22;
server server2.example.com:22;
# 一致性哈希分配, 这里是简化版手动哈希分配( 根据 HTTP-GET 地址哈希比较选择 )
consistent_hash $request_uri;
server server1.example.com:22;
server server2.example.com:22;
# 负载检测分配, 这个方法采用后台服务器转发响应时间作为依赖, 并非可信的完全负载判断.
server server1.example.com:22;
server server2.example.com:22;
fair;
# 这里支持的服务器方式可以支持以下方式
# 支持最大错误次数( max_fails=3 ), 每次最大错误的超时时间( fail_timeout=30s )
# 错误判断用于给服务器识别异常从而转发下一级的服务器( 超时/无法访问等情况 )
server server1.example.com:22 max_fails=3 fail_timeout=30s; # 域名服务器
server 127.0.0.1:22 max_fails=3 fail_timeout=30s; # IP服务器
server unix:/tmp/ssh.sock max_fails=3 fail_timeout=30s; # UnixDomain服务器
}
# TCP 挂起服务器连接池
server {
# 设定监听端口, 可以采用多配置项目, 这里说明几个关键配置
# `reuseport`, 开启了端口快速复用缓解 TIME_WAIT 回收端口请求资源过慢导致请求
# `udp`, 声明该代理的是 UDP 服务
# 以上都是比较简单的配置项, 日常基本上就这些参数配置需要注意
listen 10022 reuseport;
# 启用 TCP 的 NODELAY 特性
# 网络默认 TCP 启用 `Nagle` 算法, 该算法通过减少传输的数据包( 读写缓冲区集中发放 )
#
# `Nagle` 算法的好处: 减少传输的数据包数量, 将传输数据集中一起统一发送, 从而有效提高网络利用率.
# 但是坏处也是明显, 数据并不会实时传输具有数据传输延时的问题( 因为数据必须等到写缓冲区满足条件发送 )
#
# `TCP_NODELAY` 禁用 `Nagle` 算法的好处: 直接实时发送对应数据包, 能够有效降低数据传输的延时
# 坏处则是会频繁实时发送数据包, 网络会频繁处于活跃状态导致网络利用率低下.
#
# 当然如果想要实时传输且提高网络利用率, 则可以采用编写自定义UDP传输协议处理
tcp_nodelay on;
# 设定连接的超时时间( CONNECT 状态 )
proxy_connect_timeout 3s;
# 设定代理的请求超时时间( WAIT 状态 )
proxy_timeout 15s;
# 调用指定的后端服务池
proxy_pass ssh_proxy;
}
# 也可以直接设置转发配置
server {
listen 20022;
# 直接简单的转发配置
proxy_pass 127.0.0.1:22;
}
这里配置方式基本上是常见配置, 剩下可以参考官方文档来配置.
UDP转发
UDP 转发配置基本上也差不多, 所以直接采用简单的配置说明:
# 这里假设采用转发 DNS 的 UDP 协议来演示转发端口数据.
# sudo vim /etc/nginx/stream.d/dns.conf
upstream dns_proxy {
# 自动分配最少请求服务器, 这种方式最简单方便
least_conn;
server dns1.example.com:53;
server dns2.example.com:53;
}
# 转发 DNS 服务
server {
# 设置监听端口和端口重用/UDP转发声明
listen 53 reuseport udp;
# 直接简单的转发配置
proxy_pass dns_proxy;
}
UDP 基本上配置和 TCP 差不多.
HTTP转发
这种方式转发比较常规, 被广泛应用在 Web 应用高并发处理, 能够有效起到负载分流功能( 这种又称 反向代理 ):
# 注意, 这里只在 http 配置块配置
http{
......
# 这里一般都是加载 /etc/nginx/conf.d/xxx.conf 之中配置
# 创建代理服务池服务
upstream tomcat_service {
# 采用自动分流功能
least_conn;
# 假设内网多服务器分流, 设置最大错误和错误时间
server 192.168.1.100:8080 max_fails=2 fail_timeout=15s;
server 192.168.1.102:8080 max_fails=2 fail_timeout=15s;
server 192.168.1.104:8080 max_fails=2 fail_timeout=15s;
server 192.168.1.108:8080 max_fails=2 fail_timeout=15s;
# 追加双机宕机备份
server 192.168.1.110:8080 max_fails=2 fail_timeout=15s backup;
server 192.168.1.112:8080 max_fails=2 fail_timeout=15s backup;
}
# 挂起 http 服务器监听
server {
# 设置监听端口
listen 80;
# 设置服务器访问域名
server_name www.example.com;
......
# 这里需要设置 localhost 块
location / {
# 声明代理转发给服务器池
proxy_pass http://tomcat_service;
# 设置是否启用服务重定向, 默认 off 不启用代理转发
proxy_redirect off;
# 将客户端请求的域名转发给代理的服务器, 让接受代理的服务器可以识别出客户端访问的域名
# 如果采用多端口请求的服务, 需要追加端口信息 `$server_port`, 如下配置:
# proxy_set_header Host $host:$server_port;
proxy_set_header Host $host;
# 将域名追加请求协议头
# `$proxy_add_x_forwarded_for` 该变量会将代理机和客户端IP一起合并( 逗号区分 )发放.
# `$remote_addr` 则是直接把客户端IP写入而不会加上代理IP
# 两者按需选择
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-real-ip $remote_addr;
# 设置 CONNECT(连接) 状态超时时间( 默认单位: 秒,60s )
proxy_connect_timeout 60s;
# 设置 SEND(请求发送) 状态超时时间( 默认单位: 秒,60s )
proxy_send_timeout 60s;
# 设置 READ(请求发送) 状态超时时间( 默认单位: 秒,60s )
proxy_read_timeout 60s;
}
}
}
WebSocket转发
WebSocket 转发则比较特别, 虽然是长连接请求但是内部配置是在 Http 配置块.
Nginx 代理转发要求 1.3+ 版本
配置示例如下:
# 注意, 这里只在 http 配置块配置
http{
......
# 这里一般都是加载 /etc/nginx/conf.d/xxx.conf 之中配置
# 创建代理服务池服务
upstream websocket_service {
# 采用自动分流功能
least_conn;
# 假设内网多服务器分流, 设置最大错误和错误时间
server 192.168.1.100:10800 max_fails=2 fail_timeout=15s;
server 192.168.1.102:10800 max_fails=2 fail_timeout=15s;
}
# 挂起 http 服务器监听
server {
# 设置监听端口
listen 1080;
# 设置服务器访问域名
server_name ws.example.com;
......
# 这里需要设置 localhost 块
location / {
# 声明代理转发给服务器池
proxy_pass http://websocket_service;
# 将客户端请求的域名转发给代理的服务器, 让接受代理的服务器可以识别出客户端访问的域名
proxy_set_header Host $host:$server_port;
# 将域名追加请求协议头
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-real-ip $remote_addr;
# 以上都是常规的配置, 之后就是专属的 WebSocket 配置
# 以下三行可以直接简单将 http 请求升级成 ws 请求.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}