Skip to content

ต้องทำอะไรบ้างเมื่อเอา Node.js, Socket.io app ขึ้น production

1. Configuration file

ไฟล์ config เกี่ยวกับการ database, config ทั่วไปของ app เช่นให้รันไว้ที่ port เท่าไหร่, domain อะไร ก่อนรัน app แก้ไขให้ตรงกับที่ใช้จริงก่อนรัน app

อาจจะสงสัยว่า เออ มันเป็นสิ่งที่ต้องทำอยู่แล้วนี่หว่าจะบอกทำไม ใช่ครับมันเป็นเรื่องพื้นฐานที่ต้องทำอยู่แล้วแต่เวลาเบลอๆ (หรือไม่เบลอก็เถอะ) ก็หลงลืมได้ ฉะนั้นถ้าจะเอา app ขึ้น production แก้ config พวกนี้ให้ถูกก่อนถ้ามีปัญหาจะได้ตามแก้เป็น step ไป

2. Socket.io configuration

ตอน develop ถ้าเรารัน app ด้วยคำสั่ง node  environment default ของ Node.js จะเป็น development mode คือมันจะพ่น log ทุกอย่างออกมาหมดและใช้ค่า default ของ Node.js และ Socket.io

แต่เวลาเอาไปใช้งานจริงการใช้ default config หรือเปิด debug mode ทำให้ประสิทธิภาพของ app แย่ลงก็ต้อง config เพิ่มกันหน่อยอย่างเช่น

  • log level  ตั้งเป็น 1 ก็พอ (การเก็บ log อาจจะใช้ lib ตัวอื่นช่วย pipe ไปลง syslog ก็ได้)
  • transports  ใส่ไป 3 อัน โดยทั่วไปผมมักจะให้ websocket เป็นอันดับแรกแล้วค่อยเป็น xhr-polling หรือ jsonp-polling เพราะเวลารันมันจะเลือกเอาอันแรกก่อนถ้าทำงานไม่ได้ค่อยไปใช้อันที่ 2 ที่เลือก websocket ก่อนเนื่องจาก overhead น้อยกว่า polling แต่บางเบราว์เซอร์ยังไม่รองรับก็เลยต้องใส่ xhr-polling ไปกันเหนียว
  • browser client gzip , browser client etag , browser client minification  config 3 ตัวนี้ช่วนเรื่องการบีบอัด static file (เช่น socket.io.js ในฝั่ง client) ลดขนาดไฟล์เวลารับ-ส่งจะได้ส่งน้อยๆ และรวดเร็ว
  • match origin protocol  document ของ Socket.io บอกว่าควร set เป็น true  สำหรับ production เหตุผลเรื่องความปลอดภัยครับ เมื่อมี request เข้ามาจะ check ต้นทางของ request (origin) ก่อนว่ามาจากไหนถ้าเป็น domain หรือ IP ของเราเองจะ connect ได้ปกติถ้าไม่ match ก็ reject ทิ้ง

configuration ข้างบนเป็นตัวอย่างเฉยๆ ครับถ้าเอาไปใช้จริงก็เอาให้เหมาะกับ app ของตัวเองพวก heartbeat timeout, heartbeat interval, polling duration ทั้งหลาย (ดูเพิ่มเติมที่ document ของ Socket.io)

3. ทำให้ app เข้าถึงได้ด้วย port 80

port 80 เป็น default ของ web server (HTTP server) หลายตัวเช่น Apache, Nginx เวลาเรียกดูผ่าน IP หรือ URL ถ้าไม่ระบุ port มันจะวิ่งเข้า port 80 ก่อน

โดยทั่วไปการเอา Node.js มาใช้ก็ไม่ได้ใช้เฉพาะ Node.js อย่างเดียวบางระบบใหญ่ๆ มีการทำงานหลายอย่างมักจะเลือก technology หรือภาษาที่เด่นและเก่งในแต่ละงานมาใช้ แต่ละส่วนรันบน port ต่างกัน

รัน app คนละ port แต่เข้าถึงผ่าน port 80 ไม่ได้แล้วมีปัญหาอะไร? มีปัญหาแน่ครับปัญหาที่น่าจะตามมาก็เช่น

  • ถ้าเขียน Node.js เป็น web service แต่รันไว้ที่ port อื่นเวลาเรียกด้วย Ajax แล้วอาจจะเจอปัญหา Ajax cross-domain ได้ แม้จะมีวิธีแก้ CORS (Cross-origin resource sharing) นี้ด้วยการกำหนด header  Access-Control-Allow-Origin : * โดย * (star) หมายถึงเรียกได้จาก IP หรือ domain อะไรถ้าจะให้เรียกได้เฉพาะ domain ที่กำหนดก็อาจใส่เป็น Access-Control-Allow-Origin : example.com  แต่เบราว์เซอร์เก่าหรือเบราว์เซอร์สำหรับบาง device อาจไม่รองรับ header นี้
  • internet ทุกที่ไม่ได้เปิด port ไว้ให้ใช้ทุก port บางที่เปิดให้ใช้แค่ port 80 สำหรับเข้าเว็บ ถ้ามีการเรียกไป port แปลกๆ นอกเหนือจากนี้ก็จะใช้งานไม่ได้

ถ้าใช้ transport เป็น websocket อาจจะต้องใช้ proxy ที่รองรับ WebSocket วางขวางไว้ที่ port 80 เช่น HAProxy, Nginx เวอร์ชัน 1.3 ขึ้นไป (เคยบล็อกถึงไปแล้ว) สำหรับคนที่ใช้ Nginx (เวอร์ชัน 1.3 ขึ้นไป) เป็น web server อยู่แล้วก็สบายหน่อยเพราะทำ reverse proxy ได้เลยเพราะรองรับ WebSocket แล้ว ถ้าใช้ Apache ก็ต้องหามาลงและ config เพิ่มเพราะตอนนี้ยังไม่รองรับ WebSocket แต่ถ้าใช้ transport แบบ xhr-polling ร่วมกับ Apache ก็สามารถทำ reverse proxy ได้เลยเช่นกัน

4. เลือก WebSocket หรือ XHR-polling ดี?

อันนี้ก็ขึ้นอยู่กับ user ที่ใช้ app ครับถ้าผู้ใช้เป็น dev, เป็นกลุ่มที่ใช้เบราว์เซอร์ใหม่อยู่แล้วหรือเป็น environment ที่คุมได้เช่น app ที่เราทำใช้กับเบราว์เซอร์มือถือได้และรองรับ WebSocket ก็เลือก transports  เป็น websocket  แต่ถ้าเน้นผู้ใช้ทั่วไปก็เลือกเป็น xhr-polling  หรือ jsonp-polling  เพราะบางเบราว์เซอร์ยังไม่รองรับ  websocket

ถ้าจะให้ครอบคลุมกันเหนียวก็ใส่ไปทั้ง websocket , xhr-polling  และ jsonp-polling  Socket.io จะ test transport แต่ละแบบตามลำดับถ้าใช้ transport แบบไหนได้ก็จะใช้อันนั้น

5. ปัญหาเล็กๆ น้อยกับการใช้ transport แบบ XHR-polling

สำหรับใครที่ใช้ transport แบบ xhr-polling  พัฒนา application ที่ค่อนข้างซีเรียสกับการ connect/disconnect, การจัดการ session คงเจอปัญหาที่มัน detect การ disconnect จาก client ไม่ได้ และไม่ยอม fire disconnect event ทำให้โค้ดที่เขียนไว้เมื่อเกิด event disconnect ที่ฝั่ง server ไม่ทำงานเพราะไม่รู้ว่า client disconnect หรือยัง และโดยปกติ Socket.io ค่า default ของมันจะ re-connect ให้อัตโนมัติทำเมื่อ connect เข้ามาก็จะเกิด session ใหม่โดยที่ session เก่าก็ยังค้างอยู่อาจทำให้ logic การทำงานของโปรแกรมผิดได้ ยกตัวอย่างเช่น app ที่ผมทำมีการนับจำนวน user ที่ connect เข้ามาโดยนับจาก socket id และจำกัดจำนวน user ในการเข้าใช้ app ถ้ามี session เก่าค้างอยู่ user ใหม่ๆ ก็จะ connect เข้ามาไม่ได้ หรือแม้กระทั่ง user เก่าที่เพิ่งหลุดไปแล้ว re-connect ใหม่เข้ามาก็จะ connect เข้ามาไม่ได้เหมือนกัน แบบนี้เป็นต้น

วิธีแก้ไขก็มี work around ช่วยได้บ้างคือการกำหนด config การที่ฝั่ง client โดยเพิ่ม option  sync disconnect on unload เป็น  true

แต่วิธีนี้ก็มีคนบอกว่ามันใช้กับเบราว์เซอร์ iPhone, iPad ไม่ได้หรืออาจมีปัญหาถ้าเน็ตช้า (ตามลิงก์อ้างอิงข้างล่าง)

เรื่องการใช้งานกับ iDevice ผมก็ไม่ทราบว่าจริงหรือเปล่า อาจจะถูกแก้ปัญหาไปแล้วก็ได้ ผมไม่มี iDevice ทดสอบเลย (ท่านใดที่ทดสอบแล้วก็มาคุยกันได้ครับ) ส่วนเรื่องเน็ตช้าผมมองว่าถ้าเน็ตช้ายังไงมันก็มีปัญหา ไม่ใช่แค่ปัญหานี้หรอก :p

6. Logging

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

สำหรับ Node.js ก็มี module สำหรับเก็บ log อยู่หลายตัวเลือกใช้ตามสะดวก แต่ถ้าอยากใช้ syslog เก็บให้ก็มี node-syslog ให้ใช้เหมือนกัน ถ้าใช้ syslog เก็บจะสบายหน่อยเพราะเป็นระแบบเก็บ log ของระบของ Linux อยู่แล้ว ทำ log rotation ให้อัตโนมัติด้วย

7. Availability เป็นเรื่องสำคัญ

Availability ของ app หรือ service หมายความว่า app/service พร้อมให้บริการตลอดเวลา พูดง่ายๆ คือถึงเวลาต้องใช้งานก็พร้อมใช้งาน user ก็เกิด impression ต่อระบบเพราะสามารถใช้งานได้ตลอดเวลาอยากใช้เมื่อไหร่ก็ได้

การเพิ่ม Availability สำหรับ Node.js app มีโปรแกรมพวก process monitor ช่วยทั้งทางฝั่ง server เองเช่น Monit โปรแกรมนี้สามารถ config ได้ละเอียดเลยว่าจะให้ shutdown app เมื่อไหร่ ใช้ memory ไปเท่าไหร่, load ไปเท่าไหร่ถึงจะ shutdown app แล้ว start ใหม่ แต่การใช้งานอาจจะต้องมีความรู้ด้าน programming และ Linux, Unix สักนิด

อีกโปรแกรมที่อยากแนะนำคือ Forever เป็น module ของ Node.js สามารถติดตั้งได้ผ่าน NPM package manager สามารถใช้ได้ทั้งแบบ command line เหมือนคำสั่ง Linux ทั่วไปและแบบไลบรารี่เรียกใช้เหมือนได้ในโปรแกรม ส่วนตัวผมคิดว่าตัวนี้ใช้ง่ายกว่า Monit ถ้าใช้แบบ command line อาจจะมี option เพิ่มเข้ามานิดหน่อยแต่ถ้าไม่ใส่ option อะไรใช้ default ของมันก็ยังทำงานได้ดีครับ

อ้างอิง

2 Comments

  1. มันคืออัลไล อ่านยังไง ก็ไม่เข้าใจ เพราะว่ายังไง ก็ไม่เคยเขียน อิอิ

  2. Kor Kor

    workshop กันดีกว่า Node.js + Git + deploy ขึ้น OpenShift ด้วย 🙂

Leave a Reply

Your email address will not be published.