คำตอบสั้น ๆ: หาสาเหตุของข้อความ Too many open files แล้วตั้งเพดานให้ถูกที่ ทั้งระดับผู้ใช้ ระดับ systemd service และระดับทั้งระบบ
คู่มือนี้อธิบาย Too many open files ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
ข้อความ Too many open files ใน Log ของ Nginx, MySQL หรือแอป Node.js เป็นสัญญาณว่าโปรเซสนั้นชนเพดานจำนวนไฟล์ที่เปิดได้พร้อมกัน บน Linux ทุกอย่างนับเป็นไฟล์ รวมถึงการเชื่อมต่อเครือข่ายด้วย เว็บที่มีผู้ใช้พร้อมกันหลักพันจึงชนเพดานได้ง่ายกว่าที่คิด
ความสับสนของเรื่องนี้คือมีเพดานอยู่สามชั้นที่แยกกันคนละที่ ตั้งผิดชั้นแล้วค่าจะไม่มีผลเลย คู่มือนี้ไล่ทั้งสามชั้นตามลำดับที่ควรตรวจ
สิ่งที่ต้องเตรียม (Too many open files)
- Linux Server ที่ใช้ systemd และสิทธิ์
sudo - ชื่อบริการที่มีปัญหา เช่น
nginx,mysqlหรือชื่อ service ของแอปคุณ
ขั้นตอนที่ 1: ยืนยันว่าชนเพดานจริง (Too many open files)
ค้นหาข้อความใน Log ก่อน
sudo journalctl --since '1 day ago' | grep -i 'too many open files'
sudo grep -i 'too many open files' /var/log/nginx/error.log
ดูตัวเลขรวมทั้งระบบ ค่าสามตัวคือ จำนวนที่เปิดอยู่ จำนวนที่จัดสรรแล้วแต่ยังไม่ใช้ และเพดานรวม
cat /proc/sys/fs/file-nr
หาโปรเซสที่เปิดไฟล์มากที่สุด
sudo lsof 2>/dev/null | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
นำ PID ที่ได้ไปดูชื่อโปรเซสและเพดานจริงของมัน
ps -p 1234 -o pid,comm,user
cat /proc/1234/limits | grep 'open files'
ls /proc/1234/fd | wc -l
บรรทัดสุดท้ายคือจำนวนไฟล์ที่โปรเซสนั้นเปิดอยู่จริงในขณะนี้ เทียบกับ Soft Limit ที่เห็นในบรรทัดก่อนหน้า
ขั้นตอนที่ 2: เข้าใจเพดานสามชั้น
- ชั้นทั้งระบบ คือ
fs.file-maxเพดานรวมของทุกโปรเซสในเครื่อง ปกติสูงมากอยู่แล้วและไม่ค่อยเป็นสาเหตุ - ชั้น systemd service คือ
LimitNOFILEใช้กับบริการที่เริ่มโดย systemd ซึ่งก็คือเกือบทุกอย่างบนเซิร์ฟเวอร์ยุคนี้ นี่คือชั้นที่ถูกมองข้ามบ่อยที่สุด - ชั้นผู้ใช้ คือ
/etc/security/limits.confใช้เมื่อผู้ใช้ล็อกอินเข้ามาแล้วรันโปรแกรมเอง ไม่มีผลกับบริการที่ systemd เป็นคนเริ่ม
สาเหตุที่คนแก้ไม่หายส่วนใหญ่คือไปแก้ limits.conf ทั้งที่ปัญหาอยู่ที่ LimitNOFILE ของ systemd
ขั้นตอนที่ 3: ตั้งค่าที่ระดับ systemd service
อย่าแก้ไฟล์ service ต้นฉบับ ให้ใช้ไฟล์เสริมแทน ซึ่งจะไม่ถูกเขียนทับเมื่ออัปเดตแพ็กเกจ
sudo systemctl edit nginx
พิมพ์เนื้อหานี้ลงไปในส่วนที่ว่าง
[Service]
LimitNOFILE=65535
บันทึกแล้วโหลดใหม่
sudo systemctl daemon-reload
sudo systemctl restart nginx
ยืนยันผล
systemctl show nginx -p LimitNOFILE
cat /proc/$(pgrep -f 'nginx: master' | head -1)/limits | grep 'open files'
ทำแบบเดียวกันกับบริการอื่นได้ เช่น sudo systemctl edit mysql หรือ sudo systemctl edit php8.3-fpm
ขั้นตอนที่ 4: ตั้งค่าเฉพาะของแอปเพิ่ม
บางโปรแกรมมีเพดานของตัวเองซ้อนอีกชั้น ต้องตั้งให้สอดคล้องกัน
Nginx
sudo nano /etc/nginx/nginx.conf
worker_rlimit_nofile 65535;
events {
worker_connections 16384;
}
คำนวณคร่าว ๆ จำนวนการเชื่อมต่อสูงสุด = worker_processes คูณ worker_connections และ worker_rlimit_nofile ควรมากกว่า worker_connections อย่างน้อยสองเท่า เพราะหนึ่งคำขอที่ผ่าน Proxy ใช้ทั้งการเชื่อมต่อขาเข้าและขาออก
MySQL / MariaDB
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
open_files_limit = 65535
ตรวจค่าที่ใช้จริงหลังรีสตาร์ต
mysql -e "SHOW VARIABLES LIKE 'open_files_limit';"
PHP-FPM
sudo nano /etc/php/8.3/fpm/php-fpm.conf
rlimit_files = 65535