2 giờ sáng và cơn ác mộng mang tên “Slow Request”
Điện thoại rung bần bật. Tin nhắn từ hệ thống giám sát hiện vỏn vẹn: “Latency tăng vọt, 504 Gateway Timeout trên diện rộng”. Mình bật dậy, SSH vào server trong trạng thái mắt nhắm mắt mở. CPU vẫn thấp, RAM còn thừa cả tá, log Nginx và Application thì sạch bóng. Mọi thứ trông có vẻ ổn, nhưng thực tế hệ thống đang lết đi từng chút một.
Ngày đầu làm sysadmin, mình thường tốn cả buổi chiều chỉ để khởi động lại service hay tăng RAM trong vô vọng. Nhưng đêm đó thì khác. Mình cần nhìn xuyên qua lớp vỏ của hệ điều hành, đi sâu vào nhân (kernel) – nơi mà log ứng dụng thường bỏ qua. Đó là lúc eBPF và bộ công cụ BCC Tools chứng minh giá trị thực tế của chúng.
Trong bài này, mình sẽ hướng dẫn bạn cách dùng eBPF để “soi” từng thao tác nhỏ nhất của hệ thống mà không cần sửa một dòng code app nào.
Quick Start: Cài đặt và dùng ngay sau 3 phút
Đừng để cái tên eBPF làm bạn bối rối. Sử dụng nó qua bộ công cụ BCC (BPF Compiler Collection) thực tế rất đơn giản. Trên Ubuntu hoặc Debian, bạn chỉ cần chạy:
# Cài đặt BCC tools và header của kernel hiện tại
sudo apt update
sudo apt install bpfcc-tools linux-headers-$(uname -r)
Cài xong, các công cụ sẽ nằm trong /usr/sbin với hậu tố -bpfcc. Hãy thử ngay lệnh execsnoop để xem các tiến trình đang thực thi theo thời gian thực:
sudo execsnoop-bpfcc
Mọi process vừa khởi tạo sẽ hiện ra ngay lập tức. Đây là cách nhanh nhất để tóm cổ những cronjob chạy sai giờ hoặc các script lạ đang “đâm lén” hệ thống từ bên trong.
eBPF thực chất là gì?
Về bản chất, eBPF giống như một engine JavaScript (kiểu V8) nhưng chạy ngay trong Linux Kernel. Nó cho phép bạn thực thi các chương trình giám sát siêu nhỏ ngay khi có sự kiện (events) xảy ra trong nhân hệ điều hành. Nhờ bộ kiểm tra an toàn (verifier) cực kỳ khắt khe, script của bạn sẽ bị chặn đứng nếu có nguy cơ làm treo máy.
Trước đây, nếu muốn debug sâu, bạn phải cài Kernel Module (rất dễ gây Kernel Panic) hoặc dùng ptrace (làm chậm ứng dụng tới 10 lần). eBPF giải quyết được cả hai: vừa an toàn, vừa có hiệu năng gần như không gây trễ.
Sức mạnh của BCC
Viết code eBPF thuần bằng C là một cực hình. BCC xuất hiện để chúng ta viết logic bằng Python hoặc Lua đơn giản hơn. Phần xử lý nặng nề bên dưới sẽ được BCC biên dịch sang bytecode eBPF một cách tự động. Hầu hết các lỗi hệ thống phổ biến đều đã có sẵn tool trong bộ BCC, bạn chỉ việc gọi tên và dùng.
Thực chiến: Truy tìm thủ phạm gây lag
Trở lại câu chuyện lúc 2 giờ sáng. Khi execsnoop không báo gì lạ, mình chuyển hướng nghi ngờ sang Disk I/O. Có thể một process nào đó đang chiếm dụng băng thông đĩa, khiến các yêu cầu khác phải xếp hàng chờ đợi.
Bước 1: Kiểm tra độ trễ đĩa với biolatency
sudo biolatency-bpfcc 1 10
Lệnh này thống kê độ trễ I/O dưới dạng biểu đồ histogram. Nếu các cột nằm ở vùng micro giây (usecs) thì hệ thống vẫn ổn. Nhưng nếu bạn thấy biểu đồ nhảy vọt lên hàng mili giây (msecs) hoặc hàng giây, chắc chắn ổ cứng đang có vấn đề hoặc bị quá tải.
Bước 2: Tìm xem file nào đang bị mở quá nhiều
Nếu thấy I/O chậm, hãy dùng opensnoop để xem ứng dụng đang tương tác với những file nào:
sudo opensnoop-bpfcc
Mình từng phát hiện một app Java bị lỗi loop vô hạn, liên tục mở/đóng một file config 2.000 lần mỗi giây. Log ứng dụng hoàn toàn im lặng, nhưng opensnoop đã chỉ mặt đặt tên thủ phạm ngay lập tức.
Bước 3: Debug mạng với tcptracer
Khi nghi ngờ lỗi kết nối microservices hoặc database, tcptracer sẽ giúp bạn theo dõi mọi kết nối TCP:
sudo tcptracer-bpfcc
Công cụ này liệt kê rõ Source IP, Destination IP và Port ngay khi kết nối được thiết lập. Nó cực kỳ hữu ích để xác định nhanh liệu Firewall có đang chặn nhầm kết nối hay không.
Nâng cao: Tự viết script giám sát
Đôi khi các tool có sẵn là chưa đủ. Giả sử bạn muốn nhận cảnh báo mỗi khi có ai đó thực thi rm -rf trong thư mục /var/www. Với BCC và Python, việc này chỉ tốn vài dòng code.
Cấu trúc cơ bản của một script BCC sẽ như thế này:
from bcc import BPF
# Code C chạy trực tiếp trong Kernel
program = """
int kprobe__do_sys_open(struct pt_regs *ctx, int dfd, const char __user *filename) {
// Logic kiểm tra và ghi log ở đây
return 0;
}
"""
# Nạp vào Kernel và chạy
b = BPF(text=program)
print("Đang theo dõi... Nhấn Ctrl+C để dừng.")
b.trace_print()
Bạn có thể can thiệp vào gần như bất kỳ hàm nào của kernel (kprobes) hoặc user space (uprobes). Khả năng tùy biến ở đây là cực lớn.
Mẹo nhỏ khi dùng eBPF trong thực tế
- Kernel Version: eBPF cần tối thiểu kernel 4.1. Tuy nhiên, để dùng ổn định và đầy đủ tính năng nhất, bạn nên ưu tiên kernel 4.15 trở lên (Ubuntu 18.04 trở đi là đạt chuẩn).
- Overhead: Dù rất nhanh, nhưng nếu bạn đặt probe vào các hàm bị gọi hàng triệu lần mỗi giây (như xử lý từng packet mạng), server vẫn có thể bị quá tải. Hãy cân nhắc kỹ vị trí đặt “trạm quan sát”.
- Quyền hạn: Hầu hết các tool yêu cầu quyền root hoặc
CAP_SYS_ADMINvì chúng can thiệp trực tiếp vào nhân hệ thống. - Tận dụng tài liệu: Trong thư mục
/usr/share/bcc/tools/doc/có sẵn các file text ví dụ cho từng công cụ. Hãy đọc qua chúng trước khi bắt đầu một ca debug khó.
Nắm vững eBPF không chỉ giúp bạn giải quyết các sự cố “không dấu vết” mà còn giúp bạn hiểu sâu hơn về cách Linux vận hành. Nếu các lệnh truyền thống như top hay iostat đã bó tay, đừng ngần ngại gọi tên eBPF. Chúc bạn có những đêm trực yên bình và không còn nỗi lo lỗi ẩn!

