วันพฤหัสบดีที่ 9 สิงหาคม พ.ศ. 2550

Setting up apache2-mpm-worker, mod-fcgid, php5-cgi on Debian Etch

เคยเจอปัญหาเว็บเซิร์ฟเวอร์เมื่อมีคนเข้าใช้เยอะๆ แล้วช้าลงมากๆ ไหม ทั้งๆ ที่ซีพียูก็แรง แรมก็มีไม่น้อย ปัญหามักจะเกิดขึ้นเมื่อเว็บเซิร์ฟเวอร์นั้นมี 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/

    AllowOverride None
    Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
    Order allow,deny
    Allow from all

    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 แทนละ แต่โดยรวมยังถือว่ารับมือไหว

9 ความคิดเห็น :

  1. ตอนนี้ผมมีปัญหานี้อยู่พอดี แต่ที่ใช้งานนี้อยู่บน RS6000 นะครับ
    ผู้ใข้งาน ไม่เกิน 200 คน
    เดี๋ยวลองดูก่อน

    ขอบคุณสำหรับวิธีการดี ๆ ครับ

    ตอบลบ
  2. ขอบคุณมากครับ กำลังมีปัญหาเรื่องนี้อยู่พอดี

    ตอบลบ
  3. สำหรับระบบอื่นๆ คงใช้หลักการเดียวกันแหละครับ พอดีผมอ้างอิงระบบที่ผมใช้คือ Debian เลยไม่ได้อธิบายยาวนัก



    ตอนนี้ผมใช้บนเซิร์ฟเวอร์ 2 ตัวละ ใช้ได้ดีทีเดียว



    อ่อ มีปัญหาเรื่องหนึ่งคือ เนื่องจากไม่ใช่ mod_php ทำให้ไม่สามารถใช้ directive php_value php_flag หรือ php_admin_flag ใน config ของ apache หรือใน .htaccess ได้ ซึ่งถ้ามีปรากฎอยู่ จะทำให้รัน apache ไม่ได้ หรือ ถ้าอยู่ใน .htaccess จะทำให้เปิดเว็บภายใต้ directory นั้นไม่ได้ ก็ต้องเอาออก แล้วเอาไปใส่ใน php.ini แทนครับ

    ตอบลบ
  4. Anonymous26/9/50 23:22

    แล้วถ้าเป็น freeBSD 6.2 ละครับจะต้องทำอย่างไรบ้างครับ

    อยากจะขอคำแนะนำครับ

    เพราะหัวหน้าสั้งทำ web+steaming VDO + ระบบสืบค้นหนังสือด้วยนะครับ (ทำเสร็จแล้ว อยู่คนละเครื่อง)

    ตอนนี้กำลังลงเครื่องที่จะเป็น web อยู่ กำลังติดตั้ง freeBSD+apache+mysql+php+phpmyadmin ครับ



    ขอคำแนะนำบน freeBSD ด้วยนะครับ

    ตอบลบ
  5. เอก6/3/51 04:12

    ผมลองแล้ว เอาไปใช้ใน ubuntu gutsy ช่วยได้เยอะเลยครับ

    แต่ตอนนี้กลับมีปัญหาแปลกๆมาแทน อย่างเช่น ช่วงเวลาหนึ่ง (ประมาณ 1-2 วัน) ตัว php5-cgi อยู่ๆก็โหลดขึ้นมาเพียบเลย (จากที่มี process อยู่แค่ไม่กี่ตัว) ทำให้ใช้ Memory เยอะมาก จนไปใช้ในส่วน Swap Memory สุดท้าย เครื่องก็ช้าลงจนใช้การไม่ได้ ถ้าเครื่องยังไม่ช้าเกินไป ผมยังเข้าไป Killall ได้ แต่ถ้ามันช้าจนรับไม่ได้ ผมก็ต้อง hard reboot ไปเลย ที่แปลกก็คือ พอboot กลับเข้ามาแล้ว อาการก็เกิดขึ้นอีก ต้อง reboot อยู่หลายครั้ง อาการก็หายไปเอง



    ผมสงสัยว่า มีวิธีการสร้าง process ให้ php5-cgi หรือเปล่าครับ (สร้างใน /etc/init.d จะสั่ง start/stop ได้) เพราะถ้าทำได้ ผมก็ยังใช้โปรแกรมอื่นตรวจว่ามันวิ่งมากไปไหม ถ้าใช่ก็ให้ kill ทิ้งได้เลย ไม่งั้น ผมก็ต้องมานั่งตามเช็คตลอด



    หรือถ้ามีวิธีแก้เลย ก็จะดีมากครับ



    ขอบคุณมากครับ

    ตอบลบ
  6. ผมว่าผมลืมบอกไปสองคำสั่งนะนี่

    <code># apt-get install libapache2-mod-fcgid

    # a2enmod fcgid</code>



    เดี๋ยวอัพเดทบล็อกก่อน

    ตอบลบ
  7. มีปัญหาว่า หลังจากเปลี่ยนมาใช้ fcgid แทน mod_php แล้ว upload ไฟล์ขนาด มากกว่า 2M ไม่ได้ครับ

    ตอบลบ
  8. น่าจะเป็นเพราะเดิมตอนใช้ mod_php นั้น มันจะอ่าน config จาก /etc/php5/apache2/php.ini แต่เมื่อเปลี่ยนเป็น fcgid แล้ว มันจะรัน php ด้วย php-cgi ซึ่งจะอ่าน config จาก /etc/php5/cgi/php.ini แทน



    วิธีแก้ ให้คัดลอก php.ini เดิมจาก /etc/php5/apache2/ ไปใส่ไว้ที่ /etc/php5/cgi/ แล้วรีสตาร์ต apache2 ใหม่ ก็น่าจะใช้ได้แล้วครับ

    ตอบลบ
  9. ตอนนี้ใช้อย่างนี้แหล่ะครับ host เว็บกว่าร้อยโดเมน เริ่มมีปัญหา internal server error (500)



    กำลังจะลองทดสอบ apache2 itk mpm อยู่ครับ

    ตอบลบ