Meteor 3.5 ช่วยให้นักพัฒนาสามารถเปลี่ยนจาก SockJS มาใช้ uWebSockets.js ได้ง่ายๆ เพียงแค่กำหนด environment variable ตัวเดียว ซึ่งจะช่วยลดการใช้ CPU, RAM และภาระของ garbage-collection ลงอย่างเห็นได้ชัด สำหรับแอปพลิเคชันที่ต้องเรียกใช้งาน method calls เป็นจำนวนมาก
ทำไมการเปลี่ยนแปลงนี้ถึงสำคัญ
นับตั้งแต่เปิดตัว Meteor ได้ส่งข้อความ DDP (Distributed Data Protocol) ทุกข้อความผ่าน SockJS ซึ่งเป็น JavaScript fallback ที่ทำงานได้ทุกที่ แต่ไม่ได้ถูกออกแบบมาเพื่อความเร็วสูงสุดโดยเฉพาะ การเปิดตัวเวอร์ชันใหม่นี้ได้แยก transport layer ออกจากกัน โดยเปิดช่องทางให้สามารถเสียบปลั๊ก (plug-in point) เพื่อใช้งาน WebSocket implementation ใดก็ได้ที่สอดคล้องกับข้อกำหนดของ DDP การตั้งค่า DDP_TRANSPORT=uws ตอนเริ่มทำงาน จะเป็นการเปลี่ยนจากค่าเริ่มต้นมาเป็น uWebSockets.js ซึ่งเป็นเซิร์ฟเวอร์ที่ทำงานบน C/C++ และขึ้นชื่อเรื่อง throughput ที่สูง
มุมมองด้านประสิทธิภาพ
ผลการทดสอบประสิทธิภาพ (Benchmarks) ที่มาพร้อมกับการเปิดตัวครั้งนี้แสดงให้เห็นว่า:
- การใช้ CPU ลดลง 9%
- การใช้ RAM ลดลง 11%
- เวลาที่หยุดชะงักจากการทำ garbage-collection ลดลง 26%
- Throughput เพิ่มขึ้น 1.6 เท่า ในการทดสอบแบบ micro-benchmarks
ประสิทธิภาพที่เพิ่มขึ้นนี้จะเห็นได้ชัดเมื่อแอปพลิเคชันมีการเรียกใช้งาน method calls ในรูปแบบ RPC จำนวนมาก โดยตัว transport จะกลายเป็นคอขวด (bottleneck) ก็ต่อเมื่อ business logic ของแอปพลิเคชันได้รับการปรับแต่ง (optimised) จนถึงที่สุดแล้ว ดังนั้นการเปลี่ยนครั้งนี้จึงสามารถช่วยลดต้นทุนของเซิร์ฟเวอร์ได้โดยตรง
วิธีทดลองใช้งานในวันนี้
ไม่จำเป็นต้องใช้ binary แยกต่างหาก เพียงแค่ใช้ Meteor 3.5 ก็พอ สามารถรันแอปพลิเคชันด้วยคำสั่ง:
DDP_TRANSPORT=uws meteor run
เซิร์ฟเวอร์ uWebSockets.js จะรอรับการเชื่อมต่อที่พอร์ตของตัวเอง (ค่าเริ่มต้นคือ 5001) ในกรณีที่มี Meteor หลาย instance อยู่บน host เดียวกัน แต่ละ instance จะต้องได้รับการกำหนด uws.port ที่แตกต่างกันผ่าน METEOR_SETTINGS เพื่อหลีกเลี่ยงการชนกันของพอร์ต
ใครจะได้ประโยชน์ และใครที่อาจจะไม่เห็นความแตกต่างมากนัก
- งานที่เน้น RPC เป็นหลัก (RPC-heavy workloads) – บริการที่มีการเรียกใช้งาน method จำนวนมากต่อหนึ่งคำขอ จะสามารถประหยัดรอบการทำงานของ CPU และหน่วยความจำ ช่วยลดแรงกดดันในการขยายระบบ (scaling)
- แอปพลิเคชันที่เน้น Pub/Sub (Pub/Sub-centric apps) – ความหน่วง (latency) ส่วนใหญ่ในรูปแบบ publish/subscribe เกิดจากการคำนวณ data-diff ไม่ใช่จากตัว transport ดังนั้นความเร็วที่เพิ่มขึ้นจึงมีเพียงเล็กน้อย
การเปลี่ยนแปลงนี้เป็นแบบเลือกใช้งานเอง (opt-in) โดย SockJS ยังคงเป็นค่าเริ่มต้น เพื่อรักษาความเข้ากันได้กับสภาพแวดล้อมที่ไม่รองรับ native WebSockets
ข้อแลกเปลี่ยนและข้อควรระวัง
การเปลี่ยน transport เพิ่มขั้นตอนการดำเนินงานเล็กน้อย นั่นคือการจัดการพอร์ตเพิ่มเติมและตรวจสอบให้แน่ใจว่าไม่ไปชนกับบริการอื่น เนื่องจาก uWebSockets.js เป็น native module จึงมีข้อควรพิจารณาเรื่อง binary dependencies ตามปกติ กล่าวคือต้องมี build tools อยู่บน host ที่ใช้ deploy และการอัปเดตไลบรารีในอนาคตจำเป็นต้องได้รับการทดสอบกับ codebase ของแอปพลิเคชันด้วย
ก้าวต่อไปของ transport layer ใน Meteor
ด้วยการเปิดช่องว่างที่ชัดเจน (clean boundary) ตอนนี้ Meteor ได้เชิญชวนให้ชุมชนนักพัฒนามาทดลองใช้ transport ทางเลือกอื่นๆ ไม่ว่าจะเป็นเพื่อความต้องการด้านความปลอดภัยเฉพาะทาง, การขยายโปรโตคอลแบบกำหนดเอง หรือการปรับแต่งประสิทธิภาพเพิ่มเติม การเฝ้าดูว่าจะมี implementation จากบุคคลที่สามปรากฏขึ้นเร็วแค่ไหน จะเป็นตัวบ่งชี้ว่าโมเดลแบบ pluggable นี้จะกลายเป็นส่วนหนึ่งที่ถาวรของสถาปัตยกรรม Meteor หรือไม่
สรุปสาระสำคัญ: การเปลี่ยน DDP transport แบบ pluggable ใน Meteor 3.5 ช่วยให้คุณสามารถแทนที่ stack ของ SockJS แบบเดิมด้วย uWebSockets.js ได้ด้วยคำสั่งเดียว ซึ่งให้ throughput สูงขึ้นถึง 1.6 เท่า และช่วยประหยัดทรัพยากรอย่างเห็นได้ชัดสำหรับแอปพลิเคชันที่ใช้งาน RPC อย่างหนัก ในขณะที่ยังคงรักษาการตั้งค่าเดิมไว้สำหรับงานที่ไม่จำเป็นต้องได้รับการเพิ่มประสิทธิภาพนี้
