《从应用到内核:三种流量转发方案深度对比》
一、前序介绍
1、为什么需要流量转发?
● 业务场景引入:微服务、数据库代理、边缘网关、高可用架构
● 核心问题:如何将客户端请求高效、可靠地转发到后端?
● 本文目标:通过 原理 + 实操,带你掌握三种主流方案的选型与落地
2、OSI的 3/4/7 层区别在哪里?
● L7(应用层):看得懂HTTP头、URL、Cookie,可做路由、鉴权、WAF、压缩、缓存、重写、A/B复制等。
● L4(传输层):只关心TCP/UDP连接与端口,做不到基于URI/Cookie的策略,但可做SNI预读与直通。
● L3(网络层):基于IP的转发/NAT,不涉及内核态/用户态数据拷贝,性能最好,功能最“朴素”。
3、场景应用场景
● Web网关:Nginx7层 (TLS终止/路由/限流) --> 后端服务。
● 数据库/缓存:Nginx stream做4层负载(或直连) --> 后端实例: 需要源端IP 就上PROXY协议。
● 内网入口:iptables 做DNAT把少量端口打到特定机器,追齐极致性能,零改造。
二、环境准备
1、资源列表
● (请求发起机器)EC2:172.31.50.171
● (作为流量转发机器) EC2:172.31.50.172
● (接收流量转发)Aliyun-ALB: 对外监听80端口,http://alb-v6pg0tz2zs69n0k0m2.cn-hangzhou.alb.aliyuncsslb.com
● (接收流量转发)Aliyun-NLB: 对外监听80端口,挂载两个VIP,172.31.50.174、172.18.139.235
● (后端服务)ECS:172.31.50.173
2、Nginx安装
登录172.31.50.172机器,参考Nginx官方安装方案—链接
启动Nginx服务
注意:在CentOS中如果默认源安装的nginx版本低,不包含stream模块,会导致方案二中的配置文件无法识别。
3、后端服务部署
登录172.31.50.173机器,使用Python3启动以下脚本
from http.server import BaseHTTPRequestHandler, HTTPServerclass MyHandler(BaseHTTPRequestHandler):def do_GET(self):self.send_response(200)self.send_header('Content-type', 'text/plain')self.end_headers()self.wfile.write(b"Hello from Python!")if __name__ == "__main__":server = HTTPServer(('0.0.0.0', 8089), MyHandler)print("Server started on port 8089")server.serve_forever()
python3 server.py
三、方案实施
1、方案一:Nginx 7层协议转发
修改Nginx.conf的文件内容如下,然后重启Nginx
#user nobody;
worker_processes 1;#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;#log_format main '$remote_addr - $remote_user [$time_local] "$request" '# '$status $body_bytes_sent "$http_referer" '# '"$http_user_agent" "$http_x_forwarded_for"';#access_log logs/access.log main;sendfile on;#tcp_nopush on;#keepalive_timeout 0;keepalive_timeout 65;#gzip on;server {listen 8080;server_name localhost;#charset koi8-r;#access_log logs/host.access.log main;location / {#root html;#index index.html index.htm;#proxy_pass http://localhost:8080;#proxy_pass http://game-server:8080;proxy_pass http://alb-v6pg0tz2zs69n0k0m2.cn-hangzhou.alb.aliyuncsslb.com;}#error_page 404 /404.html;# redirect server error pages to the static page /50x.html#error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}include servers/*;
}
#在部署Nginx的机器上,操作重启
nginx -s reload
#在请求发起服务器上,触发请求
curl 172.31.50.172:8080
2、方案二:Nginx 4层流量转发
修改Nginx.conf的文件内容如下,然后重启Nginx
# -------------------------------
# 全局配置
# -------------------------------
# 指定 Nginx 运行的用户和用户组(可选,生产环境建议指定)
# user nginx;# 启动进程数,建议设置为 CPU 核心数
worker_processes auto;# 错误日志位置,级别可选:debug, info, notice, warn, error, crit
error_log /usr/local/nginx/logs/error.log warn;# 指定 PID 文件位置
pid /usr/local/nginx/logs/nginx.pid;# -------------------------------
# Events 配置
# -------------------------------
events {# 使用 epoll 模型,高效处理大量并发连接(Linux 推荐)use epoll;# 每个 worker 进程允许的最大连接数worker_connections 1024;# 启用多路复用 accept,提高性能multi_accept on;
}# ================================
# Stream 模块配置(四层代理)
# ================================
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 /usr/local/nginx/logs/tcp-access.log proxy;# 关闭日志文件缓存,便于 logrotateopen_log_file_cache off;# -------------------------------# Upstream:定义 NLB 后端# -------------------------------upstream nlb_backend {# NLB 双VIP地址server 172.31.50.174:80 max_fails=3 fail_timeout=15s;server 172.18.139.235:80 max_fails=3 fail_timeout=15s;}# -------------------------------# Server:监听 MySQL 客户端请求# -------------------------------server {# 监听 8080 端口listen 8080;# 转发到 nlb 后端proxy_pass nlb_backend;# 超时设置proxy_timeout 30s;# 响应数proxy_responses 1;# 访问日志access_log /var/log/nginx/tcp-nlb.log proxy;# 错误日志error_log /var/log/nginx/tcp-nlb-error.log error;}
}
#在部署Nginx的机器上,操作重启
nginx -s reload
#在请求发起服务器上,触发请求
curl 172.31.50.172:8080
3、方案三:iptables 网络转发
1)首先在EC2上配置流量转发的ip_tables规则
在172.31.50.172上添加转发规则
#开启Linux服务器的IP转发能力
echo “net.ipv4.ip_forward=1” >> /etc/sysctl.conf
sysctl -p
#配置入口流量预处理转发规则
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.31.50.174:80
#配置回路流量处理规则
iptables -t nat -A POSTROUTING -p tcp -d 172.31.50.174 --dport 80 -j MASQUERADE
2)查看配置规则
sudo iptables -t nat -L -n -v
3)配置流量转发的日志–可选
#配置入口流量转发日志
iptables -t mangle -A PREROUTING -p tcp --dport 8080 -j LOG --log-prefix “nf_debug_in”
#配置回路流量转发日志
iptables -t mangle -A POSTROUTING -p tcp -d 172.31.50.174 --dport 80 -j LOG --log-prefix “nf_debug_out”
4)流量测试
PS:直接在EC2上发起curl 127.0.0.1无法转发,需要在另外一台机器发起
比如 EC2 172.31.50.173
5)查看日志
sudo tail -f /var/log/messages | grep "nf_debug
6)删除ip_tables规则
iptables -t nat -D PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.31.50.174:80
iptables -t nat -D POSTROUTING -p tcp -d 172.31.50.174 --dport 80 -j MASQUERADE
四、场景选项与对比
对比维度 | Nginx 七层代理 | Nginx 四层代理 | iptables |
---|---|---|---|
工作层级 | L7(应用层) | L4(传输层) | L3/L4(网络/传输层) |
数据处理方式 | 解析 HTTP 协议,可读取 URL、Header、Cookie 等 | 不解析应用层,只转发 TCP/UDP 流 | 不解析应用层,仅修改 IP/Port |
性能 | ⭐⭐⭐高,但有协议解析开销 | ⭐⭐⭐⭐ 较高,接近线速 | ⭐⭐⭐⭐⭐ 极高,纯内核态 |
CPU/内存开销 | 高(需解析、缓冲、TLS 解密) | 中(仅转发,支持长连接) | 极低(内核处理,无用户态拷贝) |
功能丰富性 | ✅✅✅ 极强 • 基于 URL 路由 • HTTPS 终止 • 缓存、压缩、限速 • WAF、灰度发布 | ✅✅ 强 • 负载均衡 • 健康检查 • proxy_protocol • 日志记录 | ✅ 有限 • 端口转发(DNAT) • 防火墙规则 • 简单负载(配合 ipvs) |
是否经过用户态 | ✅ 是(数据进入 Nginx 用户进程) | ✅ 是(数据进入 Nginx 用户进程) | ❌ 否(纯内核态,无数据拷贝) |
配置复杂度 | 中高(需理解 HTTP 语义) | 中(需理解 TCP 语义) | 高(命令行复杂,易出错) |
可维护性 | 高(配置文件清晰,支持 reload) | 高(模块化配置) | 低(规则易混乱,难调试) |
适用协议 | HTTP/HTTPS | TCP/UDP | TCP/UDP/ICMP 等所有 IP 协议 |
典型应用场景 | Web 服务、微服务网关、静态资源代理 | MySQL、Redis、Kafka、自定义 TCP 服务 | 防火墙、NAT、边缘路由、容器网络 |
扩展性 | 高(支持 Lua、动态模块) | 中(支持 stream 模块) | 低(依赖内核) |
安全性 | 高(可集成 WAF、JWT 认证) | 中(可做访问控制) | 高(底层防火墙) |
五、从浅入深的落地建议
- 先7层,再4层,最后3层
a. 需求从“功能为王”到“性能为王”的递进,Web/API先上7层,中台类中间件连通选4层,极简内核映射时再考虑iptables; - 统一真实客户端信息
a. 7层:X-Forwarded-For / X-Forwarded-Proto
b. 4层:若后端支持,启用PROXY protocol;否则只能看到代理源。 - 健康检查与容灾
a. 7/4层可内建检查; iptables需要依赖外部监控+自动切换脚本或路由协议(较为复杂)。 - 长连接与内核调优
a. keepalive、worker_rlimit_nofile、net.core.somaxconn、net.ipv4.ip_local_port_range、reuseport等 - Kubernetes场景
a. 北向七层入口:Ingress(Controller 用Nginx);
b. 东西向与中间件:Service(L4)或Nginx stream;
c. 节点级/容器网络:CNI/iptables 规则由kube-proxy/ebpf控制,尽量别手工硬改;
六、结束语
这里也总结个三板斧:能用7层就别无脑走4层,能用4层就别硬啃内核,真到极致性能再上L3/NAT。
理解分层的边界与取舍,你的流量控制转发就会既稳又快,可万般演变应对业务的千万变化!