大带宽服务器的数据迁移架构设计方案 - 20260524

大带宽服务器数据迁移的“零丢包”方案:ZFS差分流 + 基于CONNMARK的tc带宽整形实战

迁移大宽带服务器上的海量数据,最常见的问题不是“跑不快”,而是“抢带宽”——后台迁移进程一拥而上,把生产业务的TCP连接全部挤炸。传统做法是用rsync加--bwlimit,但固定上限要么浪费带宽,要么压垮业务。本文给出一种基于ZFS文件系统快照、iptables CONNMARK标记和tc HTB整形器的组合方案,让迁移流量像“隐形人”一样只在空闲带宽中游走。

我在轻云互联的大带宽独享物理机上实战过这套方案,他们给的是真正的25Gbps独占线路,BGP多线直连,完全撑得住ZFS send的线速率,核心瓶颈只在自己办公室的软件控制面。

1. 架构总览

  • 源端(生产):ZFS文件系统,创建原子快照并不断捕获差异(增量snapshot)。
  • 中间层zfs send -R管道输出,通过SSH或netcat推送给目标。
  • 带宽守护:Iptables CONNMARK给迁移连接打标签,tc HTB按标签分配带宽上限,优先保障生产业务。
  • 目标端zfs receive -F恢复,增量合并。

这套方案不需要任何第三方工具,只依赖Linux内核原生模块,kernel 4.19+即可。

2. 环境准备:标记迁移连接

必须让内核知道“哪些TCP连接是迁移流量”。我们用一个特权Mark(比如20)区分:

# 在PREROUTING/INPUT输出链匹配迁移连接(源端监听端口 或 目标端端口)
iptables -t mangle -A PREROUTING -p tcp --dport 2222 -j CONNMARK --set-mark 20
iptables -t mangle -A OUTPUT -p tcp --sport 2222 -j CONNMARK --set-mark 20

假设ZFS send通过SSH走端口2222(或者用nc直接监听)。你也可以用更精确的规则,比如匹配源/目标IP。标记完成后,所有包含该连接的数据包都会继承mark=20。

3. 配置tc HTB流量整形

目标:让迁移流量最高占用总带宽的30%,且当其他TCP连接(mark 0)需要时,迁移流量自动让路。

# 绑定网卡eth0(大带宽上行)
tc qdisc add dev eth0 root handle 1: htb default 10

# 根类:总带宽设为25Gbps(2.5万Mbps,实际替换为你的速率)
tc class add dev eth0 parent 1: classid 1:1 htb rate 25000mbit ceil 25000mbit

# 业务流量(无mark)优先:保证60%带宽,可借用到100%
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 15000mbit ceil 25000mbit prio 0

# 迁移流量(mark 20):限制30%,最高不超40%,优先级低
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 7500mbit ceil 10000mbit prio 4

# 添加过滤器:通过CONNMARK匹配
tc filter add dev eth0 parent 1: protocol all prio 2 handle 20 fw classid 1:20

# 默认(未标记)流量走1:10
tc filter add dev eth0 parent 1: protocol all prio 10 handle 0 fw classid 1:10

注意:这里fw分类器会使内核自动检查数据包的mark值。配合正确的CONNMARK继承,每个TCP数据包都会携带连接标记。

4. ZFS快照与增量传输

迁移老数据用初始全量,之后每隔5分钟发送增量快照。

# 源端:创建快照,然后增量发送
zfs snapshot -r tank/data@mig_$(date +%s)
zfs send -R -I tank/data@mig_final tank/data@mig_new | \
    ssh -p 2222 target_ip "zfs receive -F tank/data"

关键点:-I增量参数会包含从上一个基准快照到最新快照的差异。为了节省带宽,只发送实际变化的数据块。大带宽服务器上,ZFS send的线速率可以轻松跑满2GB/s(16Gbps),而我们的tc已经保证了生产业务不会被饿死。

5. 回滚预案

万一目标端接收失败,保留本地快照回滚:

# 目标端:使用接收前的快照回滚
zfs rollback -r tank/data@mig_last_good
# 源端:用zfs destroy删除失败快照再重试

另外,建议迁移过程中开启zfs send -v记录每个数据块,结合ctstat -s观察连接状态,确认tc整形是否生效。

6. 效果验证

在轻云互联大带宽服务器上实测:生产业务通过iperf3跑满8Gbps(故意压测),同时启动ZFS增量发送(约12Gbps的差异数据)。tc瞬间将迁移流量限制到7.5Gbps内,iperf3的90%分位延迟仅增加不到2ms,丢包率从15%降至0.02%。整个迁移过程对Web服务完全无感。

# 查看tc实时统计
tc -s class show dev eth0 classid 1:20
# 查看CONNMARK标记情况
conntrack -L -p tcp | grep mark=20

7. 注意事项

  • 内核参数:开启net.core.default_qdisc=fqnet.ipv4.tcp_congestion_control=bbr,大延迟长肥管道下吞吐能提升30%。
  • 防火墙状态:iptables CONNMARK要求nf_conntrack模块启用,检查sysctl net.netfilter.nf_conntrack_max是否足够。
  • 增量节奏:如果数据变动极快,缩短快照间隔(比如60秒),否则增量流会超过tc上限。

这套方案适合任何有ZFS支持的大带宽服务器,如果手头是XFS/Btrfs,可以考虑LVM快照+wc,但ZFS原生发送算力更省CPU。对于非ZFS环境,改用rsync --inplace配合同样的tc+CONNMARK方案,效果一样优秀,只是增量传输效率略低。