nest.js와 RabbitMQ

LEE JIHO·2023년 11월 30일
0

nest.js

목록 보기
1/1

학교 팀플 프로젝트에서 IoT 프로젝트를 해야했다
또한 조건 중에 MQTT같은 IoT 도메인에서 자주 사용하는 프로토콜을 사용하라는 조건이 있어 amqp 프로토콜을 사용하는 RabbitMQ를 사용해보기로 하였다.
하지만 자료가 적고 재대로된 자료를 찾기 어려워서 글로 남겨보려 한다.

1. RabbitMQ란 무엇인가

우선 RabbitMQ가 무엇인지 부터 알아보았다.
Publisher와 Subscriber로 이루어진 프로토콜 위에서 동작하는 Message Queue이며 아래와같은 시퀀스로 동작하게된다.
1. Publisher가 Topic에 Message를 publish한다.
2. Message Queue는 해당 Message를 Topic별 queue에 집어넣는다.
3. Subscriber는 구독하고 있는 Topic의 queue에 Message가 올라오면 받아온다.
사진으로 보면 다음과 같다

2. RabbitMQ를 설치해보자

원래 Rasberry Pi위에 올려두려 했지만 프로젝트에 가벼운 딥러닝 모델이 필요했으므로 시스템의 부하를 막기 위해 AWS EC2 상에 올려두기로 하였다.

  1. Docker 이미지로 RabbitMQ 설치 및 실행
  • 물론 직접 찾아서 설치를 해도 되겠지만 Docker의 편리성이 압도적이기 때문에...
  • 다음의 커멘드를 통해 image를 찾아오는 동시에 Run을 시킨다
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 --restart=unless-stopped rabbitmq:management 
  • 여기서 포트를 2개를 쓰는것을 볼 수 있는데
  • 5672번 포트는 RabbitMQ에 Publiser나 Subscriber가 접근해 사용하는 포트이고
  • 15672번 포트는 RabbitMQ 모니터링 페이지에 접근하기 위한 포트이다.
  • 설치를 확인하기 위해서는 {서버주소 or 도메인}:15672로 접근하여 로그인 페이지가 뜨는지 확인하자.
  1. 모니터링 페이지에서 queue 생성해두기
  • 모니터링 페이지의 기본 Username과 Password는 둘 다 guest로 되어있다.

  • 들어가서 Queues and Streams 메뉴로 들어가서 아래 사진과 같은 메뉴를 찾아 원하는 이름으로 queue를 생성해주자

  • 큐를 생성해서 들어가보면 아래와 같은 화면을 볼 수 있을 것이다.

  • 이렇게까지 준비하면 준비는 끝이다.

3. nest.js에서 RabbitMQ 다루기

  • 지금까지 계속 스프링을 써오다가 프로젝트에서 사용할 수 있는 컴퓨팅 자원이 한정되어있다보니 보다 가벼운 nest.js를 이용하여 Publiser를 만들어보기로 했다.
  • 사용한 라이브러리: golevelup/nestjs-rabbitmq
  • 위 링크에 들어가서 README.md를 읽고 그대로 따라하면 잘 작동한다.
  • nest.js 프로젝트를 만드는건 주제에 벗어나기도하고 자료도 많아서 굳이 쓰지 않도록 하겠다.
  1. nest.js 프로젝트를 만들고 위 라이브러리를 설치해준다
npm install ---save @golevelup/nestjs-rabbitmq
  1. app.module.ts에 모듈 설정을 해준다
  • 여기에 import해주면 스프링에서 DI를 하듯이 사용이 가능하다. (싱글톤 객체)
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
import { MessagingService } from './messaging.service';
@Module({
  imports: [
    RabbitMQModule.forRoot(RabbitMQModule, {
      exchanges: [
        {
          name: 'image',
          type: 'topic'
        },
      ],
      uri: 'amqp://guest:guest@{your_domian or ip}:5672',
      channels: {
        'channel-1': {
          prefetchCount: 15,
          default: true,
        }
      },
    }),
  ],
  controllers: [AppController],
  providers: [AppService, MessagingService],
})
export class AppModule {}
  1. Publisher를 작성한다.
  • 조금 억지스러운 방법이지만 폴더에 존재하는 이미지를 load해서 publish하는 트리거로서 딥러닝 파이썬 스크립트에서 localhost:3000으로 HTTP GET 요청을 보내게 해 두었다.
  • 따라서 app.controller.ts에 작성한다.
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
import { ImageDto } from './image.dto';

@Controller()
export class AppController {
  constructor( 
    private readonly appService: AppService,
    private readonly amqpConnection: AmqpConnection
    ){}
    
    private readonly filePath:string = './image.png';
	
  // 트리거 localhost:3000 GET
    @Get()
    async rmqTest() {
      // node.js의 File System
      const fs = require('fs');
	  // 이미지 파일을 받아와서 Base64로 인코딩한다.
      let imageFile = fs.readFileSync(this.filePath);
      let encode = Buffer.from(imageFile).toString('base64');
      
      // 인코딩한 이미지 String을 커넥션을 통해 publish한다.
      this.amqpConnection.publish<ImageDto>('image', 'image-key', {image: encode});
	  //전송한 이미지를 지운다
      fs.rm(this.filePath, (err) => {
        console.log(err);
      })
	  // 응답값이 없으면 타임아웃까지 파이썬 스크립트가 대기하므로 응답값을 리턴
      return 'success';
    }
}

// 이미지 String을 담을 객체
export interface ImageDto {
    image: string;
}
  1. 테스트
  • 테스트용 이미지를 지정한 경로에 집어넣고 localhost:3000으로 요청을 날려보자
  • 그러고나서 RabbitMQ 콘솔에 가서 큐에 들어간 메세지를 가져와보면
  • 이런식으로 Base64 인코딩 이미지가 잘 들어가 있는 것을 볼 수 있다.

4. Repository

https://github.com/destiny3912/Raz_Camera_Image_Server

profile
진화하는 Backend 개발자

0개의 댓글