Cuộc Gọi Lúc 2 Giờ Sáng
Monitoring báo động. Người dùng không thể truy cập ứng dụng. SSH vào một nửa số server bị timeout. Bạn kiểm tra những thứ hiển nhiên — interface vẫn up, route trông ổn — rồi bạn phát hiện nó ẩn trong dmesg:
[ 4823.119472] neighbour: arp_cache: neighbor table overflow!
[ 4823.119512] Neighbour table overflow: ARP table full
Kernel của bạn đã hết chỗ trong bảng ARP. Các entry ARP mới không thể được tạo, vì vậy các gói tin gửi đến host mà server chưa thấy gần đây bị drop âm thầm. Trong một mạng phẳng /20 hoặc lớn hơn với hàng trăm host đang hoạt động, điều này xảy ra rất nhanh — đặc biệt trên gateway, load balancer, hoặc monitoring server phải giao tiếp với tất cả mọi thứ.
Điều Gì Đang Thực Sự Xảy Ra Bên Trong
Linux kernel duy trì một bảng neighbor (ARP cache) để ánh xạ địa chỉ IP sang địa chỉ MAC. Mặc định, nó được sizing cho các mạng nhỏ. Ba tham số kernel kiểm soát giới hạn:
gc_thresh1— dưới ngưỡng này, không có garbage collection nào chạy (mặc định: 128)gc_thresh2— giới hạn mềm; GC khởi động sau 5 giây nếu vượt quá (mặc định: 512)gc_thresh3— giới hạn cứng; không cho phép entry mới vượt qua điểm này (mặc định: 1024)
Trên một server bận rộn trong mạng /22 (~1000 host đang hoạt động), bạn chạm gc_thresh3 trong vài phút. Kernel bắt đầu âm thầm drop các gói tin đến bất kỳ host nào mà nó không thể ARP, đó là lý do tại sao mọi thứ trông ổn trên giấy tờ nhưng thực tế không có gì hoạt động.
Xác Nhận Trước Khi Thay Đổi Bất Cứ Điều Gì
Chạy các lệnh này để xác minh bảng ARP đã đầy và đang gây ra các gói tin bị drop:
# Kiểm tra kích thước bảng ARP hiện tại
ip neigh show | wc -l
# Kiểm tra giới hạn kernel hiện tại
cat /proc/sys/net/ipv4/neigh/default/gc_thresh1
cat /proc/sys/net/ipv4/neigh/default/gc_thresh2
cat /proc/sys/net/ipv4/neigh/default/gc_thresh3
# Tìm thông báo overflow trong log kernel gần đây
dmesg | grep -i 'neighbour\|arp' | tail -20
journalctl -k | grep -i 'neighbour table overflow' | tail -10
# Kiểm tra thống kê ARP cache (tra cứu thất bại)
netstat -s | grep -i 'arp\|fail'
Nếu ip neigh show | wc -l trả về một con số gần hoặc vượt quá gc_thresh3, đó là thủ phạm của bạn. Bạn cũng sẽ thấy các entry bị kẹt ở trạng thái FAILED:
ip neigh show | grep FAILED | head -20
Khắc Phục Ngay Lập Tức (Không Cần Reboot)
Tăng các ngưỡng ngay bây giờ để dừng việc drop gói tin:
sudo sysctl -w net.ipv4.neigh.default.gc_thresh1=4096
sudo sysctl -w net.ipv4.neigh.default.gc_thresh2=8192
sudo sysctl -w net.ipv4.neigh.default.gc_thresh3=16384
Cũng thấy ndisc_cache bị overflow? Bao gồm cả IPv6:
sudo sysctl -w net.ipv6.neigh.default.gc_thresh1=4096
sudo sysctl -w net.ipv6.neigh.default.gc_thresh2=8192
sudo sysctl -w net.ipv6.neigh.default.gc_thresh3=16384
Nhắm tới khoảng 2–3× số lượng host duy nhất dự kiến mỗi segment. Một mạng /20 có 4094 địa chỉ khả dụng — đặt gc_thresh3 ít nhất là 8192. Một mạng /16 với hàng nghìn VM đang hoạt động thì nên đặt 32768 hoặc cao hơn.
Giữ Cấu Hình Sau Khi Reboot
Các thay đổi sysctl -w đó sẽ mất sau khi reboot. Ghi chúng vào file cấu hình bền vững:
sudo tee /etc/sysctl.d/99-arp-table.conf <<EOF
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 8192
net.ipv4.neigh.default.gc_thresh3 = 16384
net.ipv6.neigh.default.gc_thresh1 = 4096
net.ipv6.neigh.default.gc_thresh2 = 8192
net.ipv6.neigh.default.gc_thresh3 = 16384
EOF
sudo sysctl --system
Xác Minh Bản Sửa Đã Hoạt Động
# Xác nhận giới hạn mới đang hoạt động
sysctl net.ipv4.neigh.default.gc_thresh3
# Bảng ARP giờ nên ở mức thấp hơn giới hạn nhiều
ip neigh show | wc -l
# Không còn thông báo overflow trong log kernel
dmesg | grep -i 'neighbour table overflow'
# Các entry FAILED tự xóa, nhưng bạn có thể flush ngay lập tức
ip neigh flush nud failed
ip neigh flush nud stale
Kết nối thường được khôi phục trong vài giây sau khi áp dụng các thay đổi sysctl. Nếu host vẫn không thể truy cập, hãy flush các entry ARP bị failed thủ công — kernel sẽ re-ARP và điền các entry mới ngay lập tức.
Tùy Chọn: Tinh Chỉnh Garbage Collection Cho Môi Trường Động
Chạy nhiều VM hoặc container liên tục khởi động và tắt? Cài đặt GC mặc định được thiết kế cho host tĩnh. Hãy siết chặt chúng lại:
# Thời gian trước khi entry không dùng trở thành stale
# Mặc định là 60 giây — 30 giây hiệu quả hơn khi IP được tái sử dụng thường xuyên
sudo sysctl -w net.ipv4.neigh.default.base_reachable_time_ms=30000
# GC chạy mỗi N giây (mặc định: 30, có thể giữ nguyên)
sudo sysctl -w net.ipv4.neigh.default.gc_interval=30
# Thời gian một entry stale tồn tại trước khi GC xóa nó
sudo sysctl -w net.ipv4.neigh.default.gc_stale_time=60
Nguyên Nhân Gốc Rễ Bạn Thực Sự Cần Giải Quyết
Tăng ngưỡng chỉ là giải pháp tạm thời. Nhưng hãy tự hỏi tại sao bạn có nhiều entry ARP như vậy ngay từ đầu:
- Mạng phẳng quá lớn — một mạng
/20trải rộng trên một domain Layer 2 duy nhất là vấn đề thiết kế. Chia nhỏ thành các VLAN nhỏ hơn với lõi được định tuyến. Mỗi segment nằm trong broadcast và ARP domain riêng, vì vậy không có server đơn lẻ nào cần biết về 4000 host. - Công cụ ARP scan hoặc monitoring — Nagios, Zabbix, hoặc một network scanner tùy chỉnh ping mọi IP trong dải
/20sẽ làm ngập bảng ARP trong vài phút. Kiểm tra xem cái gì đang chạy broad ping trên toàn segment. - Broadcast storm — chạy
tcpdump -i eth0 arp | pv -l -r > /dev/nullđể xem tốc độ ARP request trực tiếp. Hàng trăm mỗi giây có nghĩa là bạn gặp vấn đề khuếch đại broadcast, không chỉ là vấn đề kích thước bảng. - Kubernetes hoặc container overlay — các cluster lớn làm cạn kiệt bảng ARP nhanh chóng vì mỗi pod có IP riêng. Áp dụng cùng bản sửa sysctl, nhưng cũng kiểm tra xem CNI của bạn (Calico, Flannel, Cilium) có cấu hình bảng neighbor riêng cần tinh chỉnh không.
Mẹo Lập Kế Hoạch Mạng
Khi bạn chia một mạng phẳng lớn thành các VLAN nhỏ hơn để giảm áp lực ARP, việc tính toán subnet đúng rất quan trọng. Tôi dùng Subnet Calculator trên ToolCraft để tính dải CIDR, số lượng host khả dụng, và địa chỉ broadcast khi lập kế hoạch chia VLAN — nó chạy hoàn toàn trên trình duyệt, không có dữ liệu nào rời khỏi máy bạn, điều này quan trọng khi bạn làm việc với các sơ đồ IP nội bộ.
Những Điều Cần Ghi Nhớ
- Giới hạn ARP mặc định 1024 entry có ý nghĩa vài thập kỷ trước. Bất kỳ mạng phẳng hiện đại nào lớn hơn
/22đều cần các giá trị này được tinh chỉnh từ lúc provisioning — không phải phát hiện ra lúc 2 giờ sáng trong một sự cố. - Thêm mức bão hòa bảng ARP vào monitoring của bạn. Một metric duy nhất —
ip neigh show | wc -lchia chogc_thresh3— cho bạn cảnh báo sớm trước khi nó ảnh hưởng đến production. - Thêm các giá trị sysctl này vào Ansible playbook hoặc cloud-init config của bạn. Lần thứ hai bạn phải truy đuổi vấn đề này lúc 2 giờ sáng là hoàn toàn có thể tránh được.
- Nếu overflow cứ tái diễn sau khi bạn đã tăng ngưỡng, bạn đang giải quyết sai vấn đề. Đó là vấn đề kiến trúc mạng, không phải vấn đề tinh chỉnh Linux.

