Skip to content

คำแนะนำการพัฒนา real-time app ด้วย Node.js และ Socket.io

ผมใช้ Node.js ร่วมกับ Socket.io มาได้ซักพักแล้ว เอาไปใช้ในแลปเล็กๆ ส่วนตัวของผมเองและเอาไปใช้จริงในงานที่ทำด้วย ก็พอเห็นปัญหาการในพัฒนาพอสมควรขอสรุปปัญหาและวิธีแก้ของผมดังนี้ครับ

1. สไตล์การเขียนโปรแกรมแบบ Asynchronous

Node.js มันคือ Javascript ถ้าคุ้นเคยมาก่อนจะดีมาก การเขียนโดยทั่วไปเขียนเหมือน procedural programming ทำงานจากบนลงล่างแต่ก็มีส่วนที่เป็น asynchronous API ของภาษามีการใช้ callback function เยอะมาก

ด้วยความที่ Node.js เป็น event-driven หรือ event-based รันด้วย thread เดียว เพื่อให้รองรับการทำงานพร้อมกันและลด overhead ระหว่าง thread การทำงานของโปรแกรมจะเป็นแบบ asynchronous หมายความว่า I/O จะไม่ถูกบล็อคการทำงาน ตัวอย่างเช่น การใช้งาน AJAX เมื่อเริ่มทำงานก็จะ request ข้อมูลออกไประหว่างที่รอ response ตอบกลับมาคำสั่งบรรทัดข้างล่างก็จะงานของมันไป (ถ้าทำเป็นแบบ sync ต้องรอให้มี response ตอบกลับมาก่อนจึงจะทำคำสั่งต่อไปได้) เมื่อมีการ response ข้อมูลกลับมาก็จะมีการส่ง event บอกว่าการตอบกลับมาแล้ว ซึ่ง event ตรงนี้เราสามารถเขียนโค้ดเพื่อจับ event แล้วนำข้อมูลไปประมวลผลต่อ เช่น เอาไปแสดงผลหน้าเว็บต่อได้

ปัญหาที่พบในการเขียน asynchronous programming คือการคุม control flow และ scope ของตัวแปรเพราะมีการใช้ callback function เยอะมาก บางครั้งต้องเขียน callback function ซ้อนกันหลายชั้นทำให้เกิดปัญหาที่เรียกว่า “callback pyramid”

Node.js มี lib สำหรับเขียน control flow ของโปรแกรมหลายตัวส่วนตัวผมใช้ Async เพราะครอบคลุมการทำงานหลายรูปแบบ ใช้ง่ายและ document ค่อนข้างดี คนใช้เยอะตัวอย่างเยอะด้วยอันนี้แนะนำครับ

2. server สำหรับ deploy app

ถึงแม้ว่า Node.js จะให้เราเขียนด้วย Javascript ซึ่งใช้ใน WWW มานานแล้วแต่มันเป็น Javascript ที่รันบน server  เทคโนโลยีนี้ยังใหม่ Node.js เวอร์ชันปัจจุบัน ณ ขณะนี้คืือ 0.8.12 ยังไม่ถึง 1 ด้วยซ้ำ ทำให้หา server deploy app ยาก hosting ทั่วไปยังไม่รองรับ ถ้าอยากใช้ผมก็แนะนำ 2 ทางเลือกคือ

  1. ตั้ง server หรือเช่า VPS (Virtual Private Server)  แล้ว set server ใช้เองซะเลย อยากได้อะไรก็ติดตั้งเพิ่มเอง แต่ก็ต้องรับภาระดูแล server เอง
  2. ใช้บริการ cloud จะเลือกแบบเช่าเป็นเครื่อง VM ก็ได้ (ทำเองเหมือนข้อ 1) หรือใช้ PaaS (Platform as a Service) ก็ได้ อย่างหลังแม้จะค่อนข้างจำกัดคุมเองไม่ได้ทั้งหมดแต่สะดวกกว่ามากเพราะไม่ต้องดูแล server เอง และ PaaS แต่ละเจ้ามักจะมีเครื่องมืออำนวยความสะดวกให้ deploy app ได้ง่ายขึ้น

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

3. Socket.io กับ ProxyPass ของ Apache web server

Websocket, Socket.io คืออะไรอธิบายสั้นๆ คือมันเอาไว้ทำ real-time app, PUSH data ได้ ขนาดยาวๆ ไว้เขียนแยกอีก post แล้วกันครับ เอาเรื่องการใช้งานและปัญหาที่ผมเจอก่อนดีกว่า

งานหลายๆ  implement ด้วยหลายเทคโนโลยีหลายภาษาเช่นตัวเว็บด้วย HTML, PHP แต่เซอร์วิสหรือ API เขียนด้วย Java Servlet รันบน Tomcat หรือทำด้วย Node.js, Socket.io เมื่อใช้หลายภาษาแสดงว่ามีการใช้ web server มากกว่า 1 ตัวรันคนละ port เพื่อความสะดวกจึงต้องทำ ProxyPass จุดประสงค์การทำ ProxyPass คือ

  • แก้ปัญหา AJAX cross-domain
  • เหตุผลด้านความปลอดภัย ซ่อน port ใช้ port 80 ซึ่งเป็น HTTP port เพียง port เดียว
  • ปัญหาการเข้าถึงเว็บฝั่ง client เพราะการเชื่อมต่อ internet บางแห่งเปิดให้ใช้ได้เพียง port 80 

การใช้งานร่วมกับ Apache web server ถ้าใช้เฉพาะ Node.js สามารถทำ ProxyPass map URL ได้ตามปกติแต่ถ้าใช้ถ้าใช้ Socket.io ด้วยจะมีปัญหาถึงแม้ว่าจะ Socket.io จะ handshake ด้วย HTTP แต่การรับ-ส่งข้อมูลใช้คนละ mechanism จึงทำงานไม่ได้

วิธีแก้ไขปัญหานี้ถ้าไม่สนใจว่าจะโชว์ port ที่เรารัน Node.js ไว้ในโค้ดก็ไม่ต้องทำ proxy ก็ได้แต่อย่างที่บอกไว้ข้างบนครับว่าอินเทอร์เน็ตบางที่จำกัด port แปลกๆ ไว้เมื่อเรียกใช้เว็บเราก็จะใช้งานส่วนนี้ไม่ได้

Apache web server ก็ยังไม่รองรับ Websocket ถ้าจะใช้ร่วมกับ Socket.io อาจจะเปลี่ยนไปใช้ web server ตัวอื่นที่รองรับฟีเจอร์นี้เช่น NGINX (อ่านว่า “เอน-จิ้น-เอ็กซ์”) ซึ่งทำงานเป็น event-based แบบเดียวกับ Node.js  Nginx เวอร์ชั่น 1.3 ขึ้นไปหรือไม่งั้นก็ไปใช้ PaaS แทน

Update 7 Jan 2014: สำหรับใครที่จะ Socket.io ร่วมกับ Apache โดยการทำ ProxyPass ก็ให้ config เลือก transport เป็น xhr-polling  หรือ jsonp-polling  ครับ

ใครที่พิจารณาเอา Node.js และ Socket.io มาใช้ก็อ่านไว้ประกอบการพิจารณาแล้วกันครับ ใครที่หลงเข้ามาอ่าน กำลังใช้งานพวกนี้อยู่มีปัญหาและวิธีแก้ก็มาแชร์กันได้ 🙂 

13 Comments

  1. Mic Mic

    ขอถามหน่อยคับ ที่บอกว่า apache ไม่รองรับ websocket อันนี้รวมถึง socket.io ด้วยปะคับ

    ปล. ลองดู heroku กับ appfog คับ ใช้ deploy node js ได้ ที่สำคัญมันฟรี

    • Kor Kor

      ใช่ครับ socket.io ก็เป็น implementation ของ Websockets ใช้ไม่ได้เหมือนกัน

      ผมเคยทำ list รวบรวมรายชื่อ PaaS/Cloud ไว้ ที่นี่ ครับ

  2. Mic Mic

    เยี่ยมเลยคับ

  3. Coon Coon

    ตอนนี้ผมมีปัญหาเรื่องปัญหาการเข้าถึงเว็บฝั่ง client ที่เค้าเข้าใช้ port อื่นไม่ได้ app ผมใช้ 8080,8082 ใช้ socket.io มีทั้งคนเข้าได้ และไม่ได้ อยากให้ช่วยบอกแนวทางวิธีแก้หน่อยครับ

    • Kor Kor

      ผมเองก็เจอปัญหานี้เหมือนกันครับ

      ถ้าจัดการฝั่งเองได้ลองใช้ proxy ที่รองรับ websockets ดูครับ เช่น HAProxy ตัวนี้ผมเองยังไม่ได้ลองใช้แต่ดูวิธีการ config แล้วเข้าใจง่ายดี

      Nginx เวอร์ชันปัจจุบัน (1.2) ยังไม่รองรับแต่มีข่าวดีว่าจะรองรับในเวอร์ชัน 1.3 ตอนนี้เสร็จไปประมาณ 71% แล้ว อีกไม่นานคง release ให้ใช้กัน http://trac.nginx.org/nginx/roadmap

      คงต้องรออีกพักใหญ่ครับกว่าจะมีซอฟต์แวร์รองรับมากขึ้น ไม่งั้นคงต้องหา PaaS รันแอปแทน

      • Coon Coon

        สะดวกคุยมั้ยครับ?? ผมมีคำถามเพิ่มเติม comment ไม่สะดวกครับ

        • Kor Kor

          สะดวก email, GTalk ครับ khasathan [ at ] gmail [ dot ] com

          • Coon Coon

            ขอบคุณครับ invite ไปแล้วครับ

    • Kor Kor

      ผมเขียนวิธีแก้ปัญหาการใช้งาน Nodejs, Socket.io application ร่วมกับเว็บที่รันบน Apache web server ผ่าน port 80 ไว้แล้วนะครับ ลองอ่านดูครับน่าจะแก้ปัญหาได้แล้ว

  4. poon poon

    ขอบคุณสำหรับ บทความนะครับ

     

  5. Pariwat Tiprutree Pariwat Tiprutree

    ตอนนี้ (03/10/2014) apache รองรับ socket.io หรือยังครับ

    เห็น apache มี module mod_proxy_ws_tunnel ไม่ทราบว่าใช้ทำอะไรพอทราบไหมครับ

    • Kor Kor

      เป็น module ของ Apache เอาไว้ทำ reverse proxy สำหรับ websocket ครับ

      หลักการก็เหมือน proxy ทั่วไปแต่รองรับ websocket เอาไว้ซ่อน server อื่นที่อยู่หลัง proxy server หรือบางกรณีที่เราต้องการ access application ที่รันไว้ port อื่น (เช่นรัน Node.js application ไว้ที่ port 8080) ให้ access ผ่าน port 80 ได้ก็ต้องทำ reverse proxy ครับ

Leave a Reply

Your email address will not be published.