เคยเจอปัญหาเว็บเซิร์ฟเวอร์เมื่อมีคนเข้าใช้เยอะๆ แล้วช้าลงมากๆ ไหม ทั้งๆ ที่ซีพียูก็แรง แรมก็มีไม่น้อย ปัญหามักจะเกิดขึ้นเมื่อเว็บเซิร์ฟเวอร์นั้นมี mod-php และบางครั้งมีไฟล์ static ใหญ่ๆ เช่นภาพถ่าย วิดีโอ ไฟล์พรีเซนต์ ไฟล์ดาวน์โหลดต่างๆ ให้ดาวน์โหลดผ่าน http
ปัญหามักเกิดจาก เมื่อเราใช้ mod-php ก็ต้องใช้ apache ที่ใช้ mpm-prefork ด้วย นั่นคือเมื่อมี connection เข้ามา apache ต้อง fork process เพื่อให้บริการ connection นั้นเป็นรายๆ ไป ปัญหาคือว่า mod-php ทำให้แต่ละ process มีขนาดใหญ่มาก ยิ่งเว็บแอ็พที่ใช้มีขนาดใหญ่ ยิ่งทำให้แต่ละ process ใหญ่เข้าไปอีก ปัญหาจะหนักขึ้น เมื่อต้องให้บริการดาวน์โหลดไฟล์ หรือมีรูปภาพจำนวนมากบนเว็บไซต์ด้วย เพราะแม้ว่าพวกนี้จะไม่ต้องการซีพียูในการประมวลผลมากนัก แต่การที่ apache ต้อง fork process มาเพื่อให้บริการไฟล์พวกนี้ ก็ทำให้ต้องเสีย memory มากขึ้นไปอีก ยิ่งเน็ตเวิร์คของไคลเอนต์ช้า ยิ่งทำให้ต้องใช้เวลาดาวน์โหลดนาน จะพบว่า จำนวน connection มีมากขึ้นเรื่อยๆ
ปัญหาจะถึงจุดวิกฤติเมื่อ memory หมดเกลี้ยง ลินุกซ์จะเริ่ม swap หน่วยความจำบางส่วนลงดิสก์ และเมื่อ memory ที่กำลัง active มีมากกว่า memory จริงๆ การ swap จะเกิดขึ้นแบบไม่รู้จบ ถึงตอนนี้ท่านก็จะพบว่า แม้กระทั่งการ ssh เข้ามาที่เซิร์ฟเวอร์ ก็เป็นเรื่องยาก แม้เมื่อล็อกอินที่หน้าเครื่อง ก็อาจจะทำไม่ได้ด้วยซ้ำ ทางหนึ่งที่แอดมินชอบทำก็คือ กด ctrl-alt-del เพื่อรีบูตเซิร์ฟเวอร์ หลังจากรีบูตก็จะใช้งานได้สักพัก แล้วก็จะเกิดวิกฤติอีกครั้ง ส่วนการเพิ่ม memory ก็แก้ปัญหาได้ในระยะสั้น และไม่สามารถรองรับผู้ใช้เพิ่มได้อีกมากนัก
ที่จริงแล้ว apache2 ยังมี mpm แบบอื่นๆ ที่ทำงานแบบ thread เช่น mpm-worker ซึ่งจะใช้ memory น้อยลงมาก เพราะไม่ต้อง fork process เป็นหลายๆ process เพื่อรองรับ connection แต่ว่า mpm-worker ไม่สามารถใช้กับ mod-php ได้ ทางหนึ่งที่จะทำได้คือ รัน php แบบ cgi ซึ่งไม่ใช่ทางเลือกที่ดีนัก เพราะจำเป็นต้องเริ่ม process php-cgi ใหม่ทุกครั้งที่เปิดหน้า php 1 หน้า ทางออกที่ดีที่สุดคือใช้ mod-fcgid หรือ mod-fastcgi ก็ได้ แต่ fcgid ดูจะเร็วกว่านิดหน่อย โดยหลักการจะเหมือนกันคือ php-cgi จะคอมไพล์ให้รองรับ fastcgi ไว้อยู่แล้ว คือ จะรัน script ที่ส่งเข้ามาให้จนเสร็จ แต่จะไม่ kill process แต่จะยังคงรอรับ script อื่นมาประมวลผลต่อไป ทำให้ได้ข้อดีของการทำงานแบบ mod หรือ embeded คือไม่ต้อง fork process บ่อยๆ ในขณะที่มีข้อดีแบบ cgi คือ ถ้าไม่จำเป็นต้องประมวลผล php ก็ไม่ต้องเรียกขึ้นมาใช้งาน ทำให้รับ connection ได้มากขึ้น และใช้หน่วยความจำน้อยลง และทำงานได้ไวขึ้นกว่าเดิม
ขั้นตอนบน Debian Etch มีดังนี้ โดยสมมติว่าเรามีระบบที่ให้บริการเว็บตามปกติอยู่แล้ว แต่เป็น apache2-mpm-prefork
- สร้าง directory /var/www/fcgi-bin
mkdir /var/www/fcgi-bin
- สร้างแฟ้ม /var/www/fcgi-bin/php5.fcgi ให้มีเนื้อหาดังนี้
#!/bin/sh
PHPRC="/etc/php5/cgi"
export PHPRC
PHP_FCGI_CHILDREN=4
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/bin/php5-cgi - เปลี่ยน mode ให้ execute ได้
chmod +x /var/www/fcgi-bin/php5.fcgi
- สร้างแฟ้ม /etc/apache2/conf.d/php5-fcgid ให้มีเนื้อหาดังนี้
ScriptAlias /fcgi-bin/ /var/www/fcgi-bin/
<directory "/var/www/fcgi-bin">
AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</directory>
Action application/x-httpd-php /fcgi-bin/php5.fcgi
AddHandler application/x-httpd-php .php .phtml - ลบ mod-php5 แล้วติดตั้ง php5-cgi
apt-get remove libapache2-mod-php5
apt-get install php5-cgi - ติดตั้ง libapache2-mod-fcgid และเปิดใช้งาน
apt-get install libapache2-mod-fcgid
a2enmod fcgid - ถอดถอน apache2-mpm-prefork แล้วติดตั้ง apache2-mpm-worker
apt-get remove apache2-mpm-prefork
apt-get install apache2-mpm-workerจากนั้นมันจะ start apache ตัวใหม่ให้โดยอัตโนมัติ ให้ลองทดสอบ เว็บไซต์ดูว่ายังรันได้ปกติดีหรือไม่
ถ้าใน php.ini เดิมนั้น ได้มีการปรับค่าต่างๆ ไว้ เช่น memory_limit ก็ให้ปรับในแฟ้ม /etc/php5/cgi/php.ini ตามด้วย
ทีนี้จะพบว่า จะมี process แบ่งเป็น 2 ชื่อ คือ apache2 และ php5-cgi โดย apache2 จะมีจำนวน process ไม่มากนัก และมีขนาดเล็ก ส่วน php5-cgi จะมีการ fork ไว้จำนวนหนึ่ง ซึ่งไม่ได้ทำงานตลอดเวลา คือจะทำงานเมื่อมีการเรียกแฟ้ม .php ขึ้นมาทำงานเท่านั้น ผลโดยรวมคือ ระบบเร็วขึ้นอย่างเห็นได้ชัด คราวนี้ปัญหาไปอยู่ที่ mysql server แทนละ แต่โดยรวมยังถือว่ารับมือไหว



