4. 网关以太网与 4G 双上行链路切换配置
双上行链路拓扑与切换判据
农业物联网网关通常部署在田间机井房或大棚控制柜内,以太网接入本地光纤/宽带,4G 作为备份。要让“主用断开、备用接管”真正可靠,核心不是把两条线都插上,而是明确三件事:链路健康如何检测、切换判据与回切条件、切换期间数据如何补传。下图给出本例的链路结构与检测点分布。
链路参数与切换策略配置
以下配置以常见的 Linux 网关(OpenWrt 或 Debian 系)为例,用 ip route 的 metric 值表达主备优先级:metric 越小越优先。以太网 metric 100、4G metric 600,正常情况下流量走以太网;当以太网探测失败时,脚本删除以太网默认路由,4G 路由自动成为最优。
# 1) 查看当前默认路由与接口状态
ip route show default
ip -brief addr show eth0
ip -brief addr show wwan0
# 2) 设定主备默认路由(metric 决定优先级)
sudo ip route replace default via 192.168.1.1 dev eth0 metric 100
sudo ip route replace default via 10.64.3.1 dev wwan0 metric 600
# 3) 链路探测参数(写入 /etc/gw-link-monitor.conf)
PROBE_TARGETS="223.5.5.5 8.8.8.8"
PROBE_INTERVAL=5 # 探测间隔 5 s
PROBE_FAIL_THRESHOLD=3 # 连续 3 次失败判定断链
PROBE_RECOVER_WAIT=60 # 主链路恢复后等待 60 s 再回切
PRIMARY_IF=eth0
PRIMARY_GW=192.168.1.1
BACKUP_IF=wwan0
BACKUP_GW=10.64.3.1
CACHE_DIR=/var/spool/gw-cache
探测脚本的核心逻辑是“失败计数 + 状态机”,避免单次丢包就误切换。下面给出可直接运行的 Bash 实现,探测使用 ping -I 绑定源接口,确保测的是该链路本身而不是系统默认路由。
#!/bin/bash
# /usr/local/bin/gw-link-monitor.sh
source /etc/gw-link-monitor.conf
fail=0
state="primary" # primary | backup
probe_if() {
local iface=$1
for t in $PROBE_TARGETS; do
if ping -I "$iface" -c 1 -W 2 "$t" >/dev/null 2>&1; then
return 0
fi
done
return 1
}
switch_to_backup() {
ip route del default via "$PRIMARY_GW" dev "$PRIMARY_IF" 2>/dev/null
ip route replace default via "$BACKUP_GW" dev "$BACKUP_IF" metric 600
logger -t gw-link "PRIMARY down -> switch to 4G"
state="backup"
}
switch_to_primary() {
ip route replace default via "$PRIMARY_GW" dev "$PRIMARY_IF" metric 100
ip route replace default via "$BACKUP_GW" dev "$BACKUP_IF" metric 600
logger -t gw-link "PRIMARY recovered -> back to eth0"
state="primary"
}
while true; do
if [ "$state" = "primary" ]; then
if probe_if "$PRIMARY_IF"; then
fail=0
else
fail=$((fail+1))
if [ "$fail" -ge "$PROBE_FAIL_THRESHOLD" ]; then
switch_to_backup
fail=0
fi
fi
else
# 备用态:先确认 4G 可用,再判断主链路是否恢复
if ! probe_if "$BACKUP_IF"; then
logger -t gw-link "WARN: 4G also unreachable"
fi
if probe_if "$PRIMARY_IF"; then
sleep "$PROBE_RECOVER_WAIT"
probe_if "$PRIMARY_IF" && switch_to_primary
fi
fi
sleep "$PROBE_INTERVAL"
done
探测目标建议同时配置一个公共 DNS(如 223.5.5.5)和云平台域名解析结果,避免“能 ping 通外网但平台不可达”的假健康状态。若网关使用
mwan3 等现成多拨组件,可用其 health check 配置替代上述脚本,判据参数含义一致。断网注入验证与数据补传
验证分两步:先测切换时延,再测补传完整性。切换时延的观测方法是:在网关侧持续向云平台发送带序号的心跳,同时在 PC 上以 1 s 间隔记录时间戳;拔掉网线后,统计从最后一次以太网成功心跳到第一次 4G 成功心跳之间的时间差。
| 验证项 | 注入方式 | 观测点 | 预期判据 |
|---|---|---|---|
| 主链路断链切换 | 拔掉 eth0 网线 | 心跳序号 + 时间戳日志 | ≤ 20 s 内恢复上行(3×5 s 探测 + 拨号/路由收敛) |
| 主链路恢复回切 | 重新插回网线 | 默认路由与出口 IP | 60 s 稳定后回切至 eth0,无频繁抖动 |
| 4G 弱信号 | 移至信号弱区或遮挡天线 | RSSI、重拨次数 | 不误判为“主链路故障”,仅记录告警 |
| 数据补传 | 断网 5 min 后恢复 | 平台时序库记录数 | 断网期间数据全部到达,按时间戳排序无缺失 |
补传依赖本地缓存队列。采集程序在 MQTT 发布失败时把消息写入磁盘队列,恢复后按时间顺序重发,并携带原始采集时间戳,平台侧按 deviceId + timestamp 去重。下面是一个最小可用的补传逻辑示例(Python,使用 paho-mqtt):
import json, os, time, sqlite3
import paho.mqtt.client as mqtt
DB = "/var/spool/gw-cache/queue.db"
conn = sqlite3.connect(DB)
conn.execute("""CREATE TABLE IF NOT EXISTS pending(
id INTEGER PRIMARY KEY AUTOINCREMENT,
topic TEXT, payload TEXT, ts INTEGER)""")
conn.commit()
def enqueue(topic, payload):
conn.execute("INSERT INTO pending(topic,payload,ts) VALUES(?,?,?)",
(topic, json.dumps(payload), int(time.time())))
conn.commit()
def flush(client):
rows = conn.execute(
"SELECT id,topic,payload FROM pending ORDER BY id LIMIT 200").fetchall()
for rid, topic, payload in rows:
info = client.publish(topic, payload, qos=1)
if info.rc != mqtt.MQTT_ERR_SUCCESS:
break
conn.execute("DELETE FROM pending WHERE id=?", (rid,))
conn.commit()
client = mqtt.Client(client_id="gw-farm-01")
client.connect("mqtt.example-farm.cn", 1883, 30)
client.loop_start()
# 采集循环:先尝试直发,失败则入队
while True:
data = {"temp": 23.6, "soil_ec": 1.42, "ts": int(time.time())}
info = client.publish("farm/zone1/sensor", json.dumps(data), qos=1)
if info.rc != mqtt.MQTT_ERR_SUCCESS:
enqueue("farm/zone1/sensor", data)
else:
flush(client) # 链路正常时顺带清空积压
time.sleep(60)
补传队列必须设置容量上限(如 5000 条或 7 天),否则长时间断网会写满网关存储导致采集程序崩溃。队列满时应丢弃最旧数据并记录丢弃计数,便于事后评估数据完整率。
结果判读与常见问题
- 切换时延超标:多为 4G 拨号耗时或路由未及时删除。检查
ip route show default是否同时存在两条默认路由且 metric 未生效。 - 反复切换(抖动):探测阈值过严或回切等待过短。将失败阈值提高到 3 次以上、回切等待设为 60 s,并确认探测目标稳定。
- 补传重复:QoS 1 本身可能重复,平台侧必须按时间戳去重;不要依赖“只发一次”。
- 4G 有信号但不可达:检查 APN 与拨号状态,
ping -I wwan0失败而ifconfig wwan0有 IP,通常是运营商侧未放行或 DNS 问题。
完成上述配置与注入验证后,网关应具备“以太网优先、4G 兜底、断网缓存、恢复补传”的完整上行能力,切换时延与数据完整性均有可量化判据。