Cách khắc phục lỗi 'Too Many Open Files' trên Linux

intermediate🐧 Linux2026-03-30| Linux (Ubuntu, Debian, CentOS, RHEL), áp dụng cho các ứng dụng Nginx, Apache, MySQL, Java và Node.js.

Error Message

Too many open files
#linux-admin#ulimit#devops#performance

Lỗi

Lỗi này thường xảy ra khi lưu lượng truy cập tăng đột biến: máy chủ Nginx của bạn ngừng chấp nhận kết nối, hoặc một microservice Java đột ngột bị treo. Nhật ký (logs) sẽ hiển thị một thông báo ngắn gọn: Too many open files. Điều này xảy ra vì tiến trình đã cố gắng mở nhiều tài nguyên hơn mức hệ điều hành cho phép. Linux coi hầu hết mọi tài nguyên I/O—bao gồm socket mạng, kết nối cơ sở dữ liệu và đường ống (pipes)—là một tệp tin. Mỗi tài nguyên này tiêu thụ một "File Descriptor" (FD).

Too many open files

Tại sao lỗi này xảy ra

Linux áp đặt các giới hạn an toàn để ngăn một tiến trình bị lỗi ngốn hết bộ nhớ hệ thống. Theo mặc định, nhiều bản phân phối thiết lập giới hạn chỉ 1.024 tệp cho mỗi tiến trình. Con số này là quá thấp đối với một máy chủ web hoặc cơ sở dữ liệu hiện đại. Có hai lớp giới hạn này:

  • Soft Limit (Giới hạn mềm): Đây là giới hạn hiện tại được kernel thực thi. Một tiến trình có thể tự tăng giới hạn mềm của nó lên đến giá trị của giới hạn cứng.
  • Hard Limit (Giới hạn cứng): Đóng vai trò như một mức trần vật lý. Chỉ người dùng có quyền root mới có thể tăng giới hạn cứng.

Bước 1: Kiểm tra các giới hạn hiện tại

Bắt đầu bằng cách xác định những gì hệ thống của bạn hiện đang cho phép. Chạy các lệnh này với tư cách là người dùng cụ thể đang chạy ứng dụng của bạn (ví dụ: www-data hoặc mysql):

# Xem giới hạn mềm
ulimit -Sn

# Xem giới hạn cứng
ulimit -Hn

Để xem số lượng tệp tối đa mà toàn bộ hệ điều hành có thể xử lý trên tất cả các tiến trình, hãy chạy:

cat /proc/sys/fs/file-max

Bước 2: Tăng giới hạn cho người dùng (Vĩnh viễn)

Nếu bạn chạy ứng dụng thủ công hoặc qua cron, bạn cần chỉnh sửa tệp /etc/security/limits.conf. Thay đổi này là vĩnh viễn và vẫn được duy trì sau khi khởi động lại hệ thống.

sudo nano /etc/security/limits.conf

Thêm các dòng sau vào cuối tệp. Chúng tôi khuyên dùng giá trị 65535 cho hầu hết các môi trường production. Thay thế * bằng tên người dùng cụ thể nếu bạn muốn giới hạn thay đổi này:

*    soft    nofile    65535
*    hard    nofile    65535

Quan trọng: Bạn phải đăng xuất và đăng nhập lại để các thay đổi này có hiệu lực cho phiên làm việc của người dùng.

Bước 3: Khắc phục cho các dịch vụ Systemd

Các tệp cấu hình tiêu chuẩn như limits.conf thường không áp dụng cho các dịch vụ được quản lý bởi systemd (như Nginx, MySQL hoặc các ứng dụng Node.js). Đối với những trường hợp này, bạn phải chỉ định giới hạn trong cấu hình riêng của dịch vụ.

Tạo một tệp ghi đè (override) cho dịch vụ cụ thể của bạn:

sudo systemctl edit myservice.service

Trong trình soạn thảo, hãy chèn các dòng sau:

[Service]
LimitNOFILE=65535

Lưu tệp và thoát. Bây giờ, yêu cầu systemd tải lại cấu hình và khởi động lại ứng dụng của bạn:

sudo systemctl daemon-reload
sudo systemctl restart myservice.service

Bước 4: Tăng giới hạn trên toàn hệ thống

Các máy chủ có độ tải cao xử lý hàng triệu yêu cầu có thể chạm tới giới hạn toàn cục của kernel. Nếu giá trị /proc/sys/fs/file-max thấp, bạn có thể tăng nó bằng cách chỉnh sửa /etc/sysctl.conf:

sudo nano /etc/sysctl.conf

Thêm hoặc cập nhật tham số sau để cho phép mở 2 triệu tệp:

fs.file-max = 2097152

Áp dụng các cài đặt kernel mới ngay lập tức mà không cần khởi động lại:

sudo sysctl -p

Cách xác minh kết quả

Đừng bao giờ mặc định rằng thay đổi cấu hình đã hoạt động mà không kiểm tra tiến trình đang chạy. Tìm Process ID (PID) của ứng dụng và kiểm tra các giới hạn thực tế khi thực thi của nó:

# Tìm PID (ví dụ: cho Nginx)
pgrep nginx

# Kiểm tra giới hạn cho PID cụ thể đó
cat /proc/<PID>/limits | grep "Max open files"

Kết quả đầu ra bây giờ sẽ phản ánh giới hạn mới của bạn (ví dụ: 65535).

Mẹo xử lý sự cố

Xác định rò rỉ File Descriptor

Nếu lỗi quay trở lại sau vài ngày mặc dù đã đặt giới hạn cao, mã nguồn của bạn có khả năng bị rò rỉ (leak). Điều này xảy ra khi một ứng dụng mở các kết nối cơ sở dữ liệu hoặc tệp tin nhưng quên đóng chúng. Sử dụng lsof để điều tra xem tiến trình đang giữ những gì:

# Đếm chính xác số lượng tệp mà một PID đang mở hiện tại
sudo lsof -p <PID> | wc -l

# Xem các tệp hoặc socket cụ thể đang được giữ
sudo lsof -p <PID>

Yêu cầu về PAM

Nếu các thay đổi trong limits.conf không hoạt động, hãy đảm bảo hệ thống của bạn thực sự đang tải mô-đun giới hạn. Kiểm tra /etc/pam.d/common-session và xác minh dòng này không bị vô hiệu hóa (commented out):

session required pam_limits.so

Related Error Notes