Những đợt tăng vọt độ trễ và rớt session SSH không ai mong muốn
Quý trước, hệ thống phân tán của chúng tôi đã va phải một bức tường cản trở lớn. Tiến trình backup giữa các node US-East và EU-Central chậm chạp đến mức gần như đình trệ, thường chạm trần ở mức khoảng 140 Mbps trên đường truyền 1 Gbps. Các session SSH bị treo cứng trong những đợt migration schema PostgreSQL lớn, còn các query trên môi trường staging thì thường xuyên bị timeout. Các tunnel OpenVPN ngốn sạch chu kỳ CPU và làm thất thoát gần 45% băng thông thô.
Tệ hơn nữa, toàn bộ outbound traffic của mọi developer đều bị định tuyến qua một gateway trung tâm duy nhất chỉ để truy cập một Redis instance nội bộ tại 192.168.50.12. Một lệnh npm install đơn giản hay một cuộc gọi Zoom cũng cạnh tranh trực tiếp với các tiến trình đồng bộ dữ liệu production. Gateway đó thường xuyên đẩy hai nhân CPU lên mức tải 90% trong giờ làm việc cao điểm.
Nguyên nhân gốc rễ: Giao thức cồng kềnh và định tuyến nguyên khối
Hai lỗ hổng mang tính hệ thống đã bóp nghẹt hiệu năng mạng của chúng tôi:
1. Chuyển đổi ngữ cảnh ở user-space và overhead của TLS
Các VPN dùng SSL/TLS truyền thống hoạt động ở user space. Từng gói tin đơn lẻ phải đi qua ranh giới giữa kernel và user space hai lần: một lần khi được interface ảo TUN/TAP bắt giữ, và lần nữa khi được mã hóa rồi trả ngược lại cho network socket. Việc context switching liên tục này phá hủy CPU cache locality của L1/L2 và đẩy load average lên mức báo động. Khi đường truyền giữa các đám mây bị rớt gói từ 1% đến 2%, cơ chế handshake có trạng thái (stateful) của OpenVPN bị nghẽn lại, kéo theo sự đình trệ của các TCP session đang hoạt động phía sau.
2. Thiết lập mặc định ‘Route Everything’
Các profile client của chúng tôi đẩy toàn bộ 0.0.0.0/0 qua tunnel một cách mù quáng. Việc chuyển hướng default gateway đồng nghĩa với việc các hoạt động tải package bên ngoài thông thường, stream video và gọi public API đều bị kéo lê qua gateway staging. Do không có bảng định tuyến cô lập, lưu lượng quản trị nội bộ đã làm tê liệt đường truyền internet công cộng.
So sánh thực nghiệm: OpenVPN vs. IPsec vs. WireGuard
Chúng tôi đã thử nghiệm cả ba giải pháp trên các node có cấu hình giống hệt nhau gồm 4 core, 8 GB RAM chạy Ubuntu 22.04 LTS trên đường truyền 1 Gbps bằng iperf3:
- OpenVPN (v2.5, UDP, AES-256-GCM): Chạm trần ở mức 165 Mbps trong khi ép một nhân CPU chạy 100%. Việc quản lý Certificate Authority nội bộ và xử lý xoay vòng chứng chỉ tạo ra gánh nặng vận hành tẻ nhạt.
- IPsec / strongSwan (IKEv2, AES-128-GCM): Nhanh và chạy trực tiếp ở kernel, đạt 780 Mbps với mức tải CPU 24%. Tuy nhiên, cú pháp cấu hình trong
swanctl.confkhá phức tạp. Quá trình rekeying qua các AWS NAT gateway có trạng thái đã làm gián đoạn handshake hai lần trong bài kiểm tra độ bền kéo dài hai tuần của chúng tôi. - WireGuard (Kernel Module): Đạt tốc độ tối đa 935 Mbps với chỉ 4% mức sử dụng CPU tổng thể. Được tích hợp sẵn vào Linux 5.6+, WireGuard dựa trên các nguyên mẫu hiện đại: Curve25519 cho trao đổi khóa, ChaCha20-Poly1305 cho mã hóa xác thực, và BLAKE2s cho băm. Toàn bộ mã nguồn chỉ vỏn vẹn dưới 4.000 dòng C dễ đọc. WireGuard duy trì mối quan hệ peer dựa trên UDP một cách âm thầm, giảm thiểu overhead của handshake về 0 cho đến khi thực sự có dữ liệu cần truyền tải.
Bản thiết kế triển khai Production: Kernel WireGuard kết hợp Split Tunneling
Chúng tôi đã triển khai thử nghiệm cấu hình này trên hai node production: Node A (Gateway: 203.0.113.10) và Node B (Remote Worker: 198.51.100.4). Thay vì chuyển toàn bộ lưu lượng internet qua tunnel, chúng tôi giới hạn đường truyền nghiêm ngặt chỉ trong các private subnet.
Bước 1: Cài đặt công cụ và tạo khóa mã hóa
Cài đặt các công cụ quản lý kernel trên cả hai máy:
# Ubuntu / Debian
sudo apt update && sudo apt install -y wireguard wireguard-tools
# RHEL / Rocky Linux 9 / AlmaLinux 9
sudo dnf install -y epel-release
sudo dnf install -y wireguard-tools
WireGuard sử dụng mật mã khóa công khai lấy cảm hứng từ Noise và SSH. Trên cả hai node, hãy tạo một private key và trích xuất public key tương ứng với quyền truy cập file nghiêm ngặt:
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
Bước 2: Cấu hình Gateway Server (Node A)
Tạo file /etc/wireguard/wg0.conf trên Node A. Trong kiến trúc này, Node A sử dụng IP tunnel nội bộ là 10.100.0.1/24 và lắng nghe trên cổng UDP 51820:
[Interface]
Address = 10.100.0.1/24
ListenPort = 51820
PrivateKey = <NODE_A_PRIVATE_KEY>
# Chuyển tiếp gói tin và xử lý NAT cho private subnet nội bộ (192.168.50.0/24)
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = <NODE_B_PUBLIC_KEY>
AllowedIPs = 10.100.0.2/32
Lưu cấu hình packet forwarding vĩnh viễn trong kernel để Node A có thể định tuyến các gói tin giữa các interface:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
Bước 3: Cấu hình Client với Split Tunneling (Node B)
Để loại bỏ tình trạng chiếm dụng băng thông trên gateway, hãy cấu hình Node B với bảng định tuyến chính xác. Bằng cách giới hạn AllowedIPs chỉ cho các subnet nội bộ (10.100.0.0/24 và 192.168.50.0/24), wg-quick sẽ tự động thêm các route cụ thể vào kernel. Mọi outbound traffic khác vẫn sẽ đi theo route mặc định cục bộ của Node B.
Tạo file /etc/wireguard/wg0.conf trên Node B:
[Interface]
Address = 10.100.0.2/24
PrivateKey = <NODE_B_PRIVATE_KEY>
[Peer]
PublicKey = <NODE_A_PUBLIC_KEY>
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.100.0.0/24, 192.168.50.0/24
PersistentKeepalive = 25
Tham số PersistentKeepalive = 25 sẽ gửi một gói tin rỗng đã được xác thực sau mỗi 25 giây. Việc này duy trì các bảng NAT stateful hoạt động trong firewall đám mây, đảm bảo các kết nối đến được Node B ngay cả khi nằm sau hệ thống NAT khắt khe của nhà cung cấp.
Bước 4: Kích hoạt kết nối và kiểm tra Handshake
Khởi động các interface bằng wg-quick và cấu hình systemd để tự động chạy khi khởi động hệ thống:
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0
Kiểm tra trạng thái kết nối trên một trong hai node:
sudo wg show wg0
Bạn sẽ thấy session đã được thiết lập cùng với bộ đếm lưu lượng hai chiều:
interface: wg0
public key: hK9sB8r3G2...x8=
listening port: 51820
peer: rF3wK91mP0...m1=
endpoint: 198.51.100.4:51820
latest handshake: 18 giây trước
transfer: 4.82 MiB đã nhận, 11.29 MiB đã gửi
Test the route from Node B. Only packets bound for the internal network should traverse wg0:
ip route get 192.168.50.12
# Kết quả: 192.168.50.12 dev wg0 src 10.100.0.2
ip route get 1.1.1.1
# Kết quả: 1.1.1.1 via 198.51.100.1 dev eth0 src 198.51.100.4
Bước 5: Phòng thủ theo chiều sâu (Defense-in-Depth) với Pre-Shared Key và giới hạn Firewall
Khi thiết lập các liên kết mesh hoặc point-to-point giữa nhiều nhà cung cấp cloud khác nhau, hãy bổ sung thêm một lớp mã hóa đối xứng để phòng ngừa các kỹ thuật thám mã lượng tử trong tương lai đối với handshake của Curve25519. Tạo một pre-shared key (PSK):
wg genpsk > preshared.key
Thêm dòng PresharedKey = <CONTENTS_OF_FILE> vào bên dưới phần [Peer] trong file cấu hình của cả hai node. WireGuard sẽ trộn chuỗi bí mật 256-bit này vào quá trình băm handshake mà không gây ra bất kỳ độ trễ đáng kể nào.
Tiếp theo, hãy siết chặt quyền truy cập vào cổng lắng nghe UDP. Không mở cổng 51820 ra toàn bộ public internet nếu peer của bạn sử dụng IP tĩnh công khai. Hãy khóa chặt cổng này chỉ dành riêng cho địa chỉ IP gốc từ xa:
# UFW (Ubuntu / Debian)
sudo ufw allow proto udp from 198.51.100.4 to any port 51820 comment "Peer WireGuard Node B"
# firewalld (RHEL / Rocky / AlmaLinux)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.4" port port="51820" protocol="udp" accept'
sudo firewall-cmd --reload
Những kết quả đo lường rõ rệt trong môi trường Production
Việc chuyển đổi này đã giải quyết triệt để các nút thắt cổ chai ngay lập tức. Độ trễ point-to-point giữa các node khác vùng giảm mạnh từ 48ms xuống còn 19ms, trong khi hiện tượng jitter của ping giảm từ ±14ms xuống dưới 0.8ms. Khi tiến trình đồng bộ backup cơ sở dữ liệu đạt tốc độ tối đa 1 Gbps, mức tải CPU của gateway vẫn duy trì ổn định dưới 6%. Split tunneling đã giải phóng hoàn toàn đường truyền trung tâm, cho phép các developer làm việc với các database nội bộ ở tốc độ nguyên bản mà không làm nghẽn kết nối internet công cộng.

