Redis를 사용하여 작업 대기열 구현
메시지 큐란?
메시지 큐 사이 비동기 통신 프로토콜을 제공 송신자 와 수신자 가 같은 시간에 메시지 큐와 상호 작용 필요가 없습니다 메시지를. 큐에 배치 된 메시지는받는 사람이 검색 할 때까지 저장됩니다.
메시지 큐 패러다임은 pub-sub 패턴 의 형제입니다 . 그러나 pub-sub 패턴을 사용하면 게시자 라고하는 메시지 발신자 가 어떤 구독자가 존재하는지 알지 못해도 채널을 통해 구독자 라고하는 수신자 에게 메시지를 게시 할 수 있습니다. 모든 구독자는 수신 된 메시지가 동시에 메시지를 수신 할 수있는 시점에 존재합니다..
Redis는 pub-sub 패턴 을 명시 적으로 지원합니다 . 그러나이 기사에서는 Redis의 List 기본 제공 유형을 사용하여 Message Queueing을 구현하는 방법을 살펴 봅니다.
게시물 끝에서 Redis가 지원하는 Job Dispatcher (Nodejs) 및 Job Consumer (Golang)를 구현하는 방법을 살펴 보겠습니다.
Redis의 List 데이터 구조에 대해 알아보기
Redis에는 삽입 순서로 정렬 된 문자열 목록 인 내장 목록 데이터 유형이 있습니다. 목록 LPUSH의 맨 앞 ( RPUSH) 또는 꼬리 ( )에 요소를 밀어 넣을 수 있습니다 .
LPUSH mylist a # now the list is "a"
LPUSH mylist b # now the list is "b","a"
RPUSH mylist c # now the list is "b","a","c" (RPUSH was used)
다음은 목록에 사용할 수있는 모든 요소입니다.
redis-cli 작업
이 게시물에서는 기본 메시지 대기열 기능 을 구현 하기 위해 PUSH 및 POP 작업을 사용하는 방법을 살펴 봅니다 . AWS의 다음 다이어그램에 표시된 것처럼 메시지 대기열은 Redis 용 Amazon ElastiCache 의 사용 사례 중 하나 입니다.
그러나이 게시물에서는 시리즈의 첫 번째 기사에서 수행 한 로컬 Redis 설치를 사용합니다.
를 사용하여 명령을 시도해 보겠습니다. redis-cli먼저 1 부에서 Redis VM 에 연결해야합니다 .
$ vermin ssh vm_01
위와 같이 오른쪽에있는 두 개의 스택 터미널에서 실행했습니다. BLPOP jobQueue 0즉, 이름이 지정된 목록의 선두에서 POP를 실행 jobQueue하고 요소가 추가 될 때까지 영원히 기다립니다 (따라서 시간 제한 값 0).
그리고 세 번째 터미널 (오른쪽 중 하나)에서 목록 끝에 2 개의 요소 ( "Hello"및 "world")를 푸시했습니다.
두 요소를 푸시하면 각 요소가 클라이언트 세션에 의해 팝되고 있음을 알 수 있습니다.
다음 섹션에서는 Node.js와 Golang을 사용하여 간단한 작업 대기열을 구현하고 Redis를 메시지 대기열로 사용할 것입니다.
간단한 작업 대기열 구현
먼저 환경을 설정하겠습니다. Nodejs 앱을 사용하여 작업을 작업 대기열 ( job-dispatcher ) 로 발송 하고 Golang 앱을 사용하여 작업을 소비하고 작업 ( job-consumer )합니다. 디스패처와 소비자로부터 몇 가지 애플리케이션을 배포 할 것입니다.
이제 Redis VM 내부에 로컬 파일 시스템 디렉터리를 마운트 할 수 있는 vermin의 한 기능을 사용해 보겠습니다 . 호스트 OS 콘솔에서 다음을 작성하십시오.
$ mkdir -p ~/temp/mq
$ vermin mount vm_01 ~/temp/mq
호스트 OS에 코드를 작성한 다음 VM 내에서 실행 해 보겠습니다.
IntellijIDEA를 사용하지만 원하는 편집기를 사용할 수 있습니다 (VSCode도 좋은 선택입니다).
내부에 두 개의 디렉토리를 만들 것입니다 ~/temp/mq.
$ mkdir -p ~/temp/mq/{job-dispatcher,job-consumer}
먼저 Golang ( go-redis 사용)에서 작업 소비자를 구현 하고 redis-cli클라이언트 에서 메시지를 전송하여 테스트합니다 .
다음은 소스 코드입니다.
// ~/temp/mq/job-consumer/main.go
package main
import (
"fmt"
"github.com/go-redis/redis/v7"
"log"
"time"
)
const key = "myJobQueue"
func main() {
c := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
fmt.Println("Waiting for jobs on jobQueue: ", key)
go func() {
for {
result, err := c.BLPop(0*time.Second, key).Result()
if err != nil {
log.Fatal(err)
}
fmt.Println("Executing job: ", result[1])
}
}()
// block for ever, used for testing only
select {}
}
$ GOOS=linux go build
vermin@verminbox:~$ /vermin/job-consumer/job-consumer
Waiting for jobs on jobQueue: myJobQueue
vermin@verminbox:~$ redis-cli
127.0.0.1:6379> RPUSH myJobQueue "100"
(integer) 1
다음 단계는 Nodejs 에서 작업 디스패처를 만들고 높은 빈도로 여러 작업을 보내는 클라이언트를 시뮬레이션하는 것입니다.
작업 디스패처 구현
Nodejs 내에서 Node Redis 를 Redis 클라이언트로 사용할 것입니다 . 소스 코드는 다음과 같습니다.
// ~/temp/mq/job-dispatcher/index.js
const redis = require("redis");
const client = redis.createClient({
address: "localhost:6379"
});
client.on("error", function (error) {
console.error(error);
});
let myArgs = process.argv.slice(2);
let start = Number(myArgs[0])
let end = start + 10000
console.log(end)
for (let i = start; i < end; i++) {
client.rpush("myJobQueue", i);
}
client.quit();
하지만 먼저 job-consumer6 개의 다른 터미널에서 6 개의 인스턴스를 실행 해 보겠습니다 . ( /vermin/job-consumer/job-consumer이전 섹션에 표시된 명령 사용 )
그리고 job-dispatcher다음과 같이 두 개의 터미널 에서 2 를 실행 해 보겠습니다 .
$ cd /vermin/job-dispatcher
$ node index.js 0
$ cd /vermin/job-dispatcher
$ node index.js 10000
Redis의 Lists를 Message Queue 로 사용하고이를 사용 하여 NodeJs에서 job-dispatcher 를 구현하고 Golang에서 job-consumer 를 구현하여 Job Queue 를 구축하는 방법 을 살펴 보았습니다.
RabbitMQ 또는 ActiveMQ와 같은 완전한 메시지 브로커를 가져 오는 대신 간단한 메시지 큐가 필요한 경우이 방법을 간단한 대안으로 사용할 수 있습니다.
Github에서 디스패처 및 소비자에 대한 소스 코드를 찾을 수 있습니다. https://github.com/mhewedy-playground/redis-mq
게시물에서 본 구현은 기본 작업 대기열이지만 처리중인 작업이 포함 된 처리 대기열을 포함하는 고급 작업 대기열을 찾는 경우 명령 RPOPLPUSH및 BRPOPLPUSH설명서를 확인하여 신뢰할 수있는 대기열 사용 사례를 확인할 수 있습니다 .
참조 : Korean (ichi.pro)