双网卡双网关服务器策略路由配置与持久化完全指南
彻底解决非对称路由问题,实现网络高可用与流量分离
在企业级服务器网络架构中,双网卡双网关 配置是实现网络高可用、业务流量隔离和负载分担的核心方案。然而,这种配置极易引发非对称路由 问题,导致外部访问超时、丢包甚至完全不通。本文将从原理到实践,使用真实可直接参考的私网IP示例,全面讲解如何通过Linux策略路由彻底解决这一问题,并提供生产级的持久化配置方案和故障排查手册。
文章目录
- 双网卡双网关服务器策略路由配置与持久化完全指南
-
- 彻底解决非对称路由问题,实现网络高可用与流量分离
- 一、非对称路由问题深度解析
-
- [1.1 典型问题现象](#1.1 典型问题现象)
- [1.2 根本原因与原理](#1.2 根本原因与原理)
- [二、解决方案:Linux策略路由(Policy Routing)](#二、解决方案:Linux策略路由(Policy Routing))
-
- [2.1 策略路由核心原理](#2.1 策略路由核心原理)
- [2.2 整体设计方案](#2.2 整体设计方案)
- [2.3 设计原则](#2.3 设计原则)
- 三、生产级详细配置步骤
-
- [3.1 环境准备与规划](#3.1 环境准备与规划)
- [3.2 创建自定义路由表](#3.2 创建自定义路由表)
- [3.3 配置策略路由规则](#3.3 配置策略路由规则)
- [3.4 配置自定义路由表内容](#3.4 配置自定义路由表内容)
- [3.5 配置主路由表](#3.5 配置主路由表)
- 四、持久化配置实现
-
- [4.1 两种持久化方案对比](#4.1 两种持久化方案对比)
- [4.2 方案一:通过rc.local实现持久化](#4.2 方案一:通过rc.local实现持久化)
- [4.3 方案二:通过NetworkManager dispatcher脚本实现(生产级推荐)](#4.3 方案二:通过NetworkManager dispatcher脚本实现(生产级推荐))
- [4.4 配置反向路径过滤(通用)](#4.4 配置反向路径过滤(通用))
- 五、全面验证与测试
-
- [5.1 一键验证脚本](#5.1 一键验证脚本)
- [5.2 关键验证点](#5.2 关键验证点)
- [5.3 重启验证](#5.3 重启验证)
- 六、配置优化与最佳实践
-
- [6.1 路由表设计优化](#6.1 路由表设计优化)
- [6.2 脚本优化建议](#6.2 脚本优化建议)
- [6.3 安全加固](#6.3 安全加固)
- 七、常见故障排查指南
-
- [7.1 通用故障排查流程](#7.1 通用故障排查流程)
- [7.2 持久化方案专属问题](#7.2 持久化方案专属问题)
-
- rc.local方案常见问题
- [NetworkManager dispatcher方案常见问题](#NetworkManager dispatcher方案常见问题)
- [7.3 常见问题与解决方案](#7.3 常见问题与解决方案)
- [7.4 常用排查命令](#7.4 常用排查命令)
- 八、总结与扩展
-
- [8.1 本文方案优势](#8.1 本文方案优势)
- [8.2 扩展应用场景](#8.2 扩展应用场景)
- [8.3 注意事项](#8.3 注意事项)
一、非对称路由问题深度解析
1.1 典型问题现象
- 服务器双网卡分别接入不同网段,配置两个默认网关
- 从外网或其他网段访问服务器时,出现间歇性连接超时
- 同一网段内访问正常,跨网段访问异常
- 使用
ping测试时,部分数据包丢失,telnet端口测试成功率低 - 从服务器主动向外连接正常,但外部主动连接服务器失败
1.2 根本原因与原理
非对称路由 是指数据包的请求路径 与响应路径不一致。这是Linux内核默认路由机制的必然结果:
客户端 → 网关1(192.168.1.1) → 服务器ens18网卡(192.168.1.100) → 服务器处理请求
↓
客户端 ← 网关2(10.0.0.1) ← 服务器ens19网卡(10.0.0.100) ← 服务器生成响应
当服务器收到来自ens18网卡的请求时,内核会根据主路由表 的默认网关优先级选择响应出口。如果ens19的默认网关优先级更高,响应包就会从ens19网卡发出。
此时,中间的防火墙或网关设备会检测到:一个来自网关1的请求,却收到了来自网关2的响应,出于安全考虑会直接丢弃该数据包,导致连接失败。
二、解决方案:Linux策略路由(Policy Routing)
2.1 策略路由核心原理
传统路由仅根据目标IP地址 选择下一跳,而策略路由允许根据源IP地址、目标IP地址、入站接口、服务端口等多种条件,选择不同的路由表进行转发。
对于双网卡双网关场景,核心解决思路是:
谁接收的请求,就从谁那里返回响应
2.2 整体设计方案
我们将采用"一网卡一路由表"的设计模式:
- 为每个网卡创建独立的自定义路由表
- 配置策略规则:根据源IP地址选择对应的路由表
- 每个自定义路由表只包含该网卡的网段路由和默认网关
- 保留主路由表用于服务器主动发起的连接
2.3 设计原则
- 路径对称:确保同一连接的进出流量通过同一网卡
- 职责分离:每个路由表只管理一个网卡的流量
- 优先级明确:目标地址规则优先级高于源地址规则
- 持久可靠:配置在系统重启和网络服务重启后自动恢复
- 向后兼容:不影响服务器原有网络功能
三、生产级详细配置步骤
3.1 环境准备与规划
本文以CentOS/RHEL 7/8/9系统为例,使用以下真实私网IP配置作为示例:
| 网卡名称 | IP地址/掩码 | 网关地址 | 所属网段 | 用途 |
|---|---|---|---|---|
| ens18 | 192.168.1.100/24 | 192.168.1.1 | 192.168.1.0/24 | 业务主网(对外提供服务) |
| ens19 | 10.0.0.100/24 | 10.0.0.1 | 10.0.0.0/24 | 管理网/专用网 |
| - | - | - | 172.16.0.0/16 | 需要通过ens19访问的内部专用网段 |
注意:请将以下配置中的IP地址替换为您的实际环境地址。
3.2 创建自定义路由表
Linux内核支持最多255个自定义路由表,我们需要在/etc/iproute2/rt_tables文件中定义:
bash
# 备份原始配置文件(生产环境必做)
cp /etc/iproute2/rt_tables /etc/iproute2/rt_tables.bak
# 添加自定义路由表(ID建议从100开始,避免与系统保留表冲突)
cat >> /etc/iproute2/rt_tables << 'EOF'
# 自定义策略路由表
100 ens18_table # 对应ens18网卡(192.168.1.100)的路由表
101 ens19_table # 对应ens19网卡(10.0.0.100)的路由表
EOF
3.3 配置策略路由规则
策略规则决定了什么样的数据包使用哪个路由表,规则按优先级从小到大依次匹配:
bash
# 清除可能存在的旧规则(避免重复配置导致冲突)
ip rule del from 192.168.1.100 lookup ens18_table 2>/dev/null || true
ip rule del from 10.0.0.100 lookup ens19_table 2>/dev/null || true
ip rule del to 172.16.0.0/16 lookup ens19_table 2>/dev/null || true
ip rule del pref 10000 2>/dev/null || true
# 添加核心策略规则
# 规则1:源IP是192.168.1.100的数据包,使用ens18_table路由表
ip rule add from 192.168.1.100 lookup ens18_table
# 规则2:源IP是10.0.0.100的数据包,使用ens19_table路由表
ip rule add from 10.0.0.100 lookup ens19_table
# 规则3:目标是172.16.0.0/16专用网段的数据包,强制使用ens19_table
# 优先级10000,高于默认规则(32766)
ip rule add to 172.16.0.0/16 lookup ens19_table pref 10000
3.4 配置自定义路由表内容
为每个自定义路由表配置独立的路由信息,实现流量完全分离:
bash
# ==================== 配置ens18_table路由表 ====================
# 默认网关:所有未知目标通过192.168.1.1转发
ip route replace default via 192.168.1.1 dev ens18 table ens18_table
# 本地网段路由:直接通过ens18网卡访问192.168.1.0/24
ip route replace 192.168.1.0/24 dev ens18 scope link table ens18_table
# ==================== 配置ens19_table路由表 ====================
# 默认网关:所有未知目标通过10.0.0.1转发
ip route replace default via 10.0.0.1 dev ens19 table ens19_table
# 本地网段路由:直接通过ens19网卡访问10.0.0.0/24
ip route replace 10.0.0.0/24 dev ens19 scope link table ens19_table
# 专用网段路由:通过10.0.0.1访问172.16.0.0/16
ip route replace 172.16.0.0/16 via 10.0.0.1 dev ens19 table ens19_table
3.5 配置主路由表
主路由表用于服务器主动发起的连接,通过metric值控制默认网关优先级:
bash
# 清除原有默认网关(避免冲突)
ip route del default 2>/dev/null || true
# 添加两个默认网关,metric值越小优先级越高
# 这里设置业务主网(ens18)优先级更高
ip route add default via 192.168.1.1 dev ens18 metric 100
ip route add default via 10.0.0.1 dev ens19 metric 101
# 添加专用网段路由(主路由表也需要,用于服务器主动访问)
ip route replace 172.16.0.0/16 via 10.0.0.1 dev ens19
四、持久化配置实现
4.1 两种持久化方案对比
本文提供两种主流的持久化方案,您可以根据自己的系统环境和需求选择:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| rc.local | 简单易上手,兼容所有Linux系统 | 执行时机不确定,网络服务重启后配置丢失,错误处理能力弱 | 测试环境、不使用NetworkManager的老旧系统 |
| NetworkManager dispatcher | 执行时机准确,网络状态变化自动触发,支持完善的日志和错误处理 | 仅适用于使用NetworkManager的系统(CentOS7+/Ubuntu18.04+) | 生产环境、需要高可靠性的场景 |
4.2 方案一:通过rc.local实现持久化
这是最传统、最简单的持久化方式,适合快速部署和测试环境:
bash
# 编辑rc.local文件
cat >> /etc/rc.d/rc.local << 'EOF'
#!/bin/bash
# 双网卡策略路由持久化配置
# 等待网络接口就绪(根据实际情况调整等待时间)
sleep 3
# 1. 确保自定义路由表定义存在
grep -q "^100[[:space:]]" /etc/iproute2/rt_tables || echo "100 ens18_table" >> /etc/iproute2/rt_tables
grep -q "^101[[:space:]]" /etc/iproute2/rt_tables || echo "101 ens19_table" >> /etc/iproute2/rt_tables
# 2. 清除可能存在的旧规则
ip rule del from 192.168.1.100 lookup ens18_table 2>/dev/null || true
ip rule del from 10.0.0.100 lookup ens19_table 2>/dev/null || true
ip rule del to 172.16.0.0/16 lookup ens19_table 2>/dev/null || true
ip rule del pref 10000 2>/dev/null || true
# 3. 添加策略路由规则
ip rule add from 192.168.1.100 lookup ens18_table
ip rule add from 10.0.0.100 lookup ens19_table
ip rule add to 172.16.0.0/16 lookup ens19_table pref 10000
# 4. 配置自定义路由表路由
ip route replace default via 192.168.1.1 dev ens18 table ens18_table
ip route replace 192.168.1.0/24 dev ens18 scope link table ens18_table
ip route replace default via 10.0.0.1 dev ens19 table ens19_table
ip route replace 10.0.0.0/24 dev ens19 scope link table ens19_table
ip route replace 172.16.0.0/16 via 10.0.0.1 dev ens19 table ens19_table
# 5. 保持主路由表的关键路由
ip route replace default via 192.168.1.1 dev ens18 metric 100
ip route replace default via 10.0.0.1 dev ens19 metric 101
ip route replace 172.16.0.0/16 via 10.0.0.1 dev ens19
# 6. 记录执行日志
echo "[$(date)] 策略路由配置已通过rc.local加载" >> /var/log/rc-local-route.log
EOF
# 设置执行权限
chmod +x /etc/rc.d/rc.local
# 启用并启动rc-local服务
systemctl enable rc-local --now
4.3 方案二:通过NetworkManager dispatcher脚本实现(生产级推荐)
这是目前最可靠的持久化方式,脚本会在网络接口状态变化(up/down)、NetworkManager服务重启时自动执行,彻底解决rc.local的缺陷:
bash
# 创建NetworkManager dispatcher脚本
cat > /etc/NetworkManager/dispatcher.d/99-policy-routing << 'EOF'
#!/bin/bash
# 双网卡策略路由自动配置脚本
# 触发时机:网络接口up/down、NetworkManager服务重启
INTERFACE="$1"
ACTION="$2"
LOG_FILE="/var/log/policy-routing.log"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}
# 只在接口up时执行配置
if [ "$ACTION" != "up" ]; then
exit 0
fi
log "网络接口 $INTERFACE 已启动,开始配置策略路由"
# 1. 确保自定义路由表存在
if ! grep -q "^100[[:space:]]*ens18_table" /etc/iproute2/rt_tables; then
echo "100 ens18_table" >> /etc/iproute2/rt_tables
log "添加自定义路由表:ens18_table"
fi
if ! grep -q "^101[[:space:]]*ens19_table" /etc/iproute2/rt_tables; then
echo "101 ens19_table" >> /etc/iproute2/rt_tables
log "添加自定义路由表:ens19_table"
fi
# 2. 清除旧的策略规则
ip rule del from 192.168.1.100 lookup ens18_table 2>/dev/null
ip rule del from 10.0.0.100 lookup ens19_table 2>/dev/null
ip rule del to 172.16.0.0/16 lookup ens19_table 2>/dev/null
log "清除旧策略规则完成"
# 3. 添加新的策略规则
ip rule add from 192.168.1.100 lookup ens18_table
ip rule add from 10.0.0.100 lookup ens19_table
ip rule add to 172.16.0.0/16 lookup ens19_table pref 10000
log "添加新策略规则完成"
# 4. 配置自定义路由表
# ens18_table
ip route replace default via 192.168.1.1 dev ens18 table ens18_table
ip route replace 192.168.1.0/24 dev ens18 scope link table ens18_table
# ens19_table
ip route replace default via 10.0.0.1 dev ens19 table ens19_table
ip route replace 10.0.0.0/24 dev ens19 scope link table ens19_table
ip route replace 172.16.0.0/16 via 10.0.0.1 dev ens19 table ens19_table
log "配置自定义路由表完成"
# 5. 配置主路由表
ip route replace default via 192.168.1.1 dev ens18 metric 100
ip route replace default via 10.0.0.1 dev ens19 metric 101
ip route replace 172.16.0.0/16 via 10.0.0.1 dev ens19
log "配置主路由表完成"
log "策略路由配置全部执行成功"
EOF
# 设置脚本执行权限(必须为755,否则NetworkManager不会执行)
chmod 755 /etc/NetworkManager/dispatcher.d/99-policy-routing
# 创建日志文件并设置权限
touch /var/log/policy-routing.log
chmod 644 /var/log/policy-routing.log
# 重启NetworkManager服务,立即触发脚本执行
systemctl restart NetworkManager
# 查看日志确认配置成功
tail -f /var/log/policy-routing.log
4.4 配置反向路径过滤(通用)
反向路径过滤(rp_filter)是Linux内核的安全机制,在策略路由环境下必须设置为宽松模式,否则会丢弃非对称路由的数据包:
bash
# 创建sysctl配置文件
cat > /etc/sysctl.d/99-policy-routing.conf << 'EOF'
# 策略路由反向路径过滤配置
# 0:关闭反向路径过滤
# 1:严格模式(默认,会导致非对称路由数据包被丢弃)
# 2:宽松模式(推荐,只检查源地址是否可达)
net.ipv4.conf.all.rp_filter=2
net.ipv4.conf.default.rp_filter=2
net.ipv4.conf.ens18.rp_filter=2
net.ipv4.conf.ens19.rp_filter=2
# 禁用ICMP重定向,防止路由表被意外修改
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.ens18.accept_redirects=0
net.ipv4.conf.ens19.accept_redirects=0
EOF
# 应用配置
sysctl -p /etc/sysctl.d/99-policy-routing.conf
五、全面验证与测试
5.1 一键验证脚本
创建一个验证脚本,快速检查所有配置是否正确:
bash
cat > /usr/local/bin/verify-policy-routing << 'EOF'
#!/bin/bash
echo "====================================="
echo " 双网卡策略路由配置验证"
echo "====================================="
echo ""
echo "1. 自定义路由表定义:"
grep -E "(100|101)" /etc/iproute2/rt_tables
echo ""
echo "2. 策略路由规则:"
ip rule show | grep -E "(ens18|ens19)"
echo ""
echo "3. ens18_table路由表内容:"
ip route show table ens18_table
echo ""
echo "4. ens19_table路由表内容:"
ip route show table ens19_table
echo ""
echo "5. 主路由表内容:"
ip route show | grep -E "(default|172.16)"
echo ""
echo "6. 路由路径测试:"
echo "→ 测试从ens18(192.168.1.100)返回的路径:"
ip route get 8.8.8.8 from 192.168.1.100
echo ""
echo "→ 测试从ens19(10.0.0.100)返回的路径:"
ip route get 8.8.8.8 from 10.0.0.100
echo ""
echo "→ 测试访问专用网段(172.16.1.1)的路径:"
ip route get 172.16.1.1
echo ""
echo "7. 连通性测试:"
echo "→ 测试通过ens18访问外网:"
ping -c 2 -I 192.168.1.100 8.8.8.8
echo ""
echo "→ 测试通过ens19访问外网:"
ping -c 2 -I 10.0.0.100 8.8.8.8
echo ""
echo "→ 测试访问专用网段:"
ping -c 2 172.16.1.1
echo ""
echo "8. 持久化配置验证:"
if [ -f "/etc/NetworkManager/dispatcher.d/99-policy-routing" ]; then
echo "→ 已配置NetworkManager dispatcher持久化方案"
echo "→ 最近一次执行日志:"
tail -n 5 /var/log/policy-routing.log
elif grep -q "策略路由配置已通过rc.local加载" /var/log/rc-local-route.log; then
echo "→ 已配置rc.local持久化方案"
echo "→ 最近一次执行日志:"
tail -n 5 /var/log/rc-local-route.log
else
echo "→ 未检测到持久化配置"
fi
echo ""
echo "====================================="
echo "验证完成,请检查以上输出是否正确"
echo "====================================="
EOF
# 设置执行权限
chmod +x /usr/local/bin/verify-policy-routing
# 运行验证脚本
verify-policy-routing
5.2 关键验证点
- 策略规则:必须存在两条源IP规则和一条目标IP规则
- 路由表:每个自定义路由表必须包含默认网关和本地网段路由
- 路径测试 :
ip route get命令必须显示正确的出口网卡 - 连通性测试:指定源IP的ping测试必须全部成功
- 持久化验证:重启网络服务和系统后,配置依然存在
5.3 重启验证
bash
# 重启系统验证持久化
reboot
# 重启后再次运行验证脚本
verify-policy-routing
六、配置优化与最佳实践
6.1 路由表设计优化
- ID规划:自定义路由表ID建议从100开始,避免与系统保留表(0-255中的低ID)冲突
- 命名规范:路由表名称与网卡名称保持一致,便于维护
- 规则优先级:目标地址规则优先级应高于源地址规则,源地址规则高于默认规则
6.2 脚本优化建议
- 变量化配置:将IP地址、网卡名称等配置提取为变量,便于修改
- 错误处理:添加命令执行结果检查,失败时记录错误日志
- 幂等性设计 :使用
ip route replace替代ip route add,避免重复添加错误 - 日志轮转:配置logrotate管理策略路由日志,防止日志文件过大
6.3 安全加固
- 禁用ICMP重定向,防止路由表被恶意修改
- 配置防火墙规则,限制不必要的网络访问
- 定期检查策略路由配置,防止被意外修改
七、常见故障排查指南
7.1 通用故障排查流程
- 检查网络接口状态 :
ip addr show - 检查策略路由规则 :
ip rule show - 检查自定义路由表 :
ip route show table <表名> - 检查主路由表 :
ip route show - 测试路由路径 :
ip route get <目标IP> from <源IP> - 抓包分析 :
tcpdump -i <网卡名> host <目标IP> - 检查反向路径过滤 :
sysctl -a | grep rp_filter
7.2 持久化方案专属问题
rc.local方案常见问题
- 配置不生效:检查rc.local文件是否有执行权限,systemd是否启用了rc-local服务
- 网络服务重启后丢失:这是rc.local的固有缺陷,建议改用NetworkManager dispatcher方案
- 执行时机过早 :适当增加
sleep时间,等待网络接口完全就绪
NetworkManager dispatcher方案常见问题
- 脚本不执行 :检查脚本权限是否为755,脚本是否在
/etc/NetworkManager/dispatcher.d/目录下 - 配置错误 :查看
/var/log/policy-routing.log日志文件,定位错误原因 - 部分接口不触发:确认脚本中没有限制特定接口,NetworkManager管理了所有网卡
7.3 常见问题与解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 外部访问192.168.1.100超时 | 反向路径过滤设置为严格模式 | 将rp_filter设置为2 |
| 策略规则不生效 | 规则优先级太低 | 调整pref值,确保优先级高于默认规则 |
| 服务器主动访问172.16.0.0/16失败 | 主路由表没有配置专用网段路由 | 在主路由表添加172.16.0.0/16路由 |
| 出现"RTNETLINK answers: File exists"错误 | 路由或规则已存在 | 使用replace替代add命令 |
| 部分客户端能访问,部分不能 | 防火墙配置问题 | 检查192.168.1.1和10.0.0.1两个网关的防火墙规则 |
7.4 常用排查命令
bash
# 查看所有策略规则
ip rule show
# 查看指定路由表
ip route show table ens18_table
ip route show table ens19_table
# 测试路由路径(最关键的命令)
ip route get 8.8.8.8 from 192.168.1.100
ip route get 8.8.8.8 from 10.0.0.100
# 实时抓包分析
tcpdump -i ens18 host 192.168.1.100 and icmp
tcpdump -i ens19 host 10.0.0.100 and icmp
# 查看内核网络日志
dmesg | grep -i net
# 查看持久化脚本日志
# rc.local方案
tail -f /var/log/rc-local-route.log
# NetworkManager dispatcher方案
tail -f /var/log/policy-routing.log
八、总结与扩展
8.1 本文方案优势
- 彻底解决非对称路由导致的网络连通性问题
- 生产级可靠:支持系统重启和网络服务重启
- 易于维护:配置清晰,命名规范,日志完善
- 灵活扩展:可轻松添加更多网卡和路由表
8.2 扩展应用场景
- 多出口负载均衡:结合iptables实现基于源IP的负载均衡
- VPN分流:将特定流量引导至VPN接口
- 端口级路由:使用iptables标记数据包,实现基于端口的策略路由
- IPv6支持 :本文方案同样适用于IPv6,只需将
ip命令替换为ip -6
8.3 注意事项
- 本文方案适用于CentOS/RHEL 7/8/9、Ubuntu 18.04+等使用NetworkManager的系统
- 对于使用传统network服务的系统,可将dispatcher脚本改为rc.local脚本
- 配置前请确保您有服务器的物理访问权限或远程控制台访问权限,避免网络中断导致无法连接
- 建议在测试环境验证通过后再应用到生产环境
通过本文介绍的策略路由配置方案,您可以构建一个稳定、可靠、高性能的双网卡双网关服务器网络环境,为您的业务系统提供坚实的网络基础。
如果本文对您有帮助,欢迎点赞、收藏和关注!如有任何问题,欢迎在评论区留言交流。