Wall of Text #13: CGI

น้อง Intern บอกว่ากำลังหัดเขียน Web server อยู่ เลยสงสัยว่าแล้วจะทำให้ Web server รันโปรแกรมที่เป็น dynamic ได้ไง (สมมุติว่า Python)

เรื่องที่น่าแปลกใจคือคนรุ่นใหม่เหมือนจะไม่มีประสบการณ์ใช้งาน PHP กันแล้ว เข้าใจว่าบางมหาวิทยาลัยนอกเหนือจาก Top 5 อาจจะยังมีการสอนอยู่บ้าง ตอนที่โชว์ให้ดูว่า PHP มันวางไฟล์แล้วใช้ได้เลยนี่มันเลยดูเท่มาก เพราะถ้าเขียนภาษาอื่นๆ อย่างน้อยก็ต้อง restart app server

CGI

ในสมัยโบราณ WWW มีแต่หน้าเว็บ static ต่อมาเราอยากให้หน้าเว็บมีการอัพเดตบ้าง เลยมีผู้ที่ออกแบบมาตรฐาน CGI ขึ้นมาเพื่อให้ Web server สามารถเรียกโปรแกรมอื่นได้

การทำงานของ CGI ก็ง่ายมาก คือเรากำหนดว่าที่ URL นี้แทนที่จะส่งไฟล์กลับไปให้ ให้เรียกโปรแกรมที่กำหนดให้ ที่นิยมกันก็คือจะกำหนดเป็น folder /cgi-bin ไปเลย

เมื่อเราเข้า URL ที่อยู่ใน cgi-bin แล้ว Web server จะไปเรียกโปรแกรมนั้นๆ โดยส่ง Header ไปทาง Environment variable และส่ง Request body ไปเป็น input ของโปรแกรม จากนั้นโปรแกรมจะ print สิ่งที่ต้องการให้แสดงบนหน้าเว็บออกมา ถ้าต้องการเซต Header มาด้วยก็ให้ print ก่อนเนื้อหาได้

วิธีนี้ค่อนข้างนิยมในสมัยก่อน ภาษาที่ใช้เขียนก็ได้ทุกภาษาขอให้เรียกเป็นโปรแกรมได้เท่านั้น เช่น C, Perl, PHP ก็ใช้ได้ทั้งหมด

ยกตัวอย่างเช่น Pantip ในยุคแรกใช้ภาษา Perl ในการพัฒนา ในหน้ากระทู้นั้นจะเป็น HTML ธรรมดาๆ เมื่อมีการโพสต์ comment ก็จะไปเรียก Perl script เข้าไปแก้ไขไฟล์ HTML (ซึ่งปัญหาที่ตามมาคือเมื่อ concurrent มากๆ แล้ว Script อาจจะแย่งกันเขียนทำให้ไฟล์พัง)

PHP SAPI

ปัญหาของ CGI คือทุกครั้งที่มีการเรียก CGI Script จะต้องเรียก process ย่อยๆ นั้นใหม่ ซึ่งถ้าเขียนด้วย C ก็ไม่มีปัญหาเท่าไร แต่บางภาษาอาจจะ start ช้ามากๆ เช่นสมัยก่อนผมเคยใช้ Python แล้วเซตไม่ถูกเลยไปใช้ CGI ก็เสียเวลา start python ทุก request เกือบ 2 วินาที

มันก็มีคนแก้ไขปัญหานี้หลายๆ ทาง อันหนึ่งคือก็เอา PHP ไปฝังไว้กับ Web server เลย โดย PHP จะมีส่วนที่เรียกว่า SAPI (Server API) ซึ่งเป็น library ที่เข้าไป integrate กับ web server (เช่น Apache) ให้เมื่อมีการเรียกหน้าที่กำหนดแล้วจะไปเรียก PHP API ที่สั่งให้ script ทำงาน

วิธีนี้ทำให้ไม่ต้อง start PHP ใหม่ทุก process เพราะ PHP จะอยู่กับ web server ไปเลย

ข้อเสียหลักๆ ของการทำแบบนี้คือ

  1. PHP library ไม่ได้พัฒนาให้ thread safe ดังนั้นจะใช้ Apache ได้แค่ใน mode prefork (แยก process แทน thread) ซึ่งเปลือง memory กว่า
  2. Code จะถูกรันด้วยสิทธิ์ของ web server ซึ่งในกรณีที่ใช้ share hosting แล้วจะทำให้เราสามารถเข้าไปอ่าน/แก้ไขไฟล์ของ user อื่นๆ บนเครื่องได้ทุกคน
  3. รัน PHP ได้แค่ version เดียวต่อ web server (ในกรณีที่มี legacy code ที่อัพเวอร์ชั่นไม่ได้)

ถึงใน PHP จะมีข้อจำกัดเยอะ แต่ในช่วงประมาณปี 2008 ที่คนเริ่มสนใจ Python/Ruby ทั้งสองภาษาก็ยัง deploy ด้วยท่านี้ได้ด้วย mod_wsgi หรือ Phusion Passenger

FastCGI

ท่าที่ค่อนข้างเวิร์คกว่าในการ Deploy web application คือ FastCGI ซึ่งเป็น standard อีกตัวหนึ่งที่เข้ามาแทน CGI

การทำงานของ FastCGI คือให้ web application นั้นเปิด socket ไว้ (อาจจะเป็น UNIX socket หรือ TCP ก็ได้) แล้ว Web server จะส่งต่อ request เข้ามาใน socket และเอาผลลัพท์กลับไปแสดง

วิธีนี้ทำให้เราสามารถ scale application server / web server แยกกันต่างหากได้ และรันเป็นคนละ user เพื่อความปลอดภัยได้

ปัจจุบันท่าที่นิยมใช้ Deploy PHP บน nginx ก็จะใช้ php-fpm ซึ่งจะรับ FastCGI connection เข้ามาประมวลผลด้วย PHP และช่วยจัดการเพิ่มลด process ให้อัตโนมัติ

Reverse proxy

ถ้า FastCGI คือการที่เรารับ HTTP request แล้วแปลงเป็น FastCGI request ส่งต่อ ทำไมเราไม่ส่ง request จริงไปเลยล่ะ?

ผมเข้าใจว่าท่า Reverse proxy เริ่มดังในช่วงหลังจากที่ Node.js เข้ามาแล้ว เพราะเป็นภาษา interpreted ภาษาแรกที่บอกว่าใช้ web server ในตัวมันรับโหลดได้เลยเพราะมันเป็น async ซึ่งเป็นจุดขายที่ว้าวมากในตอนนั้น

หลังจาก Node.js แล้ว Go ก็เป็นอีกภาษาหนึ่งที่บอกเหมือนกันว่าให้ใช้ web server ในตัวรับโหลดได้เลย

ความแตกต่างระหว่างการเปิด web server กับ FastCGI ที่จะเห็นได้ก็คือ

  • FastCGI เราเชื่อ web server ตัวหน้าทั้งหมด แต่การรันเป็น web server เราจะไม่เชื่อ web server ตัวหน้า ต้องเขียนโค้ดมาประมวลผลอีกที
  • เช่น web server จะมองเห็น IP คนที่ต่อเข้ามาและส่งให้ FastCGI ใน field พิเศษ แต่ถ้าเป็น reverse proxy นั้น application ต้องอ่านจาก X-Forwarded-For อีกทีหนึ่ง ซึ่งก็ต้องระวังความปลอดภัยด้วยเพราะ user ก็สามารถเซต header ได้
  • หรือถ้า web server ตัวหน้าใช้ HTTPS แล้วต่อเข้าด้านหลังด้วย HTTP ธรรมดาจะทำให้ application ไม่ทราบรายละเอียด connection เลยว่าเป็น HTTPS หรือไม่ (นอกจากจะเชื่อตาม header) และไม่สามารถใช้ฟีเจอร์อื่นๆ ได้เช่น Client certificate หรือ check cipher suite
  • Web server ของบางภาษาอาจจะรับโหลดไม่เก่งเท่า Web server จริงๆ เช่น Gunicorn แนะนำให้ใช้ web server คั่นหน้าเสมอ เนื่องจากถ้า client ทำงานช้า (Slowloris attack) จะเสีย thread ไปเปล่าๆ หรือโค้ดในการ serve static file ก็อาจจะไม่เก่งเท่า
  • Protocol HTTP นั้น parse ยากกว่า FastCGI protocol

What comes next

ทั้งหมดด้านบนคือ protocol หลักๆ ที่ยังใช้อยู่ในปัจจุบัน

แต่ในอนาคตก็เป็นไปได้ว่าอาจจะมีวิธีอื่นๆ เข้ามาก็ได้ ท่าที่เห็นในตอนนี้คือ event-driven เสียเป็นส่วนใหญ่

ASGI v1

ผมเคยอวย ASGI v1 มากๆ มันเป็นความพยายามที่จะทำให้ Django กลายเป็น async ทั้งๆ ที่มันเขียนเป็น sync มาทั้งหมด

วิธีการคือ web server ตัวหน้า (ASGI gateway) จะแปลง HTTP request ที่เข้ามาเป็น message แล้วยิงเข้าไปใน message queue จากนั้น ASGI server จะรันตาม request ที่ได้รับแล้วส่งผลลัพท์กลับไปใน message queue เช่นกัน

ท่านี้ผมเห็นครั้งแรกใน Mongrel2 ซึ่งใช้ ZeroMQ

วิธีนี้ยังสามารถประยุกต์ใช้งานกับ protocol อื่นๆ ได้อีก ซึ่งท่าที่ทำให้มันเท่มากคือ WebSocket โดย gateway จะยิง event ต่างๆ เช่น client connected, client message เข้าไปใน message queue ทำให้โค้ด scale ได้ง่ายเนื่องจากไม่มีการ hold connection เลย (นอกจาก MQ)

ด้วยความที่มันรันบน message queue มันทำให้การ scale ต่างๆ เหมือนการ scale message queue ทั่วไป รวมถึงว่าเราสามารถรัน gateway 1 server ที่ใช้ resource ไม่มากแล้วรัน ASGI server หลายๆ server ก็ได้

ปัญหาที่เจอในการใช้งานจริงคือเนื่องจากมันเป็น request-response ในครั้งเดียว web server เลยจะต้องรับ connection ทั้งหมดมาก่อนแล้วค่อยถาม application ว่าเอาไหม ซึ่งจะทำให้เกิดปัญหา queue backlog ยาวและ message queue บางประเภท cancel message ไม่ได้

อีกปัญหาหนึ่งคือถ้า user upload file ขนาดใหญ่มา เป็นปัญหาที่มันแก้ไม่ได้เลย เพราะส่งทั้งไฟล์ไปบน MQ ก็จะ overhead สูงมาก จะเขียนลงเครื่องก็อาจจะอยู่คนละเครื่อง จะเอาไปไว้ใน storage service ก็เพิ่ม dependency

Serverless

ถ้าย้อนกลับไปอ่านข้างบนจะพบว่า Serverless ที่กำลังฮิตอยู่ตอนนี้ จริงๆ มันคือ CGI กลับชาติมาเกิดเป๊ะๆ เลย แล้วปัญหาที่คนใช้ serverless เจออย่าง cold start นาน ก็คือปัญหาเดียวกับ CGI แถมมันยังรับได้แค่ 1 request per instance เหมือนกันด้วย

จะต่างกันแค่ว่า serverless application ไม่โดนบังคับให้ออกหลังจาก serve request จบแล้วแต่จะถูก freeze ไว้แทน ทำให้ครั้งถัดไปไม่เสีย cold start อีก

ไอเดียของ AWS Lambda ผมเข้าใจว่าเค้าน่าจะพยายามทำ code execution สำหรับ event ต่างๆ อยู่ (แบบที่ Twilio มี Functions) แล้วถึงพบว่ามันเอาไปรันเป็น web ได้ทีหลัง เวลาใช้ทำเว็บเลยจะเห็นว่าท่ามันยุ่งยากมาก คือต้องมี API Gateway/ALB แปลง request เป็น event เสียก่อนแล้วค่อยไป call lambda Invoke API ไม่สามารถเรียก function ตรงๆ ได้เลย (อย่างน้อยๆ ก็ต้องเรียกผ่าน Lambda API)

ก็จะเห็นมีแต่ Google Cloud Function ที่ทำกลับกันคือมี HTTP API แล้วเพิ่มให้รองรับ event ผ่าน webhook แทน

“CMS ตายแล้วหรือยัง”

*ทำไมบริษัทรับทำเว็บควรจะทำมากกว่าแค่ผลิตเทมเพลท*

บทความแปลจาก: [Torchbox](http://www.torchbox.com/blog/2012/10/are-content-management-systems-dead)

ผู้แปล: ผมเองตอนประกวดทำเว็บผมบอกกรรมการว่า “เว็บเราเน้น content และ content เว็บเราไม่ใช่การตัดแปะ มันผ่านการออกแบบมาแล้ว” นี่คือสิ่งที่ผมเชื่อว่าเว็บที่ดีเนื้อหาไม่ใช่การเขียนลงใน WordPress แบบที่ผมเขียนบล็อค แต่มันต้องผ่านการสรุปเลือกสรรออกมาแล้ว

โอเค อันที่จริง CMS ก็ยังไม่ตายหรอกครับ พูดไปงั้นแหละ แต่สำหรับคนที่ไม่รู้เรื่อง HTML แล้ว การสร้างเนื้อหาได้โดยใช้ความรู้แค่นิดหน่อยทำให้ความคิดดีๆ ส่งผ่านไปยังถึงอินเทอร์เน็ตได้

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

ระบบจัดการเนื้อหา (CMS) ออกแบบมาให้รองรับเนื้อหาได้ทุกชนิด ฉะนั้นแล้วตามธรรมชาติมันก็ต้องเป็นอะไรที่ค่อนข้างเป็นกลาง แต่ถ้าให้การออกแบบมันเสริมกับเนื้อหาจะไม่ดีกว่่าหรอครับ?

เนื้อหาบางชนิดก็เหมาะกับระบบจัดการเนื้อหา เช่น พวกบล็อค พวกโฮมเพจ และอื่นๆ ที่ต้องรีบอัพเดตให้ทันสมัยทันเหตุการณ์ เป็นต้น แต่เนื้อหาบางชนิดมีอายุยาวนานกว่า ผมเชื่อว่าเนื้อหาพวกนี้แหละ ที่จะต้องใช้ความเอาใจใส่มากเป็นพิเศษ

ลองดูตัวอย่าง [Google Ventures](http://www.googleventures.com/) ดูนะครับ

ส่วนเดียวของหน้านี้ที่ต้องใช้ระบบจัดการเนื้อหาคือหมวด “Here’s what we’ve been up to” ส่วนหัวเว็บ ภาพหลัก คำโปรย เมนู พวกนี้นักออกแบบเค้าออกแบบมาได้ดี สอดคล้องกันอยู่แล้ว แต่ถ้าให้นักเขียนมาควบคุมปุ๊บอาจทำโครงสร้างเว็บไซต์เสีย ผู้ใช้ก็จะเสียเวลาหาเนื้อหา และเว็บดูไม่สวยงาม

ถ้าผู้ออกแบบเว็บ Google Ventures ได้รับคำสั่งมาว่านักเขียนจะต้องสามารถเปลี่ยนภาพได้ เพิ่มเมนูได้ เค้าคงออกแบบไปอีกแนวนึงที่แบ่งเว็บเป็นส่วนๆ เพื่อป้องกันการเปลี่ยนแปลงที่ไม่แน่นอนในอนาคต ลักษณะเดียวกับที่จะเห็นได้ในธีมสำเร็จรูป ไอ้ความยืดยุ่นนี่ล่ะครับคืออุปสรรค์ของงานออกแบบที่ดูน่าสนใจเลย

หน้าสินค้าของ Apple เองก็ไม่ได้ใช้ระบบจัดการเนื้อหา (ดูอย่าง [iPhone 5](http://www.apple.com/iphone/)) ทุกภาพ ทุกตัวหนังสือผ่านการเลือกสรรออกมาแล้ว งานออกแบบลักษณะนี้สำคัญมากว่าตัวเนื้อหาจะต้องไม่มีการเปลี่ยนแปลง และงานคุณภาพแบบนี้จะไม่เกิดขึ้นในเว็บไซต์ที่ใช้ระบบจัดการเนื้อหา

จุดประสงค์เดียวของการจ้าง designer คือการนำเสนอข้อมูลในรูปแบบที่น่าสนใจและเข้าถึงได้ง่าย ให้นักเขียนตัดสินใจเองก็เหมือนให้เด็กเลือกทานอาหารเอง เด็กก็รู้ว่าตัวเองชอบกินอะไร แต่สิ่งที่กินก็ไม่ได้ดีต่อสุขภาพสักเท่าไร

แล้วเราจะออกแบบไปพร้อมๆ กับการให้นักเขียนเขียนเนื้อหาได้ยังไงล่ะครับ? ผมเชื่อว่าหลักใหญ่ใจความอยู่ที่ว่าหน้าไหนน่าจะมีการเปลี่ยนแปลงอย่างน้อยเดือนละครั้งบ้าง (เช่น บล็อค) แล้วออกแบบมันให้เหมาะสม ส่วนหน้าอื่นๆ เช่นหน้าเกี่ยวกับเรา ที่อาจจะเปลี่ยนทุกหกเดือน พวกนี้โค้ดเป็น HTML ไปเลย ถ้าจะเปลี่ยนแปลงค่อยติดต่อนักพัฒนาหรือนักออกแบบ

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

ลองคิดดูอีกทีนึงก่อนจะวางแผนให้เว็บใช้ได้ยันอนาคตด้วยการเพิ่มความสามารถต่างๆ นาๆ แต่ควรเริ่มจากน้อยๆ เน้นส่วนสำคัญตรงที่เราต้องการควบคุมจริงๆ และคุยกับนักพัฒนาของคุณให้ดีเพื่อสร้างเว็บที่มันเจ๋งจริง ไม่ใช่แค่ยืดหยุ่น

ปล. ผู้แปล: บล็อค [Visual Idiot](http://visualidiot.com/) เป็นบล็อคนึงที่ผมชอบมากครับ ทุก content มีการออกแบบสวยงาม ถ้าผมจำไม่ผิด ระบบข้างหลังเว็บจะเป็น CMS แต่ว่าออกแบบให้สามารถเขียน content ที่มีการจัดออกแบบได้ (ไม่ได้แปลว่าช่วยจัดนะครับ แค่สามารถเอามาลงได้สะดวกเฉยๆ)