Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

ระบบตอบสนองเหตุฉุกเฉินแบบเรียลไทม์:ใช้ประโยชน์จาก Upstash, Redis และ QStash

ในบทความวันนี้ เราจะพูดถึงวิธีที่คุณสามารถใช้ประโยชน์จาก Upstash เพื่อจัดเก็บและเข้าถึงข้อมูลเกี่ยวกับแผนที่ที่พักพิงของประเทศอย่างปลอดภัยโดยใช้ Redis และอัปเดตฐานข้อมูลแบบเรียลไทม์ผ่าน QStash

บทนำ

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

ตั้งแต่ระบบออกอากาศฉุกเฉิน เช่น การแจ้งเตือน AMBER ไปจนถึงแอปติดตามโควิด-19 และระบบ SOS เราได้เห็นเทคโนโลยีมากมายที่ใช้เพื่อตอบสนองต่อสถานการณ์อันตรายทุกประเภทที่ส่งผลกระทบต่อประเทศ

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

ระบบตอบสนองเหตุฉุกเฉินแบบเรียลไทม์:ใช้ประโยชน์จาก Upstash, Redis และ QStash ได้รับความอนุเคราะห์จาก Project Cloud4

ทำไมถึงไร้เซิร์ฟเวอร์

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

โดยเฉพาะอย่างยิ่งเมื่อพูดถึงนักแสดงของรัฐ สภาพแวดล้อมการพัฒนาที่รวดเร็วและบริการที่ได้รับการจัดการอัตโนมัติสามารถลดความซับซ้อนและค่าใช้จ่ายในการสร้างระบบตอบสนองฉุกเฉินได้อย่างมาก เรายังต้องคำนึงถึงปัจจัยอีกสองประการด้วย:

  1. งบประมาณ :หากประเทศไม่ประสบภัยพิบัติที่เกิดขึ้น บุคคลใดที่มีบทบาทในการตัดสินใจจะสามารถอนุมัติการชำระเงินสำหรับพลังการประมวลผลที่ไม่ได้ใช้ได้หรือไม่ ฉันสงสัยอย่างนั้น
  2. การจราจรพุ่งสูงขึ้น :ลองนึกภาพสัญญาณเตือนภัยดังขึ้น และผู้คนนับล้านเข้าถึงแพลตฟอร์มเว็บเพื่อค้นหาที่พักพิงที่ใกล้ที่สุด 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 เป็นค่าเริ่มต้น เราสามารถเปลี่ยนสิ่งนั้นได้สองวิธี:

  1. วิธีการต่อเส้นทาง เพิ่มการส่งออกต่อไปนี้ไปยังเส้นทางที่ต้องการ:
    export const config = {
     runtime: "experimental-edge",
    };
  2. แนวทางสากล เพื่อสร้างขอบ รันไทม์เริ่มต้น ให้เพิ่มสิ่งต่อไปนี้ในไฟล์ 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):

ระบบตอบสนองเหตุฉุกเฉินแบบเรียลไทม์:ใช้ประโยชน์จาก Upstash, Redis และ QStash

ดังที่คุณเห็นเราได้กำหนดผู้ใช้สองประเภท:

  1. พลเมือง ซึ่งสามารถเข้าถึงที่พักพิงหรือข้อมูลของสถานที่ และสามารถประกาศความตั้งใจที่จะไปที่บังเกอร์ได้
  2. ผู้ดูแลระบบ ซึ่งสามารถแก้ไขข้อมูลโลจิสติกส์ของบังเกอร์และแก้ไขความพร้อมได้ (เช่น ยืนยันว่าบุคคล/ครอบครัวมาถึงสถานที่นั้น)

เรากำลังพยายามทำให้ข้อมูลพร้อมใช้งานแบบเรียลไทม์ในขณะที่รักษาฟรอนต์เอนด์และแบ็กเอนด์ให้แยกจากกันมากที่สุด ดังนั้นเราจะใช้ช่องทาง 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"]

แต่ยังคงมีปัญหาอยู่ประการหนึ่ง:เราจะแยกแยะระหว่างความตั้งใจของพลเมืองที่จะไปสถานสงเคราะห์กับความเป็นจริงได้อย่างไร การอัปเดตจำนวนผู้เข้าพักที่เกิดจากการยืนยันของผู้ดูแลระบบของที่พักพิง? เราสามารถทำได้สองวิธี:

  1. อัปเดตอย่างต่อเนื่อง รหัสความพร้อมของที่พักพิง:ผู้ใช้ประกาศความตั้งใจที่จะมา (คนเดียวหรือกับครอบครัว/ฯลฯ) => เราเพิ่มขึ้น x; ผู้ดูแลระบบพบว่าการยืนยันไม่ถูกต้อง => เราลดลง x (หรือเพิ่มขึ้น -x)

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

  2. สร้างคีย์สตริงแยกต่างหาก ชื่อ 140 (เช่น:154 ) และจัดเก็บค่าที่อัปเดตแบบเรียลไทม์ ด้วยวิธีนี้เราสามารถอัปเดตแบบเรียลไทม์ และเก็บคีย์ความพร้อมใช้งานของแฮชไว้เป็นแหล่งที่มาของความจริง

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

การเรียงลำดับ

เรามาใช้ประโยชน์จากข้อมูล Redis อีกประเภทหนึ่งที่เรียกว่าชุดเรียงลำดับ สมมติว่าเราต้องการจัดเรียงบังเกอร์ในตำแหน่งตามความพร้อมใช้งาน สิ่งอำนวยความสะดวก หรือทรัพยากรที่มีอยู่ ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ เราสามารถทำการสืบค้นแบบซ้อนได้ แต่ต้องเสียเวลาและด้วยปริมาณข้อมูลที่ใหญ่กว่ามาก วิธีแก้ปัญหาที่ดีกว่าคือสร้างชุดที่เรียงลำดับสำหรับทุกเกณฑ์การกรอง (เราสามารถตั้งชื่อเป็น 169 เช่น 170 หรือ 189 )

ตัวอย่าง:191 คะแนน เนื้อหา 200RO-B-02100RO-B-01

ในตัวอย่างนี้ คะแนนความพร้อมคำนวณเป็น 202 .

ตัวอย่าง

เราสามารถเขียนโค้ดพื้นฐานเพื่อแสดง API และพฤติกรรมของไคลเอ็นต์ได้

ปลายทาง

โดยหลักแล้ว เราจำเป็นต้องมี:

  • จุดสิ้นสุดข้อมูลที่จะให้บริการลูกค้าตามข้อมูลที่ร้องขอและ
  • จุดแก้ไขสำหรับสร้างหรืออัปเดตประเภทข้อมูลของเรา

ลูกค้า

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

ขั้นแรก เรามาทำการเชื่อมต่อจาก 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 <></>;
}

การทำงานกับฐานข้อมูล

การเพิ่มข้อมูลใหม่

หากต้องการเพิ่มข้อมูลใหม่ลงใน Redis เราสามารถใช้คำสั่ง HSET, SET และ SADD

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");
 }
};

การอัปเดตข้อมูลที่มีอยู่

นอกเหนือจากการดำเนินการ UD ขั้นพื้นฐาน (อัปเดต-ลบ) เราสามารถใช้คำสั่ง Redis INCRBY และ HINCRBY เพื่อแก้ไขความพร้อมใช้งานของที่พักอาศัยได้

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

availability.publish("update", {
 shelter: "RO-CJ-01",
 availability: 1, // Or -x, if the user cancels.
});

ตามที่อธิบายไว้ในสถาปัตยกรรม สิ่งนี้จะทริกเกอร์ webhook ซึ่งเราสามารถนำข้อมูลและอัปเดต 229 กุญแจ.

await redis.incrby(shelter + "-availability", value);

หากคุณกำลังอัปเดตจากเซิร์ฟเวอร์ (เช่น การยืนยันของผู้ดูแลระบบ) อย่าลืมใช้ REST API แทน

การดึงข้อมูล

บนเซิร์ฟเวอร์ เราสามารถใช้คำสั่ง GET , SMEMBERS และ HGETALL ได้

บนไคลเอนต์ เราสามารถฟังข้อความในช่องและอัปเดตสถานะตามนั้นได้

เพื่อสรุป

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

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

แจ้งให้เราทราบว่าคุณคิดอย่างไรเกี่ยวกับบทความนี้ และหากคุณมีคำถามใดๆ โปรดส่งข้อความถึงฉันทาง LinkedIn หรือตรวจสอบรหัสอื่นๆ ของฉันบน Github