ในบทความวันนี้ เราจะพูดถึงวิธีที่คุณสามารถใช้ประโยชน์จาก Upstash เพื่อจัดเก็บและเข้าถึงข้อมูลเกี่ยวกับแผนที่ที่พักพิงของประเทศอย่างปลอดภัยโดยใช้ Redis และอัปเดตฐานข้อมูลแบบเรียลไทม์ผ่าน QStash
บทนำ
ในบริบทของโลกปัจจุบัน ภัยพิบัติทางธรรมชาติและภัยคุกคามทางการทหารกำลังแพร่หลายมากขึ้นเรื่อยๆ ความจำเป็นในการเปลี่ยนผ่านสู่ดิจิทัลในด้านบริการสังคมก็เช่นกัน
ตั้งแต่ระบบออกอากาศฉุกเฉิน เช่น การแจ้งเตือน AMBER ไปจนถึงแอปติดตามโควิด-19 และระบบ SOS เราได้เห็นเทคโนโลยีมากมายที่ใช้เพื่อตอบสนองต่อสถานการณ์อันตรายทุกประเภทที่ส่งผลกระทบต่อประเทศ
ตอนนี้ เราจะมาดูกันว่า Redis และปริมาณงานแบบไร้เซิร์ฟเวอร์สามารถมีบทบาทสำคัญในการสร้างระบบตอบสนองฉุกเฉินแบบเรียลไทม์ที่ช่วยให้ประชาชนค้นหาบังเกอร์ที่ใกล้ที่สุดได้อย่างไร ขณะเดียวกันก็แจ้งให้ทราบเกี่ยวกับความจุ คุณสมบัติ (เช่น สิ่งอำนวยความสะดวกสำหรับคนพิการ) และทรัพยากร (น้ำ ไฟฟ้า ยา ฯลฯ) ที่พร้อมใช้งาน
ได้รับความอนุเคราะห์จาก Project Cloud4
ทำไมถึงไร้เซิร์ฟเวอร์
แนวคิดที่เรียกว่าไร้เซิร์ฟเวอร์ได้รับความนิยมในหมู่นักพัฒนาในช่วงหลายปีที่ผ่านมา เราพบว่ามีบริษัทสตาร์ทอัพจำนวนมากขึ้นที่เลือกที่จะปฏิบัติตามสถาปัตยกรรมนี้ และยังมีการนำไปใช้ในองค์กรขนาดใหญ่เพิ่มมากขึ้นอีกด้วย
โดยเฉพาะอย่างยิ่งเมื่อพูดถึงนักแสดงของรัฐ สภาพแวดล้อมการพัฒนาที่รวดเร็วและบริการที่ได้รับการจัดการอัตโนมัติสามารถลดความซับซ้อนและค่าใช้จ่ายในการสร้างระบบตอบสนองฉุกเฉินได้อย่างมาก เรายังต้องคำนึงถึงปัจจัยอีกสองประการด้วย:
- งบประมาณ :หากประเทศไม่ประสบภัยพิบัติที่เกิดขึ้น บุคคลใดที่มีบทบาทในการตัดสินใจจะสามารถอนุมัติการชำระเงินสำหรับพลังการประมวลผลที่ไม่ได้ใช้ได้หรือไม่ ฉันสงสัยอย่างนั้น
- การจราจรพุ่งสูงขึ้น :ลองนึกภาพสัญญาณเตือนภัยดังขึ้น และผู้คนนับล้านเข้าถึงแพลตฟอร์มเว็บเพื่อค้นหาที่พักพิงที่ใกล้ที่สุด REST API ของคุณจะจัดการกับ rps (คำขอต่อวินาที) ที่เพิ่มขึ้นอย่างกะทันหันนี้ได้อย่างไร แล้วส่วนประกอบเรียลไทม์ที่สำคัญล่ะ
คำถามต่างๆ ทั้งหมดนี้ตอบได้โดยใช้แพลตฟอร์มไร้เซิร์ฟเวอร์อย่างแท้จริง เช่น Upstash และ Ably เพื่อเพิ่มประสิทธิภาพเซิร์ฟเวอร์ที่มีน้ำหนักมาก ซึ่งจะปรับขนาดอัตโนมัติและเรียกเก็บเงินเฉพาะทรัพยากรที่คุณใช้เท่านั้น
ทำไมต้อง Redis?
ข้อกำหนดข้อมูลของโครงการของเราประกอบด้วยการดำเนินการอัลกอริทึมต่างๆ ที่ต้องดำเนินการด้วยความเร็วสูงสุดที่เป็นไปได้ ตั้งแต่โครงสร้างข้อมูลพื้นฐานสำหรับการแสดงข้อมูลของศูนย์พักพิงไปจนถึงการมีวิธีง่ายๆ ในการจัดเรียงข้อมูลที่มีอยู่ในสถานที่ตามเกณฑ์ที่แตกต่างกัน Redis ช่วยให้เราสามารถรักษาความยืดหยุ่นของฐานข้อมูล NoSQL ในขณะเดียวกันก็มอบฟังก์ชันต่างๆ เพื่อทำให้การพัฒนาง่ายขึ้นและเร็วขึ้น
ทำไมต้อง QStash
คิวข้อความแบบเดิมเป็นวิธีที่มั่นคงในการออกแบบระบบที่ขับเคลื่อนด้วยเหตุการณ์ แต่มีข้อแม้:คิวข้อความส่วนใหญ่ขึ้นอยู่กับโปรโตคอลเก็บสถานะอย่าง AMPQ อย่างสมบูรณ์ ซึ่งหมายความว่าคิวข้อความเหล่านี้ไม่พร้อมที่จะใช้ในสภาพแวดล้อมที่ทำงานระยะสั้น เช่น ฟังก์ชันแบบไร้เซิร์ฟเวอร์
QStash แก้ไขปัญหานี้โดยอนุญาตให้มีการร้องขอโดยใช้ HTTP ซึ่งเป็นโปรโตคอลไร้สัญชาติที่โดยทั่วไปใช้ในสภาพแวดล้อมดังกล่าว เมื่อผสมผสานกับ webhooks เราสามารถสร้างไปป์ไลน์แบบเรียลไทม์เพื่ออัปเดตและดึงข้อมูลจากและเข้าสู่ฐานข้อมูลได้
ข้อกำหนด
ป.ล. .:หากคุณต้องการดูตัวอย่าง ให้ข้ามข้อกำหนดและส่วนการตั้งค่า มีไว้เพื่อแสดงสิ่งที่เราใช้และวิธี
หากคุณต้องการสร้างระบบประเภทนี้ด้วยตัวเอง คุณจะต้องมีสิ่งต่อไปนี้:
- บัญชี Upstash ซึ่งคุณจะสร้างฐานข้อมูล Redis และใช้จุดสิ้นสุดหรือหัวข้อ QStash;
- บัญชี Ably และการตั้งค่าการรวมเว็บฮุค
- โครงการ Next.js;
- บริการอุโมงค์เช่น ngrok หากคุณต้องการพร็อกซีคำขอในเครื่องไปยัง URL ที่มีอินเทอร์เน็ต
- ตัวจัดการแพ็คเกจใด ๆ ที่รองรับไลบรารี่ที่ร้องขอ บทความนี้จะใช้ npm แต่ไม่บังคับ
หมายเหตุ :บทความนี้จะให้ตัวอย่างการพิสูจน์แนวคิดพื้นฐานบางส่วนเพื่อสาธิตการใช้เทคโนโลยีดังกล่าวในบริบทของสถาปัตยกรรมแอปพลิเคชันของเรา รหัสที่ระบุไม่พร้อมสำหรับการผลิตและถูกทำให้ง่ายขึ้นและสั้นลงเพื่อการอ่านที่ดีขึ้น ตรวจสอบให้แน่ใจว่าได้ทำการแก้ไขที่จำเป็นหากคุณต้องการปรับใช้ (การจัดการข้อยกเว้น ความปลอดภัย ฯลฯ)
ตั้งค่า
ฟังก์ชันไร้เซิร์ฟเวอร์
เราจะใช้เส้นทาง Edge API ของ Next.js เพื่อเรียกใช้ปริมาณงานแบบไร้เซิร์ฟเวอร์ใกล้กับตำแหน่งของผู้ใช้มากขึ้น
หากต้องการสร้างโครงการ Next.js ให้รัน 04 ในไดเร็กทอรีหลัก หลังจากนั้นคุณสามารถเรียกใช้ 18 เพื่อเริ่มเซิร์ฟเวอร์การพัฒนา 21 เพื่อสร้างชุดการผลิตและ 33 เพื่อเริ่มเซิร์ฟเวอร์ที่ใช้งานจริง
Next.js ใช้สภาพแวดล้อมของโหนดสำหรับเส้นทาง API เป็นค่าเริ่มต้น เราสามารถเปลี่ยนสิ่งนั้นได้สองวิธี:
- วิธีการต่อเส้นทาง เพิ่มการส่งออกต่อไปนี้ไปยังเส้นทางที่ต้องการ:
export const config = { runtime: "experimental-edge", }; - แนวทางสากล เพื่อสร้างขอบ รันไทม์เริ่มต้น ให้เพิ่มสิ่งต่อไปนี้ในไฟล์ next.config,js ของคุณ:
const nextConfig = { // ... experimental: { runtime: "experimental-edge", }, // ... };
สุดยอด
หากต้องการสร้างผู้ให้บริการ Upstash ให้ปฏิบัติตามคำแนะนำนี้
หากต้องการตั้งค่าเส้นทางตัวรับ QStash ให้ทำตามคำแนะนำนี้ โปรดทราบว่า Ably มีตัวเลือกการเข้ารหัสข้อความ webhook ให้เรา 2 แบบ ได้แก่ JSON และ MessagePack หากคุณต้องการใช้อันแรก คุณอาจจำเป็นต้องใช้ส่วนหัวการอนุญาตแทน JWT เพื่อแก้ไขปัญหาความเข้ากันได้ของการเข้ารหัสที่อาจเกิดขึ้น เพื่อความเรียบง่าย เราจะยึดถือ JSON
ความสามารถ
สำหรับฟังก์ชันการทำงานแบบเรียลไทม์ เราจะใช้โปรโตคอลของ Ably ซึ่งมีค่าเริ่มต้นเป็น WebSockets หากเป็นไปได้ ในการเริ่มต้น ให้ปฏิบัติตามคำแนะนำนี้ และในขณะที่เราใช้ Next.js คุณสามารถดูแพ็คเกจ @able-labs/react-hooks npm ได้
เราควรตั้งค่าการรวมเว็บฮุคเพื่อชี้ไปที่ URL ของ QStash ของเรา และเพิ่มส่วนหัวที่จำเป็น
หากคุณกำลังจะใช้งานจริง ให้ตรวจสอบการรับรองความถูกต้องและความปลอดภัยด้วย
ทางเลือก:การขุดอุโมงค์เฉพาะที่
ปฏิบัติตามคำแนะนำนี้เพื่อเริ่มต้นใช้งาน ngrok
สถาปัตยกรรม
ไหล
เพื่อให้เข้าใจขั้นตอนของแอปพลิเคชันของเราได้ดีขึ้น ลองดูที่ไดอะแกรมนี้ (สร้างด้วย excalidraw.com):

ดังที่คุณเห็นเราได้กำหนดผู้ใช้สองประเภท:
- พลเมือง ซึ่งสามารถเข้าถึงที่พักพิงหรือข้อมูลของสถานที่ และสามารถประกาศความตั้งใจที่จะไปที่บังเกอร์ได้
- ผู้ดูแลระบบ ซึ่งสามารถแก้ไขข้อมูลโลจิสติกส์ของบังเกอร์และแก้ไขความพร้อมได้ (เช่น ยืนยันว่าบุคคล/ครอบครัวมาถึงสถานที่นั้น)
เรากำลังพยายามทำให้ข้อมูลพร้อมใช้งานแบบเรียลไทม์ในขณะที่รักษาฟรอนต์เอนด์และแบ็กเอนด์ให้แยกจากกันมากที่สุด ดังนั้นเราจะใช้ช่องทาง Ably เพื่อสื่อสารกับไคลเอ็นต์และทริกเกอร์เว็บฮุคทุกครั้งที่ความพร้อมใช้งานเปลี่ยนแปลง
นอกจากนี้ เราจะใช้ REST API ของ Ably เพื่อเผยแพร่ข้อความจากแบ็กเอนด์ เนื่องจากเราไม่ควรใช้การเชื่อมต่อแบบมีสถานะใดๆ
ข้อมูล
ขณะนี้เราต้องจัดเก็บข้อมูลหลักสองประเภท:
-
ข้อมูลของที่พักพิงซึ่งอาจอยู่ในรูปแบบของแฮช Redis และมีคุณสมบัติดังต่อไปนี้:
- ชื่อของคีย์เป็น
40(เช่น:53) - ความพร้อมใช้งาน (เช่น:
61) - คุณลักษณะ (เช่น:
71) - ทรัพยากร:
เช่น:{ resource: quantity, or resource: list ... }{ "water": "200 liters", "medicine": ["insuline", ...] } - ไฟฟ้า:
86 - การทำความร้อน:
94 - ตำแหน่ง:
104รหัส> หรือ{ longitude: number, latitude: number } - _id:เราจะสร้างสิ่งนี้แบบสุ่ม
- ชื่อของคีย์เป็น
-
ข้อมูลของสถานที่
ในขณะที่เรา สามารถ ทำการค้นหาแบบซ้อนเพื่อค้นหาที่พักพิงสำหรับตำแหน่งที่ระบุ อาจเป็นความคิดที่ดีกว่าหากจัดเก็บไว้เป็นโครงสร้างข้อมูลที่แยกต่างหากเพื่อลดความซับซ้อนและเพิ่มประสิทธิภาพการสืบค้น ในการทำเช่นนั้น เราสามารถใช้ชุด Redis และตั้งชื่อองค์ประกอบเป็น
112(เช่น:126หรือ135รหัส> ). ด้วยวิธีนี้เราจะป้องกันการทำซ้ำเช่น:
city-CJ : ["RO-CJ-01", "RO-CJ-02", "RO-CJ-03"]
แต่ยังคงมีปัญหาอยู่ประการหนึ่ง:เราจะแยกแยะระหว่างความตั้งใจของพลเมืองที่จะไปสถานสงเคราะห์กับความเป็นจริงได้อย่างไร การอัปเดตจำนวนผู้เข้าพักที่เกิดจากการยืนยันของผู้ดูแลระบบของที่พักพิง? เราสามารถทำได้สองวิธี:
-
อัปเดตอย่างต่อเนื่อง รหัสความพร้อมของที่พักพิง:ผู้ใช้ประกาศความตั้งใจที่จะมา (คนเดียวหรือกับครอบครัว/ฯลฯ) => เราเพิ่มขึ้น x; ผู้ดูแลระบบพบว่าการยืนยันไม่ถูกต้อง => เราลดลง x (หรือเพิ่มขึ้น -x)
ปัญหาคือผู้ดูแลระบบจะต้องทำหน้าที่เป็นแหล่งที่มาของความจริงและติดตามตำแหน่งของพลเมือง นอกจากนี้ ข้อมูลของที่พักพิงไม่สามารถเชื่อถือได้ในทันที
-
สร้างคีย์สตริงแยกต่างหาก ชื่อ
140(เช่น:154) และจัดเก็บค่าที่อัปเดตแบบเรียลไทม์ ด้วยวิธีนี้เราสามารถอัปเดตแบบเรียลไทม์ และเก็บคีย์ความพร้อมใช้งานของแฮชไว้เป็นแหล่งที่มาของความจริงโปรดทราบว่าในฝั่งไคลเอ็นต์ เราจะดึงทั้งแฮชและคีย์สตริง และนำเสนอเป็นความพร้อมใช้งานจริงและที่คาดการณ์ไว้ อีกวิธีหนึ่งคือดึงเฉพาะสตริงและเปลี่ยนกลับไปสู่แหล่งที่มาของความจริงเมื่อจำเป็น แม้ว่าการดำเนินการนี้จะช่วยลดภาระของเครือข่าย แต่ผู้ดูแลระบบจะต้องตรวจสอบข้อมูลอย่างต่อเนื่อง (เช่นในสถานการณ์แรก) และเพื่อ ตามความเป็นจริง หากดึงมาน้อยลง เราจะต้องจัดเก็บรหัสความพร้อมของสถานสงเคราะห์แยกต่างหาก (โปรดจำไว้ว่า เรายังจำเป็นต้องได้รับข้อมูลอื่นๆ!)
การเรียงลำดับ
เรามาใช้ประโยชน์จากข้อมูล Redis อีกประเภทหนึ่งที่เรียกว่าชุดเรียงลำดับ สมมติว่าเราต้องการจัดเรียงบังเกอร์ในตำแหน่งตามความพร้อมใช้งาน สิ่งอำนวยความสะดวก หรือทรัพยากรที่มีอยู่ ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ เราสามารถทำการสืบค้นแบบซ้อนได้ แต่ต้องเสียเวลาและด้วยปริมาณข้อมูลที่ใหญ่กว่ามาก วิธีแก้ปัญหาที่ดีกว่าคือสร้างชุดที่เรียงลำดับสำหรับทุกเกณฑ์การกรอง (เราสามารถตั้งชื่อเป็น 169 เช่น 170 หรือ 189รหัส> )
ตัวอย่าง:
ในตัวอย่างนี้ คะแนนความพร้อมคำนวณเป็น
เราสามารถเขียนโค้ดพื้นฐานเพื่อแสดง API และพฤติกรรมของไคลเอ็นต์ได้
โดยหลักแล้ว เราจำเป็นต้องมี:
หลังจากติดตามตำแหน่งของผู้ใช้แล้ว เราจะเชื่อมต่อกับช่อง "ว่าง" โดยอัตโนมัติ และเผยแพร่ข้อความหากพลเมืองตั้งใจจะไปที่บังเกอร์
ขั้นแรก เรามาทำการเชื่อมต่อจาก
จากนั้นเชื่อมต่อกับช่องในส่วนประกอบใด ๆ ที่เราต้องการ:
หากต้องการเพิ่มข้อมูลใหม่ลงใน Redis เราสามารถใช้คำสั่ง HSET, SET และ SADD
นอกเหนือจากการดำเนินการ UD ขั้นพื้นฐาน (อัปเดต-ลบ) เราสามารถใช้คำสั่ง Redis INCRBY และ HINCRBY เพื่อแก้ไขความพร้อมใช้งานของที่พักอาศัยได้
หากพลเมืองประกาศความตั้งใจที่จะไปที่บังเกอร์ เราสามารถเผยแพร่ข้อความจากแอปไคลเอนต์ได้
ตามที่อธิบายไว้ในสถาปัตยกรรม สิ่งนี้จะทริกเกอร์ webhook ซึ่งเราสามารถนำข้อมูลและอัปเดต
หากคุณกำลังอัปเดตจากเซิร์ฟเวอร์ (เช่น การยืนยันของผู้ดูแลระบบ) อย่าลืมใช้ REST API แทน
บนเซิร์ฟเวอร์ เราสามารถใช้คำสั่ง GET , SMEMBERS และ HGETALL ได้
บนไคลเอนต์ เราสามารถฟังข้อความในช่องและอัปเดตสถานะตามนั้นได้
วันนี้เรามาดูกันว่าเราจะใช้ประโยชน์จากสถาปัตยกรรมไร้เซิร์ฟเวอร์อันทรงพลังเพื่อสร้างแอปติดตามเหตุฉุกเฉินในโลกแห่งความเป็นจริงได้อย่างไร แม้ว่าจะมีหลายวิธีในการทำให้สำเร็จ แต่ฉันแนะนำให้ดำเนินการตามขั้นตอนนี้เป็นการส่วนตัวเนื่องจากประสบการณ์ของนักพัฒนาซอฟต์แวร์ที่เรียบง่าย
บางทีคุณอาจเป็นนักพัฒนาอาวุโสที่เคยสร้างระบบคอมพิวเตอร์แบบกระจายและรู้สึกว่าต้องการบริการที่มีการจัดการ หรือคุณอาจเป็นมือใหม่แต่มีความคิดที่อาจเปลี่ยนแปลงโลกให้ดีขึ้นได้ การค้นหาเครื่องมือที่เหมาะสมเป็นส่วนสำคัญของกระบวนการเสมอ
แจ้งให้เราทราบว่าคุณคิดอย่างไรเกี่ยวกับบทความนี้ และหากคุณมีคำถามใดๆ โปรดส่งข้อความถึงฉันทาง LinkedIn หรือตรวจสอบรหัสอื่นๆ ของฉันบน Github191 ป> คะแนน เนื้อหา หัว> 200RO-B-02100RO-B-01 202 .ตัวอย่าง
ปลายทาง
ลูกค้า
215 ไฟล์:import { useEffect, useState } from "react";
import "../styles/globals.css";
import { configureAbly } from "@ably-labs/react-hooks";
export default function App({ Component, pageProps }) {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
configureAbly({
// In a production system, you should use authentication
key: process.env.NEXT_PUBLIC_ABLY_API_KEY,
});
setLoaded(true);
}, []);
if (!loaded) return <div>loading...</div>;
return <Component {...pageProps} />;
}import { useChannel } from "@ably-labs/react-hooks";
export default function Test() {
const [availability] = useChannel("availability", (msg) => {
console.log(msg);
});
return <></>;
}การทำงานกับฐานข้อมูล
การเพิ่มข้อมูลใหม่
export default async (req) => {
let data = await req.json();
if (data.type === "shelter") {
// Remove the 'type' key as it is not neccesary anymore
delete data.type;
const { name: shelter, availability } = data;
let shelterData = data;
// Generate a random id.
shelterData._id = Math.random()
.toString(36)
.replace(/[^a-z]+/g, "")
.substring(0, 7);
// Store the shelter's info as a hash
await redis.hset(shelter, shelterData);
// Store the realtime-updated availability as a string
await redis.set(shelter + "-availability", availability);
return new Response("ok");
} else if (data.type === "location") {
const { name: location, shelters } = data;
await redis.sadd(location, ...shelters);
return new Response("ok");
}
};การอัปเดตข้อมูลที่มีอยู่
availability.publish("update", {
shelter: "RO-CJ-01",
availability: 1, // Or -x, if the user cancels.
});229 กุญแจ.await redis.incrby(shelter + "-availability", value);การดึงข้อมูล
เพื่อสรุป