Làm chủ lsof: Tìm chính xác tiến trình đang sử dụng tệp và cổng của bạn

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Nỗi ám ảnh mang tên “Device or Resource Busy”

Tất cả chúng ta đều đã từng gặp tình huống này. Bạn cố gắng unmount một ổ đĩa, xóa một tệp log khổng lồ hoặc khởi động lại Nginx, nhưng chỉ nhận được thông báo lỗi “Device or resource busy” hoặc “Address already in use”. Linux nổi tiếng với việc coi mọi thứ đều là tệp — từ ổ cứng cho đến các socket mạng. Nhưng khi một thứ gì đó bị khóa, hệ điều hành không phải lúc nào cũng cho bạn biết tiến trình nào là thủ phạm. Đó là lúc lsof (List Open Files) xuất hiện.

Trên một máy chủ Ubuntu 22.04 production đang chạy 12 microservices, tôi đã sử dụng lsof để giải quyết tình trạng treo khi triển khai (deployment) lặp đi lặp lại. Nó đã cắt giảm thời gian khắc phục sự cố từ 20 phút đoán mò xuống còn 30 giây chính xác. Thay vì tắt các tiến trình một cách mù quáng, chúng tôi có thể thấy chính xác script Python nào đang giữ socket. Đây là công cụ “ai đang làm gì” tối thượng cho bất kỳ quản trị viên hệ thống (sysadmin) nào.

Khởi đầu nhanh: Các lệnh lsof cơ bản trong 5 phút

Nếu bạn cần khắc phục sự cố ngay lập tức, đây là những lệnh bạn sẽ sử dụng trong 90% trường hợp. Hãy nhớ sử dụng sudo, nếu không bạn sẽ không thấy các tiến trình thuộc sở hữu của người dùng khác.

1. Tìm tiến trình đang sử dụng một cổng cụ thể

Đây là cứu cánh khi máy chủ web không khởi động được. Nếu cổng 80 đã bị chiếm dụng, hãy chạy lệnh này để tìm “kẻ chiếm đóng”:

sudo lsof -i :80

2. Liệt kê các tệp được mở bởi một người dùng cụ thể

Để xem mọi tệp mà người dùng ‘www-data’ hiện đang tác động:

sudo lsof -u www-data

3. Xem một tiến trình cụ thể đang làm gì

Nếu bạn có Process ID (PID) như 1234 và muốn xem hoạt động của nó:

sudo lsof -p 1234

4. Kiểm tra một thư mục cụ thể

Bạn đang cố unmount /mnt/data? Lệnh này sẽ cho bạn thấy ai đang chặn lối ra:

sudo lsof +D /mnt/data

Giải mã kết quả đầu ra của lsof

Chạy lsof mà không có đối số sẽ tạo ra một “bức tường” văn bản. Để tìm cây kim trong đống cỏ khô, bạn cần biết ý nghĩa của các cột này:

  • COMMAND: Tên ứng dụng hoặc script.
  • PID: ID duy nhất của tiến trình.
  • USER: Người sở hữu tiến trình.
  • FD: File Descriptor (Mô tả tệp). Hãy tìm cwd (thư mục hiện tại) hoặc txt (mã thực tế đang được chạy).
  • TYPE: REG là tệp thông thường, DIR là thư mục và IPv4/IPv6 là các kết nối mạng.
  • NAME: Đường dẫn đến tệp hoặc địa chỉ IP liên quan.

Khi lần đầu tiên kiểm tra lệnh này trên một máy chủ cơ sở dữ liệu đang bận rộn, tôi đã thấy hàng nghìn mục mem. Đừng hoảng loạn. Đây chỉ là các thư viện chia sẻ (shared libraries) được ánh xạ vào bộ nhớ. Một ứng dụng hiển thị hàng tá mục này là chuyện bình thường.

Xử lý sự cố nâng cao: Mạng và dung lượng đĩa

Khi đã nắm vững các kiến thức cơ bản, bạn có thể sử dụng lsof cho các tác vụ phức tạp hơn như phân tích pháp chứng (forensic analysis) hoặc dọn dẹp các tệp “ma”.

Lọc các kết nối mạng

Bạn có thể lọc theo giao thức để tìm các loại lưu lượng cụ thể. Điều này rất hữu ích để phát hiện các kết nối trái phép hoặc gỡ lỗi các tác vụ đồng bộ hóa bị treo.

# Liệt kê các kết nối TCP
sudo lsof -i tcp

# Tìm các kết nối tới một máy chủ từ xa cụ thể
sudo lsof -i @192.168.1.50

Thu hồi dung lượng đĩa “ma”

Bạn đã bao giờ xóa một tệp log 50GB bằng lệnh rm, nhưng df -h vẫn báo đĩa đầy? Điều này xảy ra vì một tiến trình vẫn đang mở tệp đó. Tệp đã bị “xóa” nhưng dung lượng không được giải phóng cho đến khi tiến trình đó buông tay.

Tìm những kẻ chiếm dụng dung lượng ẩn này bằng:

sudo lsof +L1

Cờ +L1 tìm các tệp có số lượng liên kết (link count) bằng không. Khi bạn tìm thấy PID, hãy khởi động lại dịch vụ đó để cuối cùng lấy lại dung lượng đĩa của mình.

Kết hợp các bộ lọc với -a

Theo mặc định, lsof sử dụng logic “HOẶC” (OR). Nếu bạn muốn tìm các tệp được mở bởi người dùng ‘john’ VÀ cụ thể trên cổng 22, bạn phải sử dụng cờ -a (AND):

sudo lsof -a -u john -i :22

Mẹo thực tế cho quản trị viên hiện đại

1. Tăng tốc độ hiển thị kết quả

Theo mặc định, lsof cố gắng chuyển đổi địa chỉ IP thành hostname. Việc này rất chậm. Trên một mạng bận rộn, lệnh có thể bị treo trong vài giây. Sử dụng -n để bỏ qua DNS và -P để bỏ qua tên cổng:

sudo lsof -nP -i :443

2. Scripting và Tự động hóa

Nếu bạn cần tắt bất cứ thứ gì đang chặn một cổng trong quy trình CI/CD, hãy sử dụng cờ -t (ngắn gọn). Nó chỉ trả về PID, rất hoàn hảo để chuyển hướng (pipe) vào các lệnh khác.

# Buộc dừng bất kỳ thứ gì đang sử dụng cổng 3000
sudo kill -9 $(lsof -t -i :3000)

Hãy sử dụng lệnh này một cách thận trọng. Đó là một cách tiếp cận khá “mạnh tay”, nhưng đôi khi đó là cách duy nhất để giải quyết một đợt triển khai bị kẹt.

3. Theo dõi thời gian thực

Bạn có thể theo dõi một tệp hoặc cổng trong thời gian thực bằng cờ -r. Điều này rất tuyệt vời để xem một tệp log đang tăng kích thước hoặc chờ đợi một kết nối cụ thể xuất hiện.

# Kiểm tra mỗi 2 giây để tìm các kết nối mới trên cổng 80
sudo lsof -i :80 -r 2

Tổng kết

Học cách sử dụng lsof sẽ thay đổi cách bạn quản lý Linux. Thay vì khởi động lại và hy vọng mọi thứ ổn thỏa, bạn có thể xác định chính xác tiến trình gây ra xung đột. Cho dù bạn đang săn lùng một tệp log “ma” 100GB hay tìm hiểu lý do tại sao một cổng phát triển bị chiếm dụng, lsof đều cung cấp sự rõ ràng mà bạn cần. Hãy giữ những lệnh này bên mình và bạn sẽ không bao giờ bị khuất phục bởi lỗi “Resource busy” nữa.

Share: