ลดความยุ่งยากในการใช้คลาวด์ พูดคุยกับเจ้าหน้าที่

ปรับค่าเคอร์เนลด้วย sysctl ให้เซิร์ฟเวอร์รับโหลดสูงได้
Home ปรับค่าเคอร์เนลด้วย sysctl ให้เซิร์ฟเวอร์รับโหลดสูงได้

ปรับค่าเคอร์เนลด้วย sysctl ให้เซิร์ฟเวอร์รับโหลดสูงได้

ค่าเริ่มต้นของเคอร์เนล Linux ถูกตั้งมาให้ปลอดภัยกับเครื่องทุกขนาด ตั้งแต่อุปกรณ์ฝังตัวไปจนถึงเซิร์ฟเวอร์ใหญ่ เมื่อเซิร์ฟเวอร์ของคุณเริ่มรับการเชื่อมต่อพร้อมกันหลักพัน ค่าบางตัวจะกลายเป็นเพดานที่มองไม่เห็น อาการที่เห็นคือ connection refused หรือเว็บหน่วงเป็นช่วง ทั้งที่ CPU และ RAM ยังเหลือ

คู่มือนี้อธิบายค่าที่ควรปรับจริงสำหรับเว็บเซิร์ฟเวอร์ พร้อมเหตุผลของแต่ละตัว และที่สำคัญคือบอกด้วยว่าค่าไหน "ไม่ควรแตะ" แม้จะเห็นแนะนำกันมากในอินเทอร์เน็ต

สิ่งที่ต้องเตรียม

  • Linux Server และสิทธิ์ sudo
  • รู้ปริมาณการใช้งานจริงคร่าว ๆ เช่น จำนวนการเชื่อมต่อพร้อมกันสูงสุด ดูได้จาก ss -s

หลักสำคัญ อย่าคัดลอกชุดค่าจากอินเทอร์เน็ตมาใส่ทั้งก้อน ปรับทีละกลุ่มแล้ววัดผล ค่าที่เหมาะกับเครื่อง 64 GB ไม่เหมาะกับเครื่อง 2 GB

ขั้นตอนที่ 1: ดูค่าปัจจุบันก่อน

sysctl net.core.somaxconn
sysctl net.ipv4.ip_local_port_range
sysctl fs.file-max
sysctl vm.swappiness

# ดูทั้งหมด
sudo sysctl -a | less

จดค่าเดิมไว้ก่อนแก้เสมอ วิธีที่ง่ายที่สุดคือบันทึกลงไฟล์

sudo sysctl -a > /root/sysctl-before-$(date +%F).txt

ขั้นตอนที่ 2: สร้างไฟล์ตั้งค่าของเราเอง

อย่าแก้ /etc/sysctl.conf ตรง ๆ เพราะการอัปเดตระบบอาจเขียนทับ ให้สร้างไฟล์แยกใน /etc/sysctl.d/ ซึ่งโหลดตามลำดับตัวเลขนำหน้า

sudo nano /etc/sysctl.d/99-tdc-tuning.conf

ขั้นตอนที่ 3: ค่าเกี่ยวกับการรับการเชื่อมต่อ

# คิวของการเชื่อมต่อที่รอให้แอปรับ (Nginx, MySQL)
net.core.somaxconn = 4096

# คิวของการเชื่อมต่อที่ยังจับมือ TCP ไม่เสร็จ
net.ipv4.tcp_max_syn_backlog = 8192

# คิวแพ็กเก็ตขาเข้าที่รอเคอร์เนลประมวลผล
net.core.netdev_max_backlog = 5000

somaxconn คือค่าที่สำคัญที่สุดในกลุ่มนี้ ค่าเริ่มต้นเดิมคือ 128 ซึ่งต่ำมากสำหรับเว็บที่มีคนเข้าพร้อมกัน เมื่อคิวเต็ม การเชื่อมต่อใหม่จะถูกปฏิเสธทันที ผู้ใช้เห็นเป็นหน้าเว็บโหลดไม่ขึ้นเป็นช่วง

สำคัญ การเพิ่มค่านี้อย่างเดียวไม่พอ ต้องบอกแอปให้ใช้ค่าที่สูงขึ้นด้วย ใน Nginx ตั้งที่บรรทัด listen

listen 443 ssl backlog=4096;

ขั้นตอนที่ 4: ค่าเกี่ยวกับพอร์ตและการเชื่อมต่อที่ปิดแล้ว

# ช่วงพอร์ตที่ใช้เป็นต้นทางของการเชื่อมต่อขาออก
net.ipv4.ip_local_port_range = 10240 65535

# นำพอร์ตในสถานะ TIME_WAIT กลับมาใช้ใหม่ได้เร็วขึ้น
net.ipv4.tcp_tw_reuse = 1

# ลดเวลารอปิดการเชื่อมต่อฝั่งที่ค้าง
net.ipv4.tcp_fin_timeout = 15

ค่าเหล่านี้มีผลเมื่อเซิร์ฟเวอร์ของคุณเป็นฝั่งที่ เปิด การเชื่อมต่อออกไปเยอะ เช่น Reverse Proxy ที่ยิงต่อไปยัง Backend หรือแอปที่เรียก API ภายนอกถี่ ๆ อาการเมื่อพอร์ตหมดคือ cannot assign requested address

ตรวจจำนวน TIME_WAIT ปัจจุบันได้ด้วย

ss -tan state time-wait | wc -l

อย่าเปิด net.ipv4.tcp_tw_recycle ค่านี้สร้างปัญหากับผู้ใช้ที่อยู่หลัง NAT เดียวกันและถูกถอดออกจากเคอร์เนลรุ่นใหม่แล้ว คำแนะนำเก่า ๆ ในอินเทอร์เน็ตยังมีอยู่มาก

ขั้นตอนที่ 5: ค่าเกี่ยวกับจำนวนไฟล์ที่เปิดได้

# เพดานทั้งระบบ
fs.file-max = 2097152

# จำนวน inotify watch (สำคัญกับ Docker และตัวเฝ้าไฟล์)
fs.inotify.max_user_watches = 524288

ค่า fs.file-max เป็นเพดานรวมของทั้งเครื่อง แต่ยังมีเพดานรายโปรเซสที่ควบคุมด้วย ulimit และ systemd อีกชั้น ต้องตั้งทั้งสองที่จึงจะได้ผล ดูวิธีตั้งฝั่ง systemd ได้ในคู่มือเรื่อง Too many open files

ขั้นตอนที่ 6: ค่าเกี่ยวกับหน่วยความจำ

# ลดความอยากใช้ Swap ลง แต่ไม่ปิดทั้งหมด
vm.swappiness = 10

# เริ่มเขียนข้อมูลค้างลงดิสก์เร็วขึ้น ลดอาการค้างเป็นก้อน
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5

# จำเป็นสำหรับ Redis และ MongoDB
vm.overcommit_memory = 1

vm.swappiness = 10 ไม่ได้แปลว่าใช้ Swap แค่ 10% แต่คือ "ความเต็มใจ" ของเคอร์เนลที่จะย้ายหน่วยความจำไปดิสก์ ค่าต่ำเหมาะกับเซิร์ฟเวอร์ที่ต้องการความหน่วงคงที่ ส่วนการตั้งเป็น 0 ไม่แนะนำ เพราะทำให้ระบบฆ่าโปรเซสทิ้งเร็วเกินไปเมื่อหน่วยความจำตึง

ขั้นตอนที่ 7: ค่าด้านความปลอดภัยพื้นฐาน

# ไม่ส่งต่อแพ็กเก็ต หากเครื่องนี้ไม่ได้ทำหน้าที่เราเตอร์
net.ipv4.ip_forward = 0

# ป้องกันการปลอม IP ต้นทาง
net.ipv4.conf.all.rp_filter = 1

# ไม่รับ ICMP redirect
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# ไม่รับ source routing
net.ipv4.conf.all.accept_source_route = 0

# บันทึกแพ็กเก็ตที่มี IP ปลอม
net.ipv4.conf.all.log_martians = 1

# ป้องกัน SYN flood เบื้องต้น
net.ipv4.tcp_syncookies = 1

หมายเหตุ หากเครื่องนี้รัน Docker หรือทำ VPN ต้องปล่อย net.ipv4.ip_forward = 1 ไว้ ไม่เช่นนั้น Container จะออกอินเทอร์เน็ตไม่ได้ Docker มักตั้งค่านี้ให้เองอยู่แล้ว

ขั้นตอนที่ 8: โหลดค่าและตรวจสอบ

sudo sysctl --system
sudo sysctl -p /etc/sysctl.d/99-tdc-tuning.conf

ยืนยันว่าค่าเปลี่ยนจริง

sysctl net.core.somaxconn vm.swappiness fs.file-max

ค่าเหล่านี้มีผลทันทีโดยไม่ต้องรีบูต แต่แอปที่รันอยู่แล้วบางตัวอ่านค่าตอนเริ่มทำงานเท่านั้น ให้รีสตาร์ต Nginx, PHP-FPM และ MySQL หลังปรับ

sudo systemctl restart nginx php8.3-fpm mysql

ขั้นตอนที่ 9: วัดผลและย้อนกลับถ้าจำเป็น

วัดก่อนและหลังด้วยตัวเลขเดียวกัน อย่าเชื่อความรู้สึก

ss -s
ss -tan state time-wait | wc -l
cat /proc/sys/fs/file-nr

หากผลแย่ลงหรือระบบไม่นิ่ง ให้ย้อนกลับได้ทันทีโดยลบไฟล์ที่สร้างไว้แล้วรีบูต

sudo rm /etc/sysctl.d/99-tdc-tuning.conf
sudo reboot

ปัญหาที่พบบ่อย

ตั้ง somaxconn แล้วแต่ยังเจอ connection refused

แอปยังใช้ค่า backlog เดิมของตัวเอง ต้องแก้ที่คอนฟิกของแอปด้วย ทั้ง backlog ใน Nginx และ back_log ใน MySQL

ค่าหายหลังรีบูต

ค่าที่ตั้งด้วย sysctl -w อยู่แค่ในหน่วยความจำ ต้องเขียนลงไฟล์ใน /etc/sysctl.d/ และตรวจว่าชื่อไฟล์ลงท้ายด้วย .conf

ตั้ง vm.swappiness เป็น 0 แล้วโปรเซสถูกฆ่า

เมื่อหน่วยความจำตึงและไม่มี Swap ให้ระบาย ระบบจะเลือกฆ่าโปรเซสที่ใช้หน่วยความจำมากที่สุดแทน ใช้ค่า 10 หรือ 1 แทน 0 และเพิ่ม RAM หากเกิดบ่อย

ไม่แน่ใจว่าค่าไหนมีผลจริง

ดูว่าไฟล์ใดตั้งค่าตัวไหนไว้บ้างด้วย sudo sysctl --system ซึ่งจะพิมพ์ชื่อไฟล์ตามลำดับที่โหลด ค่าที่โหลดทีหลังชนะค่าก่อนหน้าเสมอ

ต้องการให้ทีมวิศวกรช่วยตั้งค่าให้เหมาะกับทราฟฟิกจริงของคุณ ติดต่อ THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/

ผู้ให้บริการคลาวด์ไทย
เพื่อธุรกิจของคนไทย

"มุ่งมั่น" และ "มั่นคง"
พร้อมรับมือทุกการเติบโต
Trust Cloud
คลาว์ที่ปลอดภัย
คือรากฐานที่มั่นคง
cloud security