it_devops

Elixir Nerves IoT Message Queue Design | SiamCafe Blog

Elixir Nerves IoT Message Queue Design | SiamCafe Blog

Elixir Nerves กับการออกแบบ Message Queue สำหรับงาน IoT คืออะไร

หลายคนที่เข้ามาอ่านบล็อก SiamCafe อาจสงสัยว่าทำไมผมถึงพูดถึง Elixir และ Nerves บ่อยขึ้นในช่วงหลัง

แม้ว่าในเชิงหน้าที่ผมจะเป็นเทรดเดอร์ที่ใช้ชีวิตกับกราฟ Forex มากว่า 13 ปี ก็ตาม ความจริงคือระบบแจ้งเตือนสัญญาณที่ผมพัฒนาเองใช้สถาปัตยกรรมแบบกระจายศูนย์ และฝั่งอุปกรณ์ IoT เช่น บอร์ด Raspberry Pi ที่ติดตั้งไว้ตามจุดต่าง ๆ ต้องสื่อสารกันตลอดเวลา นี่คือจุดที่ Elixir Nerves เข้ามามีบทบาท Nerves คือเฟรมเวิร์กที่ช่วยให้เราเขียน Elixir ลงไปรันบนฮาร์ดแวร์ขนาดเล็กได้โดยตรง ส่วน Message Queue หรือคิวข้อความ คือกลไกที่ใช้เก็บและส่งต่อข้อมูลระหว่างอุปกรณ์กับเซิร์ฟเวอร์อย่างเป็นระเบียบ เมื่อเอาสองอย่างนี้มารวมกัน เราจะได้ระบบ IoT ที่ทนทานต่อความผิดพลาด เพราะกระบวนการ (process) แต่ละตัวใน Elixir ทำงานแยกกันแบบสิ้นเชิง ถ้าตัวหนึ่งล่ม ตัวอื่นก็ยังทำงานต่อได้ทันทีโดยไม่กระทบกัน

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

ในทางปฏิบัติ การออกแบบคิวข้อความสำหรับงาน IoT ที่ดีต้องตอบคำถามสามข้อให้ได้ก่อนเขียนโค้ดแม้แต่บรรทัดเดียว หนึ่งคือข้อมูลจะหายได้หรือไม่ ถ้าอุปกรณ์ขาดอินเทอร์เน็ตชั่วขณะ ข้อมูลที่ยังส่งไม่ได้ต้องถูกเก็บไว้ที่เครื่องย่อยก่อน สองคือลำดับของข้อมูลสำคัญแค่ไหน เช่น ข้อมูลอุณหภูมิต้องเรียงตามเวลา สามคือระบบต้องรองรับอุปกรณ์จำนวนเท่าไรในอีกหนึ่งหรือสองปีข้างหน้า คำตอบของสามข้อนี้จะกำหนดว่าเราจะใช้คิวแบบในหน่วยความจำ แบบเก็บลงดิสก์ หรือใช้โปรโตคอลแบบเผยแพร่สมาชิก (publish-subscribe) ผ่าน MQTT ซึ่งเป็นมาตรฐานที่ใช้กันแพร่หลายในวงการ IoT ปัจจุบัน ทั้งหมดนี้คือหัวใจของหัวข้อที่เราจะเจาะลึกกันในบทความนี้

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

GenServer หนึ่งตัวต่อเซนเซอร์หรือต่อบัสสื่อสาร เช่น ไอทูซี (I2C) หรือยูเออาร์ที (UART) กระบวนการนี้มีหน้าที่อ่านค่าจากเซนเซอร์ตามรอบเวลาที่กำหนด ทำความสะอาดข้อมูลเบื้องต้น เช่น กรองค่าที่ผิดปกติออก แล้วส่งต่อเข้าคิวกลาง ชั้นที่สองคือคิวกลางเอง ซึ่งบน Nerves เรามีทางเลือกหลายแบบ ตั้งแต่คิวแบบเรียบง่ายของมาตรฐานภาษาเอง ไปจนถึงไลบรารีเฉพาะทางอย่าง Broadway ที่ช่วยจัดการดึงข้อมูลออกจากคิวเป็นชุด ๆ พร้อมควบคุมอัตราการทำงานอัตโนมัติ ชั้นที่สามคือชั้นเผยแพร่ข้อมูลออกสู่เครือข่าย มักใช้โปรโตคอล MQTT ผ่านไลบรารี Tortoise หรือใช้การเชื่อมต่อแบบถาวรผ่านเว็บซ็อกเก็ตด้วย Phoenix ชั้นที่สี่คือชั้นพักข้อมูลชั่วคราวบนตัวอุปกรณ์เอง เช่น การเขียนลงไฟล์หรือลงฐานข้อมูลขนาดเล็ก กรณีเครือข่ายขาดหาย

เมื่อเริ่มออกแบบจริง ผมแนะนำให้มองระบบออกเป็นสี่ชั้นหลักที่ทำงานประสานกัน ชั้นแรกคือชั้นเก็บกวาดข้อมูลดิบจากเซนเซอร์ โดยปกติผมจะใช้กระบวนการ GenServer หนึ่งตัวต่อเซนเซอร์หรือต่อบัสสื่อสาร เช่น ไอทูซี (I2C) หรือยูเออาร์ที (UART) กระบวนการนี้มีหน้าที่อ่านค่าจากเซนเซอร์ตามรอบเวลาที่กำหนด ทำความสะอาดข้อมูลเบื้องต้น เช่น กรองค่าที่ผิดปกติออก แล้วส่งต่อเข้าคิวกลาง ชั้นที่สองคือคิวกลางเอง ซึ่งบน Nerves เรามีทางเลือกหลายแบบ ตั้งแต่คิวแบบเรียบง่ายของมาตรฐานภาษาเอง ไปจนถึงไลบรารีเฉพาะทางอย่าง Broadway ที่ช่วยจัดการดึงข้อมูลออกจากคิวเป็นชุด ๆ พร้อมควบคุมอัตราการทำงานอัตโนมัติ ชั้นที่สามคือชั้นเผยแพร่ข้อมูลออกสู่เครือข่าย มักใช้โปรโตคอล MQTT ผ่านไลบรารี Tortoise หรือใช้การเชื่อมต่อแบบถาวรผ่านเว็บซ็อกเก็ตด้วย Phoenix ชั้นที่สี่คือชั้นพักข้อมูลชั่วคราวบนตัวอุปกรณ์เอง เช่น การเขียนลงไฟล์หรือลงฐานข้อมูลขนาดเล็ก กรณีเครือข่ายขาดหาย

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

ทางเลือกเหมาะกับงานแบบใดข้อดีข้อจำกัด
คิวในหน่วยความจำของกระบวนการข้อมูลที่ยอมรับการสูญหายได้เร็วมาก ใช้ทรัพยากรต่ำข้อมูลหายทันทีเมื่ออุปกรณ์รีสตาร์ต
Broadway + แหล่งข้อมูลภายนอกปริมาณข้อมูลสูง ต้องการความน่าเชื่อถือจัดการชุดข้อมูล ลองใหม่เองได้ต้องมีเซิร์ฟเวอร์กลางรองรับ
MQTT คิวคงอยู่ (persistent session)อุปกรณ์เชื่อมต่อไม่เสถียรมาตรฐาน IoT รองรับกว้างต้องพึ่งโบรกเกอร์ภายนอก
เขียนลงฐานข้อมูลเฉพาะที่ก่อนส่งข้อมูลวิกัยห้ามหายเด็ดขาดทนต่อไฟดับทุกรูปแบบเขียนดิสก์บ่อย ต้องระวังอายุการใช้งานแฟลช

มาถึงขั้นตอนลงมือทำจริงกัน เครื่องมือที่ต้องเตรียมมีไม่มาก แต่ต้องครบ เริ่มจากติดตั้ง Elixir และเครื่องมือ Nerves บนเครื่องพัฒนา

จากนั้นสร้างโปรเจกต์ใหม่ด้วยคำสั่งผสมระหว่าง Mix ซึ่งเป็นเครื่องมือจัดการโปรเจกต์ของ Elixir กับเทมเพลตของ Nerves ผมยกตัวอย่างลำดับคำสั่งที่ใช้จริงเป็นตัวอักษรโค้ดแบบเชลล์ดังนี้

การติดตั้งและเริ่มต้นโปรเจกต์ Nerves พร้อมคิวข้อความ

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

sudo apt update && sudo apt install -y erlang elixir git mix local.hex --force mix archive.install hex nerves_bootstrap --force

mix nerves.new iotqueuehub cd iotqueuehub

export MIX_TARGET=rpi4 mix deps.get

เมื่อโปรเจกต์พร้อมแล้ว ขั้นตอนต่อไปคือเพิ่มไลบรารีที่จำเป็นลงในไฟล์จัดการแพ็กเกจ ได้แก่ ไลบรารีสื่อสารกับ MQTT และไลบรารีสำหรับจัดการเวลาแบบทนทาน การตั้งค่าพื้นฐานของคิวข้อความผมมักเขียนเป็นโมดูลควบคุมแบบนี้

defmodule IotQueueHub.Queue do use GenServer

@maxsize 10000

def startlink(opts), do: GenServer.startlink(__MODULE__, opts, name: __MODULE__)

def push(item), do: GenServer.cast(__MODULE__, {:push, item})

@impl true def init(_opts) do {:ok, %{queue: :queue.new(), size: 0}} end

@impl true def handle_cast({:push, item}, state) do if state.size >= @max_size do

# ปล่อยข้อมูลเก่าสุดออกก่อน ป้องกันหน่วยความจำล้น

{_, rest} = :queue.out(state.queue) {:noreply, %{state | queue: :queue.in(item, rest)}} else {:noreply, %{state | queue: :queue.in(item, state.queue), size: state.size + 1}} end end end

ระบบ IoT ที่ติดตั้งออกไปนอกสำนักงานไม่มีทางให้เรานั่งเฝ้าได้ตลอด ดังนั้นการออกแบบคิวข้อความบน Nerves ที่ดีต้องมีกลไกกู้คืนในตัวตั้งแต่แรก

หลักการหลักของ Elixir คือแนวคิดต้นไม้เฝ้าดู (supervision tree) โดยเรามีกระบวนการผู้เฝ้าดูคอยจับตากระบวนการลูกทุกตัว ถ้าตัวใดล้มเหลว ผู้เฝ้าดูจะรีสตาร์ตให้ทันทีตามนโยบายที่กำหนด เช่น รีสตาร์ตเฉพาะตัวที่ล้ม หรือรีสตาร์ตทั้งกลุ่มเพื่อให้สถานะกลับมาสอดคล้องกัน ประเด็นที่ละเอียดอ่อนคือการเลือกนโยบายให้เหมาะ เพราะถ้ากระบวนการหนึ่งล้มซ้ำ ๆ จากบั๊กเดิม การรีสตาร์ตวนไปจนถึงตัวผู้เฝ้าดูระดับบนสุดจะทำให้ระบบทั้งหมดเด้งเป็นวงจรไม่รู้จบ ผมจึงตั้งค่าจำนวนครั้งรีสตาร์ตสูงสุดภายในช่วงเวลาหนึ่ง แล้วให้ระบบเข้าโหมดพักและแจ้งเตือนมายังผมก่อน

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

การจัดการความเสถียร การกู้คืน และการเฝ้าระวังระบบ

เมื่อจำนวนอุปกรณ์เพิ่มจากสิบเครื่องเป็นร้อยเครื่องหรือพันเครื่อง สถาปัตยกรรมฝั่งเซิร์ฟเวอร์ต้องเปลี่ยนบทบาทตาม จุดแข็งของ Elixir

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

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

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

การปรับขนาดระบบและรูปแบบการทำงานร่วมกับเซิร์ฟเวอร์กลาง

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

สำหรับรูปแบบการทำงานร่วมกัน ผมใช้แนวคิดหลักสองแบบสลับกันตามลักษณะงาน แบบแรกคือแบบเผยแพร่สมาชิก อุปกรณ์เผยแพร่ข้อมูลลงหัวข้อ (topic) แล้วให้ผู้สนใจหลายฝ่ายมารับพร้อมกัน เช่น ข้อมูลอุณหภูมิห้องเซิร์ฟเวอร์อาจถูกใช้ทั้งระบบแจ้งเตือน ระบบบันทึกสถิติ และระบบควบคุมเครื่องปรับอากาศพร้อมกัน แบบที่สองคือแบบคิวงาน ข้อมูลแต่ละชิ้นถูกประมวลผลเพียงครั้งเดียวโดยผู้รับคนใดคนหนึ่ง เหมาะกับงานประเภทส่งคำสั่งควบคุมอุปกรณ์ที่ต้องการความแน่นอน การเลือกใช้ผิดรูปแบบคือต้นเหตุของปัญหาข้อมูลซ้ำหรือข้อมูลหายยอดฮิตที่สุดในโปรเจกต์ของทีมผม

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

ตัวอย่างการนำไปใช้จริงและแนวปฏิบัติที่แนะนำ

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

คำถามที่พบบ่อย

Elixir Nerves คืออะไร และเหมาะกับงาน IoT แบบไหน?

Nerves คือเฟรมเวิร์กที่ช่วยให้เราเขียนโค้ดภาษา Elixir ลงไปรันบนฮาร์ดแวร์ขนาดเล็กอย่าง Raspberry Pi ได้โดยตรง จุดเด่นที่สำคัญคือเครื่องจักรเสมือน BEAM ซึ่งรองรับการทำงานขนานได้นับล้านกระบวนการพร้อมกันบนฮาร์ดแวร์ชิ้นเดียว โดยแต่ละกระบวนการทำงานแยกกันแบบสิ้นเชิง หากตัวหนึ่งล่ม ตัวอื่นยังทำงานต่อได้ทันทีโดยไม่กระทบกัน คุณสมบัตินี้เหมาะกับงาน IoT อย่างยิ่ง เพราะเซนเซอร์แต่ละตัวส่งข้อมูลมาในจังหวะที่คาดเดาไม่ได้ และข้อมูลที่ปลายทางยังประมวลผลไม่เสร็จจะรออยู่ในกล่องจดหมายของแต่ละกระบวนการอย่างปลอดภัย ไม่หายไปไหน ทำให้ได้ระบบ IoT ที่ทนทานต่อความผิดพลาดในระดับที่ภาษาอื่นทำได้ยาก

ก่อนออกแบบคิวข้อความสำหรับงาน IoT ต้องตอบคำถามอะไรบ้าง?

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

สถาปัตยกรรมระบบคิวข้อความบน Nerves มีกี่ชั้นและแต่ละชั้นทำหน้าที่อะไร?

ระบบที่ดีควรมองเป็นสี่ชั้นหลักที่ทำงานประสานกัน ชั้นแรกคือชั้นเก็บกวาดข้อมูลดิบจากเซนเซอร์ โดยใช้ GenServer หนึ่งตัวต่อเซนเซอร์หรือต่อบัสสื่อสารอย่าง I2C หรือ UART ทำหน้าที่อ่านค่าตามรอบเวลา กรองค่าผิดปกติ แล้วส่งต่อเข้าคิวกลาง ชั้นที่สองคือคิวกลางเอง เช่น คิวมาตรฐานของภาษา หรือไลบรารีอย่าง Broadway ที่จัดการดึงข้อมูลเป็นชุดพร้อมควบคุมอัตราการทำงานอัตโนมัติ ชั้นที่สามคือชั้นเผยแพร่ข้อมูลออกสู่เครือข่าย มักใช้ MQTT ผ่านไลบรารี Tortoise หรือเว็บซ็อกเก็ตด้วย Phoenix และชั้นที่สี่คือชั้นพักข้อมูลชั่วคราวบนอุปกรณ์ เช่น เขียนลงไฟล์หรือฐานข้อมูลขนาดเล็ก กรณีเครือข่ายขาดหาย การแบ่งชั้นแบบนี้ทำให้แต่ละส่วนเปลี่ยนหรือปรับปรุงได้อิสระจากกัน

ควรเลือกคิวแบบใดสำหรับข้อมูลที่สำคัญและห้ามหายเด็ดขาด?

ข้อผิดพลาดที่มือใหม่มักทำคือเลือกคิวแบบในหน่วยความจำทั้งระบบ แล้วเจอปัญหาข้อมูลหายทันทีเมื่อไฟฟ้าดับ เครือข่ายกระตุก หรืออุปกรณ์รีสตาร์ต สำหรับข้อมูลวิกัยที่ห้ามหายเด็ดขาด แนวทางที่ปลอดภัยที่สุดคือเขียนลงฐานข้อมูลเฉพาะที่ (local database) ก่อนส่ง เพราะทนต่อไฟดับได้ทุกรูปแบบ แต่ต้องระวังการเขียนดิสก์บ่อย ๆ ที่กระทบอายุการใช้งานแฟลช ในทางปฏิบัติแนะนำให้ออกแบบแบบผส

แนะนำเพิ่มเติม

🎯 เปิดบัญชี XM Forex → สมัคร

📱 แอป iCafeFX → ดาวน์โหลด

📊 สัญญาณฟรี → รับสัญญาณ

📚 คู่มือเทรด → SiamCafeBook

🤝 สมัคร Partner XM → pipaffiliates.com/c?c=72816&l=th&p=6

คู่มือ Forex ที่เกี่ยวข้อง

อ
XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง

แหล่งอ้างอิง

  • SiamCafe.net - ชุมชนไอทีไทยตั้งแต่ปี 1997
  • iCafeFX.com - ศูนย์วิเคราะห์ Forex และทองคำ