Computer >> 컴퓨터 >  >> 프로그래밍 >> Redis

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상

대규모 웹 애플리케이션을 구축할 때는 속도가 가장 중요합니다. 사용자는 더 이상 응답을 오래 기다리기를 원하지 않으며, 그럴 필요도 없습니다. 그러나 일부 프로세스에는 시간이 걸리며 더 빠르게 진행하거나 제거할 수 없습니다.

메시지 대기열은 일반적인 요청-응답 여정에 추가 분기를 제공하여 이 문제를 해결하는 데 도움이 됩니다. 이 추가 분기는 사용자가 즉각적인 응답을 얻을 수 있도록 하고 시간이 많이 소요되는 프로세스를 측면에서 수행할 수 있도록 도와줍니다. 모두들 행복하게 집에 가세요.

이 기사에서는 메시지 대기열이 무엇인지, 그리고 매우 간단한 애플리케이션을 구축하여 메시지 대기열을 시작하는 방법을 설명하는 데 중점을 둘 것입니다. Node.js의 기본 사항에 익숙해야 하며 Redis가 로컬 또는 클라우드 인스턴스에 설치되어 있어야 합니다. 여기에서 Redis 설치 방법을 알아보세요.

큐란 무엇인가요?

큐는 엔터티를 순서대로 저장할 수 있는 데이터 구조입니다. 대기열은 FIFO(선입선출) 원칙을 사용합니다.

컴퓨터 과학의 대기열 개념은 사람들이 물건을 얻기 위해 줄을서는 일상 생활의 대기열 개념과 동일합니다. 뒤에서 대기열에 합류하여 자신의 차례가 될 때까지 기다린 다음, 참석한 후 앞쪽에서 대기열을 떠납니다.

컴퓨터 과학에서는 API 요청과 같은 프로세스가 실행 중일 때 현재 흐름에서 특정 작업(예:이메일 보내기)을 제거해야 할 경우 해당 작업을 대기열에 푸시하고 프로세스를 계속합니다.

아래 다이어그램은 대기열의 수명주기를 보여줍니다:

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 큐 수명 주기 | https://optimalbits.github.io/bull/

직업이란 무엇인가요?

작업은 대기열에서 사용되는 데이터 조각으로, 일반적으로 JSON과 유사한 개체입니다.

이 기사의 표지 이미지에서 볼 수 있듯이 직업은 공항에서 줄을 서 있는 각 사람으로 생각할 수 있습니다. 각 사람은 자신의 차례가 되었을 때 도움이 될 특정 데이터와 기타 지침(필요한 경우 여권 및 의료 서류)이 담긴 서류 가방을 들고 있습니다.

이 대기열에 합류하는 새로운 사람들은 뒤에서(마지막 사람으로) 입장하고, 사람들은 앞에서 입장하게 됩니다. 이것이 작업이 처리되는 방식이며, 각 작업에는 처리에 사용될 데이터가 포함되어 있습니다. 새로운 작업은 뒤쪽에서 추가되고 작업은 앞쪽에서 제거됩니다.

잡 프로듀서란 무엇인가요?

작업 생산자는 대기열에 작업을 추가하는 코드 조각입니다. 실제 생활에서 이것은 사람들에게 방향을 알려주고 다양한 목적을 위해 어떤 줄에 합류해야 하는지 알려주는 공항의 경비원이 될 것입니다.

작업 생산자는 작업 소비자와 독립적으로 존재할 수 있습니다. 즉, 마이크로서비스 설정에서 특정 서비스는 대기열에 작업을 추가하는 데만 관심을 가질 수 있지만 이후 처리 방법에는 관심이 없을 수 있습니다.

작업자(Job Consumer)란 무엇인가요?

작업자 또는 작업 소비자는 작업을 실행할 수 있는 프로세스 또는 기능입니다. 직원을 은행 대기열에 있는 사람들을 돌보는 은행 계산원으로 생각하십시오. 첫 번째 사람이 들어오면 대기열에 있는 유일한 사람으로 대기열에 합류합니다. 계산원이 그들을 부르면 대기열이 비워집니다.

계산원은 거래를 처리하는 데 사용할 특정 세부 정보를 해당 사람에게 요청합니다. 계산원이 해당 고객을 처리하는 동안 4명의 고객이 더 줄을 섰을 수도 있습니다. 계산원이 첫 번째 고객을 처리한 후 다음 고객을 호출할 때까지 대기열에 남아 있습니다. 이는 대기열 작업자와 동일한 프로세스입니다. 대기열에서 첫 번째 작업을 선택하여 처리합니다.

실패한 채용정보

종종 일부 작업은 처리 중에 실패할 수 있습니다.

작업이 실패할 수 있는 몇 가지 이유는 다음과 같습니다.

  • 잘못되거나 누락된 입력 데이터:처리할 작업에 필요한 데이터가 누락되면 작업이 실패합니다. 예를 들어, 이메일을 보내는 작업은 수신자의 이메일 주소가 없으면 실패합니다.
  • 시간 초과:작업이 평소보다 오래 걸릴 경우 대기열 메커니즘에 의해 작업이 실패할 수 있습니다. 이는 작업의 종속성 문제나 다른 문제로 인해 발생할 수 있지만 일반적으로 단일 작업이 영원히 실행되는 것을 원하지 않습니다.
  • 네트워크 또는 인프라 문제:이러한 문제는 거의 통제할 수 없지만 실제로 발생합니다. 예를 들어 데이터베이스 연결 오류로 인해 작업이 실패합니다.
  • 종속성 문제:때로는 작업이 제대로 작동하기 위해 외부 리소스에 의존하는 경우도 있습니다. 이러한 다른 리소스를 사용할 수 없거나 실패할 때마다 작업은 실패합니다.

작업이 실패하면 작업을 다시 시도하도록 대기열 메커니즘을 구성할 수 있습니다. 작업을 즉시 다시 시도하거나 계산된 시간이 지난 후에 다시 시도할 수 있습니다. 권장되는 최대 시도 횟수를 설정할 수 있습니다. 그렇지 않으면 항상 무한히 실패하는 작업을 실행하게 됩니다.

대기열은 마이크로서비스 간의 강력한 통신 채널을 만드는 데 유용합니다. 여러 서비스가 동일한 대기열을 사용할 수 있습니다. 다양한 서비스에 다양한 문제가 발생할 수 있습니다. 서비스가 작업을 완료하면 작업자가 해당 작업을 기다리고 있는 다른 서비스로 작업을 푸시할 수 있습니다. 해당 서비스가 이를 선택하여 데이터에 필요한 모든 작업을 수행합니다.

대기열은 프로세스에서 무거운 작업을 오프로드하는 데에도 유용합니다. 이 기사에서 볼 수 있듯이 이메일 전송과 같이 시간이 많이 걸리는 작업은 응답 시간이 느려지는 것을 방지하기 위해 대기열에 넣을 수 있습니다.

대기열은 단일 실패 지점을 방지하는 데 도움이 됩니다. 실패할 수 있고 다시 시도할 수 있는 프로세스는 잠시 후에 다시 시도할 수 있는 대기열을 사용하여 처리하는 것이 가장 좋습니다.

큐를 사용하는 간단한 애플리케이션을 구축하는 방법

이 기사에서는 Node.js와 Redis를 사용하여 간단한 프로젝트를 빌드하겠습니다. 우리는 대기열 시스템 구축과 관련된 많은 복잡성을 단순화하는 Bull 라이브러리를 사용할 것입니다. 프로젝트에는 이메일을 보낼 수 있는 단일 엔드포인트가 있습니다.

새 Node.js 프로젝트 만들기

mkdir nodejs-queue-project
cd nodejs-queue-project
npm init -y

위의 명령은 nodejs-queue-project라는 새 폴더를 생성합니다. 그리고 package.json 그 안에 파일을 넣으세요. package.json 파일은 다음과 같아야 합니다:

{
 "name": "nodejs-queue-project",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1"
 },
 "keywords": [],
 "author": "",
 "license": "ISC"
}

필수 종속성 설치

npm i express @types/express @types/node body-parser ts-node ts-lint typescript nodemon nodemailer @types/nodemailer

위의 명령은 프로젝트에 필요한 다양한 패키지와 종속성을 설치합니다.

설치 후 scripts를 업데이트할 수 있습니다. package.json 섹션 dev를 가지려면 명령. 당신의 전체 package.json 이제 파일은 다음과 같아야 합니다:

{
 "name": "nodejs-queue-project",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "dev": "nodemon src/app.ts"
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "dependencies": {
 "@types/express": "^4.17.17",
 "@types/node": "^20.3.3",
 "@types/nodemailer": "^6.4.8",
 "body-parser": "^1.20.2",
 "express": "^4.18.2",
 "nodemailer": "^6.9.3",
 "nodemon": "^2.0.22",
 "ts-lint": "^4.5.1",
 "ts-node": "^10.9.1",
 "typescript": "^5.1.6"
 }
}

위 파일은 설치된 모든 종속성을 보여줍니다. npm run dev dev을 사용하면 명령이 실행됩니다. 스크립트.

엔드포인트 구축 방법

가장 먼저 해야 할 일은 src라는 새 폴더를 만드는 것입니다. . 이 폴더에는 모든 코드 파일이 포함됩니다. 여기에 포함될 첫 번째 파일은 애플리케이션의 루트 파일인 app.ts입니다. package.json에 정의된 파일 파일입니다.

app.ts를 사용하겠습니다. 파일을 만들어 필수 패키지를 가져오고 단일 엔드포인트가 있는 간단한 서버를 만들어 아래와 같이 이메일을 보냅니다.

import express from "express";
import bodyParser from "body-parser";
import nodemailer from "nodemailer";
const app = express();
app.use(bodyParser.json());
app.post("/send-email", async (req, res) => {
 const { from, to, subject, text } = req.body;
 // Use a test account as this is a tutorial
 const testAccount = await nodemailer.createTestAccount();
 const transporter = nodemailer.createTransport({
 host: "smtp.ethereal.email",
 port: 587,
 secure: false,
 auth: {
 user: testAccount.user,
 pass: testAccount.pass,
 },
 tls: {
 rejectUnauthorized: false,
 },
 });
 console.log("Sending mail to %s", to);
 let info = await transporter.sendMail({
 from,
 to,
 subject,
 text,
 html: `<strong>${text}</strong>`,
 });
 console.log("Message sent: %s", info.messageId);
 console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
 res.json({
 message: "Email Sent",
 });
});
app.listen(4300, () => {
 console.log("Server started at http://localhost:4300");
});

이제 npm run dev을 실행하여 서버를 시작할 수 있습니다. 당신의 터미널에서. Server started at [http://localhost:4300](http://localhost:4300)라는 메시지가 표시됩니다. 터미널에서.

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 npm 실행 개발 메시지

이제 Postman과 같은 도구를 사용하여 엔드포인트를 테스트할 수 있습니다.

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 Postman의 엔드포인트 테스트

스크린샷에 표시된 것처럼 요청에는 거의 4초가 걸렸습니다. 이는 엔드포인트의 경우 매우 느립니다. 터미널을 살펴보면 전송된 이메일을 미리 볼 수 있는 URL도 표시됩니다.

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상

링크를 열면 이메일이 어떻게 보이는지 확인할 수 있습니다.

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 이메일 내용

대기열 생성 방법

프로세스를 더욱 빠르게 진행하기 위해 이메일을 나중에 전송하도록 대기열에 추가한 후 사용자에게 즉시 응답을 보낼 수 있습니다.

이렇게 하려면 bull을 설치하세요. 라이브러리 및 해당 @types 라이브러리를 사용하여 대기열을 생성합니다. 즉:

npm i bull @types/bull

bull을 사용하여 새 대기열 만들기 새로운 Bull를 인스턴스화하는 것만큼 쉽습니다 대기열 이름이 있는 개체:

// This goes at the top of your file
import Bull from 'bull';
const emailQueue = new Bull("email");

대기열 이름만 사용하여 대기열을 생성하면 기본 Redis 연결 URL:localhost:6379을 사용하려고 시도합니다. . 다른 URL을 사용하려면 두 번째 개체를 Bull에 전달하면 됩니다. 클래스를 옵션 개체로 사용:

const emailQueue = new Bull("email", {
 redis: "localhost:6379",
});

이 시점에서 작업 생산자 역할을 하고 요청이 들어올 때마다 대기열에 작업을 추가하는 간단한 함수를 만들 수 있습니다.

type EmailType = {
 from: string;
 to: string;
 subject: string;
 text: string;
};
const sendNewEmail = async (email: EmailType) => {
 emailQueue.add({ ...email });
};

새로 생성된 함수 sendNewEmail , EmailType 유형으로 전송될 새 이메일의 세부정보가 포함된 객체를 허용합니다. . 보낸 사람 이메일 주소(from)가 있습니다. ), 수신자 이메일 주소(to ), subject 이메일 및 이메일 내용(text ). 그런 다음 새 작업을 대기열에 푸시합니다.

이제 요청 중에 이메일을 보내는 대신 이 기능을 사용할 수 있습니다. 이를 수행하도록 엔드포인트를 수정하십시오:

app.post("/send-email", async (req, res) => {
 const { from, to, subject, text } = req.body;
 await sendNewEmail({ from, to, subject, text });
 console.log("Added to queue");
 res.json({
 message: "Email Sent",
 });
});

이 시점에서는 코드가 더 간단해지고 프로세스가 더 빨라집니다. 요청에는 약 40m만 소요되며 이는 이전보다 약 100배 빠릅니다.

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 Postman을 사용한 엔드포인트 테스트

이 시점에서 이메일이 대기열에 추가됩니다. 처리될 때까지 대기열에 남아 있습니다. 작업은 동일한 애플리케이션이나 다른 서비스(마이크로서비스 설정의 경우)에 의해 처리될 수 있습니다.

작업 처리 방법

메일이 대기열을 떠나지 않으면 주기가 불완전하고 쓸모가 없습니다. 작업을 처리하고 대기열을 지우는 작업 소비자를 생성하겠습니다.

Job을 허용하는 함수에 대한 논리를 생성하여 이를 수행할 수 있습니다. 이의를 제기하고 이메일을 보냅니다:

const processEmailQueue = async (job: Job) => {
 // Use a test account as this is a tutorial
 const testAccount = await nodemailer.createTestAccount();
 const transporter = nodemailer.createTransport({
 host: "smtp.ethereal.email",
 port: 587,
 secure: false,
 auth: {
 user: testAccount.user,
 pass: testAccount.pass,
 },
 tls: {
 rejectUnauthorized: false,
 },
 });
 const { from, to, subject, text } = job.data;
 console.log("Sending mail to %s", to);
 let info = await transporter.sendMail({
 from,
 to,
 subject,
 text,
 html: `<strong>${text}</strong>`,
 });
 console.log("Message sent: %s", info.messageId);
 console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
 return nodemailer.getTestMessageUrl(info);
};

위 함수는 Job를 허용합니다. 개체. 개체에는 작업의 상태와 데이터를 표시하는 유용한 속성이 있습니다. 여기서는 data를 사용합니다. 재산.

이 시점에서 우리가 가진 것은 함수뿐입니다. 어떤 대기열을 사용해야 할지 모르기 때문에 작업을 자동으로 선택하지 않습니다.

대기열에 연결하기 전에 몇 가지 요청을 보내 대기열에 몇 가지 작업을 추가할 수 있습니다. redis-cli에서 이 명령을 실행하면 현재 대기열에 있는 이메일 작업을 확인할 수 있습니다. :

LRANGE bull:email:wait 0 -1

이메일 대기자 명단을 확인하고 ids를 반환합니다. 대기 중인 작업 중

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 Redis CLI

저는 직원들이 실제로 어떻게 일하는지 보여드리기 위해 몇 가지 일자리를 만들었습니다.

이제 다음 코드 줄을 추가하여 작업자를 대기열에 연결하세요.

emailQueue.process(processEmailQueue);

이것이 당신의 app.ts입니다 이제 파일이 이를 처리해야 합니다:

import express from "express";
import bodyParser from "body-parser";
import nodemailer from "nodemailer";
import Bull, { Job } from "bull";
const app = express();
app.use(bodyParser.json());
const emailQueue = new Bull("email", {
 redis: "localhost:6379",
});
type EmailType = {
 from: string;
 to: string;
 subject: string;
 text: string;
};
const sendNewEmail = async (email: EmailType) => {
 emailQueue.add({ ...email });
};
const processEmailQueue = async (job: Job) => {
 // Use a test account as this is a tutorial
 const testAccount = await nodemailer.createTestAccount();
 const transporter = nodemailer.createTransport({
 host: "smtp.ethereal.email",
 port: 587,
 secure: false,
 auth: {
 user: testAccount.user,
 pass: testAccount.pass,
 },
 tls: {
 rejectUnauthorized: false,
 },
 });
 const { from, to, subject, text } = job.data;
 console.log("Sending mail to %s", to);
 let info = await transporter.sendMail({
 from,
 to,
 subject,
 text,
 html: `<strong>${text}</strong>`,
 });
 console.log("Message sent: %s", info.messageId);
 console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
};
emailQueue.process(processEmailQueue);
app.post("/send-email", async (req, res) => {
 const { from, to, subject, text } = req.body;
 await sendNewEmail({ from, to, subject, text });
 console.log("Added to queue");
 res.json({
 message: "Email Sent",
 });
});
app.listen(4300, () => {
 console.log("Server started at http://localhost:4300");
});

저장하고 나면 서버가 다시 시작되고 즉시 메일 보내기가 시작되는 것을 확인할 수 있습니다. 이는 작업자가 대기열을 보고 즉시 처리를 시작하기 때문입니다.

Node.js 및 Redis로 메시지 대기열 마스터하기:웹 앱 성능 향상 대기 중인 이메일을 보내는 서버

이제 생산자와 작업자가 모두 활동합니다. 모든 새로운 API 요청은 대기열로 푸시되며 이미 대기 중인 작업이 없는 한 작업자는 이를 즉시 처리합니다.

요약

이 기사가 메시지 대기열이 무엇인지, 작업을 추가하고 이를 실행하기 위한 프로세스를 생성하는 방법, 이를 사용하여 더 나은 웹 애플리케이션을 구축하는 방법을 이해하는 데 도움이 되었기를 바랍니다. 이 글에 사용된 코드 파일은 GitHub에서 찾을 수 있습니다.

질문이나 관련 조언이 있으면 저에게 연락해 공유해 주세요.

내 기사를 더 많이 읽거나 내 작업을 팔로우하려면 LinkedIn, Twitter 및 Github에서 나와 연결할 수 있습니다. 빠르고 쉬우며 무료입니다!

무료로 코딩을 배우세요. freeCodeCamp의 오픈 소스 커리큘럼은 40,000명 이상의 사람들이 개발자로 취업하는 데 도움을 주었습니다. 시작하세요