Linux QoS với tc và iproute2: Đừng để các bản Backup làm nghẽn ứng dụng của bạn

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Xử lý nghẽn băng thông

Tất cả chúng ta đều đã từng gặp tình huống này: một bản sao lưu cơ sở dữ liệu 50GB bắt đầu chạy, và đột nhiên thời gian phản hồi của web server tăng vọt từ 20ms lên 2 giây. Trong môi trường Linux mặc định, kernel xử lý các gói tin theo nguyên tắc ai đến trước phục vụ trước (first-come, first-served). Điều này có nghĩa là một tệp ISO lớn đang tải xuống có thể dễ dàng đẩy phiên SSH quan trọng hoặc truy vấn cơ sở dữ liệu của bạn xuống cuối hàng đợi.

Traffic Control (tc), một phần của bộ công cụ iproute2, là công cụ tiêu chuẩn trong ngành để giải quyết vấn đề này. Nó cho phép bạn triển khai Quality of Service (QoS) bằng cách định hình (shaping) và ưu tiên lưu lượng truy cập. Bằng cách chuyển đổi từ cơ chế chuyển phát “nỗ lực tối đa” (best-effort), bạn đảm bảo các dịch vụ ưu tiên cao vẫn hoạt động mượt mà ngay cả khi đường truyền mạng đang ở mức sử dụng 99%.

Bắt đầu nhanh: Giới hạn băng thông trong 5 phút

Không phải lúc nào bạn cũng cần một cấu trúc phân cấp phức tạp. Đôi khi bạn chỉ cần ngăn một interface cụ thể chiếm dụng hết đường truyền uplink 1Gbps dùng chung. Token Bucket Filter (TBF) là cách nhanh nhất để đạt được điều này.

Giả sử bạn muốn giới hạn eth0 ở mức 10Mbps để kiểm soát một node backup đang hoạt động quá mức. Hãy chạy các lệnh sau với quyền root:

# Xóa các quy tắc hiện có trên eth0
sudo tc qdisc del dev eth0 root 2>/dev/null

# Thêm một qdisc TBF để giới hạn tốc độ ở mức 10mbit
sudo tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms

Giải thích các tham số:

  • rate: Giới hạn tốc độ duy trì của bạn.
  • burst: Lượng dữ liệu tối đa được phép đi qua ở tốc độ phần cứng trước khi giới hạn bắt đầu có hiệu lực. Hãy coi đây là một bộ đệm nhỏ cho các mức tăng đột biến trong thời gian ngắn.
  • latency: Khoảng thời gian một gói tin có thể nằm trong hàng đợi trước khi kernel loại bỏ nó.

Để xem các quy tắc đang hoạt động, hãy sử dụng:

tc -s qdisc show dev eth0

Đi sâu vào chi tiết: Hierarchical Token Bucket (HTB)

TBF phù hợp cho các giới hạn đơn giản, nhưng QoS trong thực tế đòi hỏi HTB (Hierarchical Token Bucket). HTB tổ chức lưu lượng truy cập theo cấu trúc cây. Các dịch vụ khác nhau chia sẻ một tổng băng thông chung, nhưng bạn có thể đảm bảo tốc độ tối thiểu cho các ứng dụng quan trọng trong khi vẫn cho phép chúng “mượn” thêm dung lượng khi mạng đang rảnh.

Ba trụ cột của tc

  1. Qdisc (Queueing Discipline): Thuật toán cấp cao quản lý hàng đợi, chẳng hạn như HTB hoặc FQ_CoDel.
  2. Class: Các phân khu nơi bạn xác định các giới hạn băng thông cụ thể.
  3. Filter: Logic gán các gói tin đến vào một class cụ thể.

Xây dựng cây QoS sẵn sàng cho môi trường Production

Hãy tưởng tượng một đường truyền 100Mbps. Chúng ta muốn đảm bảo 5Mbps cho SSH, 50Mbps cho lưu lượng Web và để mọi thứ khác tranh giành 45Mbps còn lại. Nếu web server đang rảnh, các class khác sẽ có thể burst lên tới toàn bộ 100Mbps.

Đầu tiên, thiết lập root và parent class chính:

# 1. Tạo HTB root
sudo tc qdisc add dev eth0 root handle 1: htb default 30

# 2. Thiết lập tổng dung lượng (100mbit)
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

Bây giờ, hãy xác định các tầng ưu tiên của bạn:

# SSH: Tầng 1 (Class 10) - Đảm bảo 5mbit, có thể burst lên 100mbit
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit ceil 100mbit prio 1

# HTTP/HTTPS: Tầng 2 (Class 20) - Đảm bảo 50mbit
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 50mbit ceil 100mbit prio 2

# Bulk: Tầng 3 (Class 30) - Đảm bảo 10mbit
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 10mbit ceil 100mbit prio 3

Trong thiết lập này, rate là băng thông “lưới an toàn” của bạn. Tham số ceil xác định mức tối đa tuyệt đối mà một class có thể mượn từ các class anh em của nó.

Sử dụng nâng cao: Đánh dấu gói tin với iptables

Việc viết các tc filters dựa trên địa chỉ IP thô là một cơn ác mộng về bảo trì. Sẽ sạch sẽ hơn nhiều nếu sử dụng bảng mangle của iptables để “gắn thẻ” (tag) các gói tin. Điều này cho phép bạn sử dụng cú pháp iptables thân thiện—như khớp theo cổng, trạng thái hoặc thậm chí là ID tiến trình—để điều hướng lưu lượng vào các class tc của bạn.

Bước 1: Liên kết tc với các đánh dấu của iptables

Yêu cầu tc tìm kiếm các handle dạng số (marks) trên các gói tin đi ra:

sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 10 fw flowid 1:10
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 20 fw flowid 1:20

Bước 2: Gắn thẻ lưu lượng truy cập của bạn

Bây giờ, hãy đánh dấu lưu lượng SSH và Web để tc biết chúng thuộc về đâu:

# Gắn thẻ SSH (Cổng 22) là handle 10
sudo iptables -t mangle -A POSTROUTING -p tcp --dport 22 -j MARK --set-mark 10

# Gắn thẻ Web (80/443) là handle 20
sudo iptables -t mangle -A POSTROUTING -p tcp -m multiport --dports 80,443 -j MARK --set-mark 20

Sự tách biệt này rất hiệu quả. Nếu bạn chuyển web server sang một cổng không tiêu chuẩn, bạn chỉ cần cập nhật một quy tắc tường lửa thay vì phải xây dựng lại toàn bộ cấu trúc tc.

Lời khuyên thực tế từ kinh nghiệm thực chiến

1. Egress (Lưu lượng đi) là quan trọng nhất

Linux tc được thiết kế cho lưu lượng egress (đi ra). Bạn không thể dễ dàng kiểm soát những gì người khác gửi cho bạn một khi nó đã đến nơi. Nếu bạn cần giới hạn tải xuống (download), bạn thường điều chỉnh các gói tin phản hồi (ACKs). Kiểm soát những gì rời khỏi máy chủ của bạn chiếm 90% nỗ lực trong môi trường production.

2. Sự an toàn của các Class mặc định

Luôn xác định một class default trong HTB root của bạn (ví dụ: default 30). Bất kỳ gói tin nào không khớp với các bộ lọc sẽ rơi vào đây. Nếu không có mặc định, lưu lượng chưa phân loại có thể bỏ qua hoàn toàn các giới hạn của bạn, tiềm ẩn nguy cơ làm nghẽn các class ưu tiên cao.

3. Theo dõi trực tiếp

Cấu hình QoS một cách mù quáng là công thức dẫn đến thảm họa. Hãy sử dụng lệnh này để xem lưu lượng truy cập đi vào các class khác nhau trong thời gian thực:

watch -n 1 tc -s class show dev eth0

Hãy để ý đến số byte “Sent”. Nếu một class đạt đến rate của nó, bạn sẽ thấy “Tokens” giảm đi khi HTB bắt đầu trì hoãn các gói tin để duy trì giới hạn.

4. Cái bẫy Hardware Offloading

Các card mạng (NIC) hiện đại sử dụng Generic Segmentation Offload (GSO) để gộp các gói tin nhỏ thành các “siêu gói tin” khổng lồ trước khi chúng đến driver. Điều này có thể làm sai lệch tính toán của tc. Nếu việc giới hạn tốc độ của bạn có vẻ thất thường, hãy thử tắt offloading để xem hành vi có ổn định lại không:

sudo ethtool -K eth0 gso off tso off

5. Duy trì cấu hình sau khi khởi động

Các thiết lập được áp dụng qua tciptables sẽ biến mất sau khi khởi động lại. Đối với một hệ thống production tin cậy, hãy gói các lệnh này vào một shell script. Bạn có thể kích hoạt script này thông qua một systemd service hoặc sử dụng iptables-persistent. Giữ logic của bạn trong một script giúp các thành viên khác trong nhóm dễ dàng kiểm tra và sửa đổi hơn.

Làm chủ tc cung cấp cho bạn quyền kiểm soát chính xác cách mạng của bạn hoạt động dưới áp lực. Đó là sự khác biệt giữa một máy chủ bị sập khi lưu lượng tăng đột biến và một máy chủ vẫn phản hồi hoàn hảo cho người dùng.

Share: