Linux网络高级玩法:多路由表与策略路由实现双路由冗余与分流
掌握这些技巧,让你的Linux服务器网络更加稳定高效
在网络应用中,保证连接的可靠性和高效性至关重要。传统单一路由的方式往往无法满足复杂场景的需求。本文将详细介绍如何使用Linux高级路由策略实现双路由冗余与分流。
1. 理解基础概念
1.1 传统路由的局限性
传统路由基于目的地址进行转发决策,仅依赖单一路由表,所有数据包都通过相同的路径传输。这种方式在复杂网络环境下存在单点故障风险,且无法根据业务需求灵活调度流量。
1.2 策略路由的优势
Linux策略路由(Policy-Based Routing,PBR)允许管理员基于特定条件(如源地址、协议类型、TOS字段等)决定数据包的路由路径,而不仅仅依赖目标地址。
主要优势包括:
- 灵活性:可根据多种条件进行复杂的路由决策
- 流量控制:实现更精细的流量管理和优化
- 故障转移:主路径出现问题时自动切换到备用路径
- 负载均衡:在多个链路上合理分配流量
2. 核心机制解析
2.1 多路由表机制
Linux系统默认包含多个路由表,而非常见的单一路由表:
# 查看系统默认的路由规则
$ ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
命令解释:
ip rule list:显示当前系统中所有的路由策略规则lookup local:优先级0,处理本地地址和广播lookup main:优先级32766,系统主路由表lookup default:优先级32767,备用路由表
这三个路由表有明确分工:
- local表:包含本地地址和广播地址的路由
- main表:系统主路由表,存储常规路由信息
- default表:通常为空,作为备用
2.2 策略路由规则
策略路由通过ip rule命令定义的规则,将特定流量导向特定的路由表。规则可以基于源地址、目的地址、服务类型(TOS)等多种条件进行匹配。
3. 实战配置示例
假设我们有以下网络环境:
- IP地址:192.168.1.57/24 和 192.168.2.57/24
- 网关:192.168.1.1 和 192.168.2.1
- 目标:实现双路由冗余与分流
3.1 创建自定义路由表
首先,我们需要在/etc/iproute2/rt_tables文件中定义两个自定义路由表:
# 编辑路由表配置文件
echo "100 primary" >> /etc/iproute2/rt_tables
echo "200 backup" >> /etc/iproute2/rt_tables
命令解释:
echo "100 primary":创建ID为100,名称为"primary"的路由表>> /etc/iproute2/rt_tables:追加到路由表配置文件中- 路由表ID范围:1-252可供用户使用
这样我们就创建了两个名为"primary"和"backup"的路由表,ID分别为100和200。
3.2 配置各路由表的路由规则
# 配置主路由表
ip route add default via 192.168.1.1 dev eth0 table primary
ip route add 192.168.1.0/24 dev eth0 scope link table primary
# 配置备用路由表
ip route add default via 192.168.2.1 dev eth1 table backup
ip route add 192.168.2.0/24 dev eth1 scope link table backup
# 刷新路由缓存
ip route flush cache
命令详细解释:
# 添加默认路由到主路由表
ip route add default via 192.168.1.1 dev eth0 table primary
# ip route add : 添加路由规则
# default : 默认路由(0.0.0.0/0)
# via 192.168.1.1 : 通过网关192.168.1.1
# dev eth0 : 使用网络接口eth0
# table primary : 将路由添加到primary路由表
# 添加本地网络路由
ip route add 192.168.1.0/24 dev eth0 scope link table primary
# 192.168.1.0/24 : 目标网络段
# scope link : 链路范围,表示直接连接的本地网络
# dev eth0 : 通过eth0接口
# 刷新路由缓存,使新规则立即生效
ip route flush cache
3.3 定义策略路由规则
# 基于源地址的路由规则
ip rule add from 192.168.1.57 table primary pref 1000
ip rule add from 192.168.2.57 table backup pref 1001
# 确保本地流量使用正确路由
ip rule add to 192.168.1.0/24 table primary pref 1002
ip rule add to 192.168.2.0/24 table backup pref 1003
# 主备冗余规则 - 基于数据包标记的故障转移
ip rule add fwmark 1 table primary pref 1004
ip rule add fwmark 2 table backup pref 1005
命令详细解释:
# 添加基于源IP的路由规则
ip rule add from 192.168.1.57 table primary pref 1000
# ip rule add : 添加路由策略规则
# from 192.168.1.57 : 匹配源IP地址为192.168.1.57的数据包
# table primary : 使用primary路由表进行路由查询
# pref 1000 : 设置规则优先级为1000(数值越小优先级越高)
# 基于目标地址的路由规则
ip rule add to 192.168.1.0/24 table primary pref 1002
# to 192.168.1.0/24 : 匹配目标网络为192.168.1.0/24的数据包
# 基于防火墙标记的路由规则
ip rule add fwmark 1 table primary pref 1004
# fwmark 1 : 匹配被iptables标记为1的数据包
3.4 配置网络接口
使用NetworkManager配置接口,以下示例使用nmcli命令:
# 配置主接口
nmcli connection add type ethernet con-name primary-if ifname eth0 \
ipv4.method manual ipv4.addresses 192.168.1.57/24 \
ipv4.routes "0.0.0.0/1 192.168.1.1 table=100" connection.zone external
# 配置备用接口
nmcli connection add type ethernet con-name backup-if ifname eth1 \
ipv4.method manual ipv4.addresses 192.168.2.57/24 \
ipv4.routes "0.0.0.0/1 192.168.2.1 table=200" connection.zone external
命令解释:
nmcli connection add:创建新的网络连接配置type ethernet:指定为以太网连接con-name primary-if:连接名称为primary-ififname eth0:接口名称为eth0ipv4.method manual:手动配置IP地址ipv4.addresses 192.168.1.57/24:设置IP地址和子网掩码ipv4.routes "...":配置路由规则,table=100指定路由表
这种方法的优势在于配置持久化,重启后仍然有效。
4. 高级冗余与分流策略
4.1 基于源地址的分流
# 内网特定子网使用主路由
ip rule add from 192.168.10.0/24 table primary pref 1100
# 服务器子网使用备用路由
ip rule add from 192.168.20.0/24 table backup pref 1101
4.2 应用类型分流
# 使用iptables标记特定类型的流量
iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark 10
iptables -t mangle -A OUTPUT -p tcp --dport 443 -j MARK --set-mark 20
# 基于标记路由
ip rule add fwmark 10 table primary pref 1200
ip rule add fwmark 20 table backup pref 1201
iptables命令解释:
iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark 10
# -t mangle : 使用mangle表,用于数据包标记
# -A OUTPUT : 追加规则到OUTPUT链(出站流量)
# -p tcp : 匹配TCP协议
# --dport 80 : 目标端口80(HTTP)
# -j MARK : 使用MARK目标(数据包标记)
# --set-mark 10 : 设置标记值为10
4.3 自动故障转移
实现自动故障转移需要结合健康检查脚本:
#!/bin/bash
# 健康检查脚本示例
PRIMARY_GW="192.168.1.1"
BACKUP_GW="192.168.2.1"
while true; do
# 检查主网关连通性
ping -c 2 -W 1 $PRIMARY_GW > /dev/null 2>&1
if [ $? -ne 0 ]; then
# 主网关不可达,切换到备用
ip route replace default via $BACKUP_GW dev eth1 metric 100
echo "$(date): 切换到备用路由"
else
# 主网关正常,使用主路由
ip route replace default via $PRIMARY_GW dev eth0 metric 50
echo "$(date): 使用主路由"
fi
sleep 5
done
脚本命令解释:
ping -c 2 -W 1 $PRIMARY_GW > /dev/null 2>&1
# -c 2 : 发送2个ping包
# -W 1 : 等待1秒超时
# > /dev/null : 将标准输出重定向到空设备(不显示)
# 2>&1 : 将标准错误重定向到标准输出
ip route replace default via $BACKUP_GW dev eth1 metric 100
# replace : 替换现有路由(如果不存在则添加)
# metric 100 : 设置路由度量为100(数值越高优先级越低)
5. 测试与验证
5.1 查看路由规则
# 检查规则配置
ip rule show
# 查看特定路由表内容
ip route show table primary
ip route show table backup
# 检查所有路由表
ip route show table all
5.2 连通性测试
# 使用traceroute测试路径
traceroute -s 192.168.1.57 example.com
traceroute -s 192.168.2.57 example.com
# 使用源地址ping测试
ping -I 192.168.1.57 example.com
ping -I 192.168.2.57 example.com
traceroute命令解释:
traceroute -s 192.168.1.57 example.com
# -s 192.168.1.57 : 指定源IP地址为192.168.1.57
# example.com : 目标主机或域名
5.3 故障转移测试
# 模拟主链路故障
ip link set eth0 down
# 测试连通性是否保持
ping -I 192.168.2.57 example.com
# 恢复主链路
ip link set eth0 up
# 验证是否切回主路由
ping -I 192.168.1.57 example.com
6. 应用场景
6.1 多ISP出口场景
企业通过多个运营商(如电信、联通)连接互联网时,可以使用策略路由实现访问电信IP走电信出口、访问联通IP走联通出口,大幅提升跨网访问质量。
6.2 关键业务冗余
对网络可靠性要求高的业务(如视频会议、金融交易)可通过双路由实现自动故障转移,确保业务连续性。
6.3 流量分流与负载均衡
根据不同业务类型的需求,将流量分配到不同链路上:
- 实时流量(VoIP、视频会议)使用低延迟链路
- 大文件传输使用高带宽链路
- 关键业务使用高质量链路
7. 常见问题与解决方案
7.1 配置后无法与设备通信
这是最常见的问题,通常由以下原因导致:
-
路由规则优先级问题
# 检查规则优先级,数值越小优先级越高 ip rule show # 确保本地通信规则优先级更高 ip rule add from 192.168.1.57 lookup local pref 900 -
本地路由表缺失
# 确保本地路由存在于所有路由表中 ip route add 192.168.1.0/24 dev eth0 scope link table primary ip route add 192.168.2.0/24 dev eth1 scope link table backup -
反向路径过滤冲突
# 临时禁用RPF检查 echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter # 永久配置 echo "net.ipv4.conf.all.rp_filter=0" >> /etc/sysctl.conf echo "net.ipv4.conf.eth0.rp_filter=0" >> /etc/sysctl.conf echo "net.ipv4.conf.eth1.rp_filter=0" >> /etc/sysctl.conf sysctl -p
7.2 策略路由规则未生效
排查步骤:
-
检查规则顺序
ip rule show确保新规则的优先级足够高,不会被默认规则覆盖。
-
验证路由表内容
ip route show table primary ip route show table backup确认路由表中的所有条目准确无误。
-
检查网络接口状态
ip link show ip addr show确认接口处于UP状态且IP配置正确。
8. 实际应用探讨
针对您提到的实际情况——别人要求使用两个设备实现主备冗余,但您想通过同一设备的两个网口实现类似效果——我的回答是:完全可以,但有注意事项。
8.1 单设备双网口方案的优势
- 成本效益:无需额外硬件设备
- 管理简便:单一设备,维护更简单
- 配置灵活:可在系统层面精细控制路由策略
8.2 与传统双设备方案的对比
| 方面 | 单设备双网口方案 | 传统双设备方案 |
|---|---|---|
| 成本 | 低 | 高 |
| 复杂度 | 配置复杂,运行简单 | 配置简单,架构复杂 |
| 可靠性 | 单点故障风险 | 真正设备级冗余 |
| 性能 | 受单设备性能限制 | 可水平扩展 |
8.3 关键实现要点
要实现真正的冗余效果,需要注意:
- 物理隔离:两个网口应连接到不同的物理设备(交换机、路由器)
- 链路独立性:确保两条链路没有单点故障
- 状态监测:实现完整的链路状态检测和自动切换
- 会话保持:确保故障转移时现有连接不会全部中断
9. 嵌入式设备双网口冗余完整脚本实例
以下是一个针对嵌入式设备的完整双网口冗余实现脚本,包含初始化、健康检查和故障转移功能:
#!/bin/bash
# embedded_dual_wan_redundancy.sh
# 嵌入式设备双WAN口冗余脚本
# 适用于BusyBox等嵌入式环境
# 配置参数
PRIMARY_INTERFACE="eth0"
BACKUP_INTERFACE="eth1"
PRIMARY_IP="192.168.1.57/24"
BACKUP_IP="192.168.2.57/24"
PRIMARY_GW="192.168.1.1"
BACKUP_GW="192.168.2.1"
PRIMARY_TABLE="100"
BACKUP_TABLE="200"
HEALTH_CHECK_INTERVAL=5
PING_COUNT=3
PING_TIMEOUT=2
# 日志函数
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# 初始化网络配置
initialize_network() {
log_message "初始化网络配置..."
# 配置IP地址
ip addr add $PRIMARY_IP dev $PRIMARY_INTERFACE
ip addr add $BACKUP_IP dev $BACKUP_INTERFACE
# 启用接口
ip link set $PRIMARY_INTERFACE up
ip link set $BACKUP_INTERFACE up
# 添加路由表(如果不存在)
if ! grep -q "primary" /etc/iproute2/rt_tables 2>/dev/null; then
echo "$PRIMARY_TABLE primary" >> /etc/iproute2/rt_tables
fi
if ! grep -q "backup" /etc/iproute2/rt_tables 2>/dev/null; then
echo "$BACKUP_TABLE backup" >> /etc/iproute2/rt_tables
fi
# 配置主路由表
ip route add default via $PRIMARY_GW dev $PRIMARY_INTERFACE table primary
ip route add $PRIMARY_IP dev $PRIMARY_INTERFACE scope link table primary
ip route add 192.168.1.0/24 dev $PRIMARY_INTERFACE scope link table primary
# 配置备用路由表
ip route add default via $BACKUP_GW dev $BACKUP_INTERFACE table backup
ip route add $BACKUP_IP dev $BACKUP_INTERFACE scope link table backup
ip route add 192.168.2.0/24 dev $BACKUP_INTERFACE scope link table backup
# 配置策略路由规则
ip rule add from $PRIMARY_IP table primary pref 1000
ip rule add from $BACKUP_IP table backup pref 1001
ip rule add to 192.168.1.0/24 table primary pref 1002
ip rule add to 192.168.2.0/24 table backup pref 1003
# 设置反向路径过滤
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/$PRIMARY_INTERFACE/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/$BACKUP_INTERFACE/rp_filter
log_message "网络初始化完成"
}
# 健康检查函数
health_check() {
local target=$1
local interface=$2
local result=1
# 使用ping检查连通性
if ping -I $interface -c $PING_COUNT -W $PING_TIMEOUT $target > /dev/null 2>&1; then
result=0
fi
return $result
}
# 切换主路由
switch_to_primary() {
log_message "切换到主路由"
# 删除可能存在的备用默认路由
ip route del default via $BACKUP_GW dev $BACKUP_INTERFACE > /dev/null 2>&1
# 添加主默认路由
ip route add default via $PRIMARY_GW dev $PRIMARY_INTERFACE metric 50
# 更新策略规则优先级
ip rule del pref 1000 2>/dev/null
ip rule del pref 1001 2>/dev/null
ip rule add from $PRIMARY_IP table primary pref 1000
ip rule add from $BACKUP_IP table backup pref 1001
}
# 切换到备用路由
switch_to_backup() {
log_message "切换到备用路由"
# 删除可能存在的主动默认路由
ip route del default via $PRIMARY_GW dev $PRIMARY_INTERFACE > /dev/null 2>&1
# 添加备用默认路由
ip route add default via $BACKUP_GW dev $BACKUP_INTERFACE metric 100
# 更新策略规则优先级
ip rule del pref 1000 2>/dev/null
ip rule del pref 1001 2>/dev/null
ip rule add from $BACKUP_IP table primary pref 1000
ip rule add from $PRIMARY_IP table backup pref 1001
}
# 主循环
main_loop() {
local current_state="primary"
local primary_healthy=1
local backup_healthy=1
log_message "开始健康检查循环..."
while true; do
# 检查主链路健康状态
if health_check $PRIMARY_GW $PRIMARY_INTERFACE; then
if [ $primary_healthy -eq 0 ]; then
log_message "主链路恢复"
primary_healthy=1
fi
else
if [ $primary_healthy -eq 1 ]; then
log_message "主链路故障"
primary_healthy=0
fi
fi
# 检查备用链路健康状态
if health_check $BACKUP_GW $BACKUP_INTERFACE; then
if [ $backup_healthy -eq 0 ]; then
log_message "备用链路恢复"
backup_healthy=1
fi
else
if [ $backup_healthy -eq 1 ]; then
log_message "备用链路故障"
backup_healthy=0
fi
fi
# 根据健康状态决定路由策略
if [ $primary_healthy -eq 1 ] && [ "$current_state" != "primary" ]; then
switch_to_primary
current_state="primary"
elif [ $primary_healthy -eq 0 ] && [ $backup_healthy -eq 1 ] && [ "$current_state" != "backup" ]; then
switch_to_backup
current_state="backup"
elif [ $primary_healthy -eq 0 ] && [ $backup_healthy -eq 0 ] && [ "$current_state" != "none" ]; then
log_message "所有链路均不可用"
current_state="none"
fi
sleep $HEALTH_CHECK_INTERVAL
done
}
# 清理函数
cleanup() {
log_message "执行清理操作..."
# 删除添加的路由规则
ip rule del pref 1000 2>/dev/null
ip rule del pref 1001 2>/dev/null
ip rule del pref 1002 2>/dev/null
ip rule del pref 1003 2>/dev/null
# 删除自定义路由表内容
ip route flush table primary 2>/dev/null
ip route flush table backup 2>/dev/null
log_message "清理完成,退出"
exit 0
}
# 信号处理
trap cleanup SIGINT SIGTERM
# 主执行流程
log_message "启动嵌入式设备双WAN口冗余脚本"
# 检查root权限
if [ "$(id -u)" -ne 0 ]; then
echo "错误: 需要root权限运行此脚本" >&2
exit 1
fi
# 初始化网络
initialize_network
# 启动主循环
main_loop
脚本使用说明:
-
保存脚本:将脚本保存为
embedded_dual_wan_redundancy.sh -
赋予执行权限:
chmod +x embedded_dual_wan_redundancy.sh -
配置参数:根据实际网络环境修改脚本顶部的配置参数
-
运行脚本:
./embedded_dual_wan_redundancy.sh -
后台运行:
nohup ./embedded_dual_wan_redundancy.sh > /var/log/dual_wan.log 2>&1 &
脚本特性:
- 轻量级设计:适用于嵌入式设备资源受限环境
- 自动故障检测:定期检查两条链路的连通性
- 无缝切换:主链路故障时自动切换到备用链路
- 状态恢复:主链路恢复后自动切回
- 完整日志:记录所有重要操作和状态变化
- 信号处理:支持优雅退出和清理
- 错误处理:完善的错误检测和处理机制
这个脚本特别适合嵌入式设备使用,因为它:
- 使用标准的BusyBox命令
- 内存占用小
- 配置简单明了
- 具有完整的故障恢复能力
10. 总结
Linux高级路由策略提供了强大而灵活的网络控制能力,通过多路由表和策略路由的配合,可以在单台设备上实现复杂的路由策略,包括冗余备份、流量分流、负载均衡等高级功能。
虽然这种方案不能完全替代真正的多设备冗余架构,但在许多场景下提供了成本效益高且足够可靠的解决方案。特别是在预算有限或环境限制无法部署多设备的场景下,这种方案表现出色。
关键是要理解其原理,仔细配置和测试,特别是要注意避免常见的配置陷阱,如路由规则优先级、本地通信问题和反向路径过滤等。
通过本文介绍的方法和实例,您应该能够在自己的环境中实施Linux高级路由策略,构建更加稳定和高效的网络架构。嵌入式设备脚本提供了一个完整的实现参考,可以根据具体需求进行调整和优化。
2287

被折叠的 条评论
为什么被折叠?



