Rất thường lỗi 'too many open files' xảy ra trên máy chủ Linux tải cao. Nó có nghĩa là một tiến trình đã mở quá nhiều file (file descriptor) và không thể mở file mới. Trong Linux, giới hạn tối đa file mở được đặt mặc định cho mỗi tiến trình hoặc người dùng và các giá trị khá nhỏ.
Trong bài viết này, chúng ta sẽ học cách kiểm tra giới hạn hiện tại về số lượng file mở tối đa trong Linux và cách thay đổi nó cho toàn bộ máy chủ, dịch vụ riêng lẻ hoặc phiên hiện tại.
Lỗi 'Too Many Open Files' & Giới hạn file mở trong Linux
Trước hết, hãy xem lỗi 'too many open files' xuất hiện ở đâu. Thường nó xảy ra trên máy chủ với máy chủ web NGINX/httpd đã cài hoặc máy chủ cơ sở dữ liệu (MySQL/MariaDB/PostgreSQL) khi đọc số lượng lớn log. Ví dụ, khi máy chủ web Nginx vượt quá giới hạn file mở, bạn sẽ thấy lỗi:
socket () failed (29: Too many open files) while connecting to upstream

Sử dụng lệnh này, bạn có thể lấy số lượng file descriptor tối đa hệ thống của bạn có thể mở:
# cat /proc/sys/fs/file-max
Giới hạn file mở cho người dùng hiện tại là 1024. Bạn có thể kiểm tra như sau:
# ulimit -n

Có hai loại giới hạn: Hard và Soft. Người dùng có thể thay đổi giới hạn mềm (tuy nhiên, giá trị soft không thể vượt quá hard). Chỉ người dùng đặc quyền hoặc root mới có thể thay đổi giá trị giới hạn hard.
Để hiển thị giới hạn mềm, chạy lệnh:
# ulimit -nS
Để hiển thị giá trị giới hạn cứng:
# ulimit -nH
Cách tăng giới hạn Max Open File trong Linux?
Để cho phép tất cả dịch vụ mở số lượng lớn file, bạn có thể thay đổi giới hạn trong hệ điều hành Linux. Để cài đặt mới vĩnh viễn và ngăn chặn việc reset sau khi khởi động lại máy chủ hoặc phiên, bạn phải thay đổi /etc/security/limits.conf. Thêm các dòng sau:
* hard nofile 97816 * soft nofile 97816
Nếu bạn dùng Ubuntu, hãy thêm dòng này nữa:
session required pam_limits.so
Tham số này cho phép đặt giới hạn file mở sau khi xác thực người dùng.
Sau khi thay đổi, tải lại terminal và kiểm tra giá trị max_open_files:
# ulimit -n
97816
Tăng giới hạn File Descriptor mở cho từng Dịch vụ
Bạn có thể thay đổi giới hạn file descriptor mở cho một dịch vụ cụ thể, thay vì cho toàn bộ hệ điều hành. Hãy lấy apache làm ví dụ. Mở cài đặt dịch vụ bằng systemctl:
# systemctl edit httpd.service
Thêm giới hạn bạn muốn, ví dụ:
[Service] LimitNOFILE=16000 LimitNOFILESoft=16000

Sau khi thay đổi, cập nhật cấu hình dịch vụ và khởi động lại nó:
# systemctl daemon-reload
# systemctl restart httpd.service
Để chắc chắn giá trị đã thay đổi, lấy PID dịch vụ:
# systemctl status httpd.service
Ví dụ, PID dịch vụ là 3724:
# cat /proc/3724/limits | grep "Max open files"

Như vậy, bạn đã thay đổi giá trị số lượng file mở tối đa cho một dịch vụ cụ thể.
Cách đặt giới hạn Max Open Files cho Nginx & Apache?
Khi thay đổi giới hạn số lượng file mở cho máy chủ web, bạn cũng phải thay đổi file cấu hình dịch vụ. Ví dụ, chỉ định/thay đổi giá trị chỉ thị sau trong file cấu hình Nginx /etc/nginx/nginx.conf:
worker_rlimit_nofile 16000
Khi cấu hình Nginx trên máy chủ 8 nhân tải cao với worker_connections 8192, bạn cần chỉ định 8192*2*8 (vCPU) = 131072 trong worker_rlimit_nofile.
Sau đó khởi động lại Nginx.
Đối với apache, tạo thư mục:
# mkdir /lib/systemd/system/httpd.service.d/
Sau đó tạo file limit_nofile.conf:
# nano /lib/systemd/system/httpd.service.d/limit_nofile.conf

Thêm vào nó:
[Service] LimitNOFILE=16000
Đừng quên khởi động lại httpd.
Thay đổi giới hạn File mở cho Phiên hiện tại
Để thay đổi giới hạn file mở tối đa cho phiên terminal của bạn, chạy lệnh:
# ulimit -n 3000
Sau khi đóng terminal và tạo phiên mới, giới hạn sẽ quay về giá trị ban đầu được chỉ định trong /etc/security/limits.conf.
Để thay đổi giá trị chung cho hệ thống /proc/sys/fs/file-max, thay đổi giá trị fs.file-max trong /etc/sysctl.conf:
fs.file-max = 100000
Và áp dụng nó:
# sysctl -p

Trong bài viết này, chúng ta đã học cách giải quyết vấn đề khi giá trị giới hạn file descriptor mở trong Linux quá nhỏ, và thảo luận một số tùy chọn thay đổi các giới hạn này trên máy chủ.