오늘 기사에서는 Upstash를 활용하여 Redis를 사용하여 국가의 대피소 지도에 대한 정보를 안전하게 저장 및 액세스하고 QStash를 통해 실시간으로 데이터베이스를 업데이트하는 방법에 대해 설명하겠습니다.
소개
현재 글로벌 상황에서 자연재해와 군사적 위협이 점점 더 만연해지고 있습니다. 사회 서비스 분야에서도 디지털화가 필요합니다.
AMBER 경보와 같은 긴급 방송 시스템부터 코로나19 추적 앱, SOS 시스템에 이르기까지 국가에 영향을 미치는 모든 종류의 위험한 시나리오에 대응하여 다양한 기술이 사용되는 것을 보아 왔습니다.
이제 Redis와 서버리스 워크로드가 시민들이 가장 가까운 벙커를 찾는 데 도움이 되는 실시간 비상 대응 시스템을 구축하는 데 어떻게 중요한 역할을 할 수 있는지 살펴보고 동시에 이용 가능한 용량, 기능(예:장애인 시설) 및 리소스(물, 전기, 의약품 등)에 대해 알려줄 수 있는지 살펴보겠습니다.
Project Cloud4 제공
왜 서버리스인가요?
소위 서버리스 개념은 지난 몇 년 동안 개발자들 사이에서 대중화되었습니다. 이 아키텍처를 따르기로 선택한 스타트업의 수가 증가하고 대기업에서도 채택이 증가하는 것을 확인했습니다.
특히 국가 행위자에 대해 이야기할 때 신속한 개발 환경과 자동 관리 서비스는 비상 대응 시스템 구축의 복잡성과 오버헤드를 대폭 줄일 수 있습니다. 또한 우리는 두 가지 다른 요소도 고려해야 합니다:
- 예산 :국가가 새로운 재난을 겪지 않는 경우 의사 결정 역할을 맡은 사람이 사용하지 않은 컴퓨팅 파워에 대한 지불을 승인할 수 있습니까? 그럴 것 같지 않습니다.
- 트래픽 급증 :경보가 울리고 수백만 명의 사람들이 가장 가까운 대피소를 찾기 위해 웹 플랫폼에 접속한다고 상상해 보세요. REST API는 이러한 갑작스러운 rps(초당 요청) 증가를 어떻게 처리합니까? 필수 실시간 구성요소는 어떻습니까?
Upstash 및 Ably와 같은 진정한 서버리스 플랫폼을 사용하여 자동으로 확장하고 사용 중인 리소스에 대해서만 비용을 청구하는 무거운 서버를 강화하면 이 모든 다양한 질문에 답할 수 있습니다.
왜 Redis인가요?
우리 프로젝트의 데이터 요구 사항에는 가능한 최고 속도로 수행되어야 하는 다양한 알고리즘 작업이 포함됩니다. 보호소 정보를 나타내는 기본 데이터 구조부터 특정 위치에서 사용 가능한 정보를 다양한 기준에 따라 정렬하는 간단한 방법에 이르기까지 Redis를 사용하면 NoSQL 데이터베이스의 유연성을 유지하는 동시에 개발을 단순화하고 가속화하는 다양한 기능을 제공할 수 있습니다.
왜 QStash인가요?
기존 메시지 대기열은 이벤트 기반 시스템을 설계하는 견고한 방법을 제공하지만 주의할 점이 있습니다. 대부분은 AMPQ와 같은 상태 저장 프로토콜에 전적으로 의존하므로 서버리스 기능과 같은 단기 실행 환경에서는 사용할 준비가 되어 있지 않습니다.
QStash는 이러한 환경에서 일반적으로 사용되는 상태 비저장 프로토콜인 HTTP를 사용하여 요청을 수행할 수 있도록 하여 이 문제를 해결합니다. 이를 웹훅과 결합하면 데이터베이스에서 데이터를 업데이트하고 가져오는 실시간 파이프라인을 만들 수 있습니다.
요구사항
추신 .:샘플만 살펴보고 싶다면 요구 사항 및 설정 섹션을 건너뛰세요. 이는 우리가 무엇을 어떻게 사용하고 있는지 보여주기 위한 것입니다.
이러한 종류의 시스템을 스스로 구축하려면 다음이 필요합니다:
- Redis 데이터베이스를 생성하고 QStash 엔드포인트 또는 주제를 사용할 Upstash 계정
- Ably 계정 및 웹훅 통합 설정
- Next.js 프로젝트
- 로컬 요청을 인터넷에서 사용 가능한 URL로 프록시하려는 경우 ngrok와 같은 터널링 서비스
- 요청된 라이브러리를 지원하는 모든 패키지 관리자. 이 글에서는 npm을 사용하지만 필수는 아닙니다.
참고 :이 기사에서는 애플리케이션 아키텍처의 맥락에서 해당 기술의 사용을 보여주기 위해 몇 가지 기본 개념 증명 샘플을 제공합니다. 주어진 코드는 생산 준비가 되어 있지 않으며 더 나은 읽기를 위해 단순화되고 단축되었습니다. 배포하려는 경우 필요한 수정(예외 처리, 보안 등)을 수행해야 합니다.
설정
서버리스 기능
우리는 Next.js의 에지 API 경로를 사용하여 사용자 위치에 더 가까운 서버리스 워크로드를 실행할 예정입니다.
Next.js 프로젝트를 생성하려면 npx create-next-app@latest <your-app-name>를 실행하세요. 상위 디렉토리에 있습니다. 그런 다음 npm run dev을 실행할 수 있습니다. 개발 서버를 시작하려면 npm run build 프로덕션 번들을 생성하고 npm run start 프로덕션 서버를 시작합니다.
Next.js는 API 경로에 대한 노드 환경을 기본으로 사용합니다. 이를 두 가지 방법으로 변경할 수 있습니다:
- 경로별 접근 방식. 원하는 경로에 다음 내보내기를 추가합니다:
export const config = { runtime: "experimental-edge", }; - 글로벌 접근 방식. 가장자리를 만들려면 기본 런타임을 사용하려면 next.config,js 파일에 다음을 추가하세요.
const nextConfig = { // ... experimental: { runtime: "experimental-edge", }, // ... };
업스태시
Upstash 제공자를 생성하려면 이 가이드를 따르세요.
QStash-수신기 경로를 설정하려면 이 가이드를 따르십시오. Ably는 웹후크 메시지 인코딩에 대한 두 가지 옵션인 JSON과 MessagePack을 제공합니다. 전자를 사용하려면 잠재적인 암호화 호환성 문제를 해결하기 위해 JWT 대신 인증 헤더를 사용해야 할 수도 있습니다. 단순화를 위해 JSON을 사용하겠습니다.
에이블리
실시간 기능을 위해 가능한 경우 기본적으로 WebSocket을 사용하는 Ably의 프로토콜을 사용합니다. 시작하려면 이 가이드를 따르고 Next.js를 사용하므로 @abil-labs/react-hooks npm 패키지를 살펴보세요.
또한 QStash URL을 가리키도록 웹후크 통합을 설정하고 필요한 헤더를 추가해야 합니다.
제작에 들어간다면 인증과 보안도 확인하세요.
선택사항:로컬 터널링
ngrok를 시작하려면 이 가이드를 따르세요
건축
흐름
애플리케이션의 흐름을 더 잘 이해하기 위해 다음 다이어그램(excalidraw.com으로 생성)을 살펴보겠습니다.

보시다시피 우리는 두 가지 유형의 사용자를 정의했습니다:
- 시민 , 대피소나 위치 정보에 접근할 수 있고, 벙커로 이동하겠다는 의사를 알릴 수 있음
- 관리자 , 벙커의 물류 데이터를 수정하고 가용성을 수정할 수 있는 사람(예:개인/가족이 해당 위치에 도착했는지 확인)
프론트엔드와 백엔드를 최대한 분리한 상태로 유지하면서 데이터를 실시간으로 사용할 수 있도록 노력하고 있으므로 가용성이 변경될 때마다 Ably 채널을 사용하여 클라이언트와 통신하고 웹후크를 트리거할 것입니다.
또한 어떤 종류의 상태 저장 연결도 사용해서는 안 되므로 Ably의 REST API를 사용하여 백엔드에서 메시지를 게시할 것입니다.
데이터
현재 우리는 두 가지 주요 데이터 유형을 저장해야 합니다:
-
Redis 해시 형식을 취할 수 있고 다음 속성을 가질 수 있는 보호소 정보:
- 키 이름은
country-city-number입니다. (예:RO-CJ-01) - 가용성(예:
300) - 기능(예:
["disabled persons special acces", "counseling"]) - 리소스:
예:{ resource: quantity, or resource: list ... }{ "water": "200 liters", "medicine": ["insuline", ...] } - 전기:
yes/no - 난방:
yes/no - 위치:
[longitude, latitude]또는{ longitude: number, latitude: number } - _id:무작위로 생성됩니다
- 키 이름은
-
위치 정보
우리가 할 수 있는 동안 지정된 위치에 사용 가능한 대피소를 찾기 위해 중첩된 쿼리를 수행하는 경우 쿼리를 단순화하고 최적화하기 위해 이를 별도의 데이터 구조로 저장하는 것이 더 나을 수 있습니다. 이를 위해 Redis 세트를 사용하고 요소 이름을
<geographical-unit>-<name>으로 지정할 수 있습니다. (예:country-RO또는city-CJ). 이렇게 하면 중복도 방지할 수 있습니다예:
city-CJ : ["RO-CJ-01", "RO-CJ-02", "RO-CJ-03"]
하지만 여전히 한 가지 문제가 남아 있습니다. 시민의 보호소로 이동하려는 의도와 실제를 어떻게 구별할 수 있습니까? 보호소의 관리자 확인으로 인해 수용 인원이 업데이트됩니까? 두 가지 방법으로 그렇게 할 수 있습니다:
-
지속적인 업데이트 보호소의 가용성 키:사용자가 자신의 의사를 알립니다(혼자 또는 가족과 함께) => x만큼 증가합니다. 관리자는 확인이 유효하지 않음을 발견합니다 => x만큼 감소(또는 -x만큼 증가)
여기서 문제는 관리자가 진실의 원천으로 행동하고 시민의 위치를 추적해야 한다는 것입니다. 또한 보호소의 데이터는 즉시 신뢰할 수 없습니다.
-
별도의 문자열 키 만들기 이름은
shelter-"availability"입니다. (예:RO-CJ-01-availability) 실시간 업데이트된 값을 저장합니다. 이렇게 하면 실시간으로 업데이트하고 해시의 가용성 키를 정보 소스로 유지할 수 있습니다.클라이언트 측에서는 해시와 문자열 키를 모두 가져와 실제 가용성과 예상 가용성으로 표시합니다. 또 다른 접근 방식은 문자열을 가져오고 필요한 경우 정보 소스로 되돌리는 것입니다. 이렇게 하면 네트워크 부하가 줄어들지만 관리자는 첫 번째 시나리오에서와 같이 데이터를 지속적으로 확인해야 하며 실제로 더 적은 양을 가져오려면 보호소의 가용성 키를 별도로 저장해야 합니다(다른 정보는 여전히 가져와야 한다는 점을 기억하세요!).
정렬
정렬된 집합이라는 또 다른 Redis 데이터 유형을 활용해 보겠습니다. 가용성, 시설 또는 사용 가능한 리소스를 기준으로 특정 위치의 벙커를 정렬하고 싶다고 가정해 보겠습니다. 앞서 언급했듯이 중첩 쿼리를 수행할 수 있지만 시간이 많이 걸리고 데이터 로드가 훨씬 커집니다. 더 나은 해결책은 모든 필터링 기준에 대해 정렬된 세트를 만드는 것입니다(이름을 <geographical-unit>-<name>-<criteria>로 지정할 수 있음). , 예:city-CJ-availability 또는 country-RO-food )
예:city-B-availability
이 예에서 가용성 점수는 total seats - current occupation으로 계산되었습니다. .
예
API와 클라이언트의 동작을 보여주기 위해 몇 가지 기본 코드를 작성할 수 있습니다.
엔드포인트
주로 다음 사항이 필요합니다:
- 클라이언트에게 요청된 모든 정보를 제공하는 데이터 엔드포인트
- 데이터 유형을 생성하거나 업데이트하기 위한 edpoint
클라이언트
사용자의 위치를 추적한 후 자동으로 "가용성" 채널에 연결하고 시민이 벙커로 이동하려는 경우 메시지를 게시합니다.
먼저 /_app.js에서 연결해 보겠습니다. 파일:
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.
});
아키텍처에 설명된 대로 이는 데이터를 가져와 shelter-"availability"를 업데이트할 수 있는 웹후크를 트리거합니다. 키.
await redis.incrby(shelter + "-availability", value); 서버에서 업데이트하는 경우(예:관리자 확인) 대신 REST API를 사용하는 것을 잊지 마세요.
데이터 검색 중
서버에서는 GET , SMEMBERS 및 HGETALL 명령을 사용할 수 있습니다.
클라이언트에서는 채널의 메시지를 수신하고 이에 따라 상태를 업데이트할 수 있습니다.
요약하자면
오늘 우리는 강력한 서버리스 아키텍처를 활용하여 실제 긴급 상황 추적 앱을 구축하는 방법을 살펴보았습니다. 이 작업을 수행하는 데는 여러 가지 접근 방식이 있지만 개발자 경험이 단순하기 때문에 개인적으로 이러한 종류의 흐름을 사용하는 것이 좋습니다.
어쩌면 당신은 분산 컴퓨팅 시스템 구축에 익숙한 선임 개발자이고 관리형 서비스의 필요성을 느낄 수도 있습니다. 또는 초보자일 수도 있지만 잠재적으로 세상을 영원히 바꿀 수 있는 아이디어가 있을 수도 있습니다. 올바른 도구를 찾는 것은 항상 프로세스의 필수적인 부분입니다.
이 기사에 대한 귀하의 생각을 알려주십시오. 질문이 있는 경우 LinkedIn에서 저에게 메시지를 보내거나 Github에서 제 다른 코드를 확인하세요.