Network Bonding trên Linux: Cấu hình tăng bandwidth và failover tự động cho server

Network tutorial - IT technology blog
Network tutorial - IT technology blog

Bối cảnh — Tại sao cần Network Bonding

Câu chuyện bắt đầu lúc 2 giờ sáng thứ Sáu. Database server đột nhiên mất kết nối mạng. Alert đổ về đầy màn hình, hơn 50 nhân viên văn phòng sáng hôm sau không thể làm việc nếu database không lên được. Khi chạy vào server room kiểm tra, mình phát hiện một card mạng bị lỗi — cái card duy nhất kết nối server vào switch.

Đó là lần đầu tiên mình thực sự hiểu tại sao network bonding lại tồn tại.

Network bonding (còn gọi là NIC teaming hay link aggregation) là kỹ thuật gộp nhiều card mạng vật lý thành một interface logic duy nhất. Lợi ích rõ ràng nhất:

  • Failover tự động: Một card chết, card kia tiếp quản ngay — không downtime
  • Load balancing: Phân tải traffic qua nhiều đường dây song song
  • Tăng bandwidth: 2 card 1Gbps → có thể đạt 2Gbps aggregated tùy mode

Linux hỗ trợ 7 bonding mode, nhưng thực tế mình dùng chủ yếu 2 mode sau:

  • mode 1 (active-backup): Chỉ 1 card active, card còn lại standby. Đơn giản, không cần switch đặc biệt — đây là lựa chọn mặc định cho production
  • mode 4 (802.3ad/LACP): Cần switch hỗ trợ LACP, nhưng đổi lại tăng được bandwidth thật sự — dùng cho database/storage server cần throughput cao

Cài đặt

Ubuntu 20.04+ đã bundle sẵn bonding driver trong kernel. Kiểm tra có load chưa:

modprobe bonding
lsmod | grep bonding

Nếu output trống, load module thủ công và đặt auto-load lúc boot:

echo "bonding" >> /etc/modules
modinfo bonding

Với Ubuntu 18.04 trở xuống, cài thêm ifenslave:

apt-get install ifenslave -y

CentOS/RHEL 8+ không cần làm gì thêm — driver có sẵn trong kernel, chỉ cần dùng nmcli để cấu hình.

Cấu hình chi tiết

Cách 1: Dùng netplan (Ubuntu 20.04+)

Đây là cách mình hay dùng nhất cho Ubuntu server hiện tại. Trước tiên xem file config hiện có:

ls /etc/netplan/
# Thường là: 00-installer-config.yaml hoặc 01-netcfg.yaml

Backup file cũ trước khi chỉnh:

cp /etc/netplan/00-installer-config.yaml /etc/netplan/00-installer-config.yaml.bak

File config đầy đủ cho active-backup bonding:

# /etc/netplan/00-installer-config.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: false
      dhcp6: false
    eth1:
      dhcp4: false
      dhcp6: false
  bonds:
    bond0:
      interfaces: [eth0, eth1]
      addresses: [192.168.1.100/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 1.1.1.1]
      parameters:
        mode: active-backup
        primary: eth0
        mii-monitor-interval: 100

Một chi tiết đáng chú ý: mii-monitor-interval: 100 là khoảng thời gian (ms) kernel check trạng thái card. Mình từng để 200ms và thấy failover hơi chậm rõ rệt — 100ms là ngưỡng tốt cho production.

Apply config — luôn dùng netplan try trước khi làm trên remote server:

netplan try     # Test 120 giây, nếu mất kết nối sẽ rollback tự động
netplan apply   # Xác nhận apply vĩnh viễn

Mình đã suýt tự khóa mình khỏi server production một lần vì bỏ qua bước netplan try. Đừng bao giờ bỏ qua nó.

Cấu hình mode 802.3ad (LACP) — tăng bandwidth thật sự

Phía switch cần tạo port-channel/LAG với LACP enabled trước. Sau đó chỉnh phần parameters trong file netplan:

bonds:
  bond0:
    interfaces: [eth0, eth1]
    addresses: [192.168.1.100/24]
    gateway4: 192.168.1.1
    parameters:
      mode: 802.3ad
      lacp-rate: fast
      transmit-hash-policy: layer3+4
      mii-monitor-interval: 100

transmit-hash-policy: layer3+4 dùng cả IP lẫn port để hash traffic — phân tải đều hơn so với layer2 mặc định chỉ hash theo MAC.

Cách 2: Dùng nmcli (CentOS/RHEL/Rocky Linux)

# Tạo bond interface
nmcli connection add type bond \
  con-name bond0 \
  ifname bond0 \
  bond.options "mode=active-backup,miimon=100"

# Gắn eth0 và eth1 làm slave
nmcli connection add type ethernet \
  con-name bond0-slave-eth0 \
  ifname eth0 \
  master bond0

nmcli connection add type ethernet \
  con-name bond0-slave-eth1 \
  ifname eth1 \
  master bond0

# Gán IP tĩnh cho bond0
nmcli connection modify bond0 \
  ipv4.addresses "192.168.1.100/24" \
  ipv4.gateway "192.168.1.1" \
  ipv4.dns "8.8.8.8,1.1.1.1" \
  ipv4.method manual

# Kích hoạt
nmcli connection up bond0

Xác nhận kết nối đã lên sau khi apply:

nmcli connection show
nmcli device status

Kiểm tra & Monitoring

Đọc trạng thái bonding từ kernel

Kernel expose toàn bộ trạng thái bonding qua /proc/net/bonding/bond0 — đây là nơi đầu tiên cần nhìn vào khi debug:

cat /proc/net/bonding/bond0

Output khi cả 2 card đang healthy:

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: eth0 (primary_reselect failure)
Currently Active Slave: eth0
MII Status: up
MII Polling Interval (ms): 100

Slave Interface: eth0
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0

Slave Interface: eth1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0

MII Status: up trên cả 2 slave và Currently Active Slave đúng card primary là dấu hiệu mọi thứ đang ổn. Theo dõi Link Failure Count để phát hiện card chập chờn — số này tăng dần là dấu hiệu card sắp hỏng, dù chưa down hẳn.

Test failover thực tế — bước không được bỏ qua

Cấu hình xong mà không test failover thì chẳng khác gì không có bonding. Mở 2 terminal:

# Terminal 1: Ping liên tục đến gateway
ping -i 0.2 192.168.1.1

# Terminal 2: Tắt card active để simulate lỗi phần cứng
ip link set eth0 down

# Quan sát Terminal 1 — lý tưởng là không có packet lost
# Nếu thấy 1-2 packet drop là bình thường, hơn 5 packet drop là cần xem lại mii-monitor-interval

# Bật lại sau khi test
ip link set eth0 up

Với mii-monitor-interval: 100ms, failover thường xảy ra trong vòng 200–300ms — đủ nhanh để TCP connection không bị reset.

Monitor real-time và các lệnh hữu ích

# Theo dõi trạng thái liên tục
watch -n 1 'cat /proc/net/bonding/bond0 | grep -E "Currently Active|MII Status|Link Failure"'

# Kiểm tra tốc độ và trạng thái vật lý từng card
ethtool eth0 | grep -E "Speed|Duplex|Link detected"
ethtool eth1 | grep -E "Speed|Duplex|Link detected"

# Thống kê bytes TX/RX per interface (xem phân tải traffic)
ip -s link show eth0
ip -s link show eth1

# Xem log kernel khi có failover event
journalctl -k | grep -i "bond\|enslaved\|link failure"

Đang dùng Prometheus + node_exporter? Metric node_network_up{device="bond0"}node_network_up{device="eth0"} tự track trạng thái bond và từng slave — không cần cấu hình thêm gì.

Những vấn đề thực tế đã gặp

Mình quản lý network cho office 50 người và datacenter nhỏ, đã gặp đủ mọi kiểu vấn đề với bonding — ghi lại đây để bạn khỏi mất cả đêm như mình:

  1. MAC address conflict với LACP: Switch cần thấy MAC của bond0, không phải MAC của từng slave riêng. Switch cũ không support LACP properly sẽ gây loop hoặc block port. Khi không chắc về switch, dùng mode 1 (active-backup) luôn an toàn hơn.
  2. Interface rename sau reboot: Từng gặp bonding hoạt động tốt, nhưng sau reboot thì eth0/eth1 tự đổi thành eth2/eth3 — do udev thay đổi thứ tự detect card. Cấu hình hỏng sạch, không có lỗi rõ ràng để debug. Luôn dùng tên predictable kiểu enp3s0, đừng tin vào eth0.
  3. VLAN trên bonding: Hoàn toàn được hỗ trợ. Tạo VLAN interface trên bond0 bình thường — không cần tạo VLAN trên từng slave riêng lẻ.
  4. Bonding trong VM: Server hypervisor thì bond ở host level rồi expose virtual NIC cho VM. Không bond bên trong guest VM — hypervisor layer đã handle failover rồi, bond thêm bên trong chỉ thêm phức tạp không cần thiết.

Sau cái đêm 2 giờ sáng đó, toàn bộ production server của mình đều chạy active-backup bonding. Một năm trở lại đây đã có 3 lần card mạng lỗi, cả 3 lần failover đều diễn ra trong im lặng hoàn toàn — không ai hay biết, không ticket support nào được mở. Đó là cách infrastructure tốt nên vận hành.

Share: