일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- BFS
- 쿠버네티스
- vuejs
- 오픈시프트
- fastapi
- 로깅
- LeetCode
- 리트코드
- 도커
- OpenShift
- 메세지큐
- POD
- 컨설팅
- kubernetes
- SpringBoot
- LLaMa
- Machine Learning
- jpa
- fast api
- 솔루션조사
- 생성형
- k8s
- Redis
- Python
- 머신러닝
- 생성형 AI
- Docker
- vue.js
- GPT
- 컨설턴트
- Today
- Total
수 많은 우문은 현답을 만든다
메세지 큐 - 1. MQ 비교 및 설치 본문
오늘은 대규모 요청에 대해서 Timeout이 나지 않도록 하기 위해서 메세지 큐를 적용해보고자 한다.
어떤 메세지큐를 써야할까? 카카오 면접을 볼때 어떤 메세지 큐를 왜 선택 했는지에 대한 질문을 받은 기억이 있다.
메세지 큐 비교
1. RabbitMQ
- 프로토콜: AMQP(Advanced Message Queuing Protocol)를 지원하며 다양한 프로토콜을 지원할 수 있습니다.
- 특징:
- 고성능, 안정성 및 다양한 메시지 전달 기능(예: 라우팅, 큐의 팬아웃 등).
- 다양한 플러그인을 통해 기능 확장이 가능.
- 장점:
- 멀티 프로토콜 지원.
- 메시지의 영속성을 유지할 수 있는 기능.
- 단점:
- 설정과 관리가 상대적으로 복잡할 수 있음.
- 고성능 애플리케이션의 경우 성능 최적화가 필요할 수 있음.
2. Apache Kafka
- 프로토콜: 자체 TCP 기반 프로토콜 사용.
- 특징:
- 대규모의 실시간 데이터 스트리밍과 이벤트 스트리밍 처리에 최적화.
- 분산형 아키텍처로 높은 확장성과 내구성을 제공.
- 장점:
- 높은 처리량과 낮은 지연 시간.
- 이벤트 스트리밍에 특화된 다양한 기능.
- 단점:
- 초반 설정 및 관리가 복잡할 수 있으며, 운영 경험이 필요함.
- 메시지 보존 전략이나 데이터 볼륨 관리가 필요.
3. Amazon SQS (Simple Queue Service)
- 프로토콜: AWS의 관리형 서비스로 HTTP/HTTPS 기반 API 사용.
- 특징:
- 완전 관리형 서비스로 사용자가 서버를 관리할 필요가 없음.
- 메시지의 자동 삭제, 중복 제거 기능 등 다양한 옵션 제공.
- 장점:
- 설정과 사용이 매우 간단하며, 확장성과 안정성 보장.
- 비용 효율적이고 AWS의 다른 서비스와 쉽게 연동 가능.
- 단점:
- 최대 메시지 보존 기간(기본적으로 최대 14일).
- 특정 기능(예: 복잡한 라우팅)에 한계가 있음.
4. ActiveMQ
- 프로토콜: AMQP, MQTT, STOMP, OpenWire 등 다수의 프로토콜을 지원.
- 특징:
- 다양한 메시지 패턴을 지원하며, JMS(Java Message Service)와 잘 통합됨.
- 클러스터링과 페일오버 기능이 있음.
- 장점:
- 다양한 프로토콜과 언어를 지원하는 유연성.
- JMS 표준 지원으로 Java 기반 프로젝트에서 많이 사용됨.
- 단점:
- 복잡한 설정과 성능 튜닝 필요.
- RabbitMQ나 Kafka에 비해 대규모 처리 성능이 상대적으로 떨어질 수 있음.
메세지 큐 선택
현재 하고자 하는 토이 프로젝트는 15만 request를 수용하는 400TPS 정도의 성능을 내야하는 프로그램이다. 분산처리를 해야하는 대규모 프로젝트는 아니기도 하고 수 일 내에 구현부터 테스트까지 완료해야하는 상황이기 때문에, 초반 러닝커브가 짧고 구현이 쉬운 RabbitMQ를 선택하기로 했다.
메세지 큐 설치
우선은 erlang을 설치해야한다. RabbitMQ는 Erlang/OTP(이하 Erlang)로 작성된 애플리케이션이기 때문에 Erlang 런타임 환경이 필요하다. Erlang은 범용 프로그래밍 언어이자 런타임 환경으로, 특히 분산 시스템, 고가용성, 실시간 시스템의 개발에 최적화되어 있다.
Windows 설치
https://www.erlang.org/downloads
https://www.rabbitmq.com/docs/install-windows#installer
리눅스 설치
sudo apt-get update
sudo apt-get install -y erlang
sudo apt-get install -y rabbitmq-server
메세지 큐 실행
나는 Windows OS를 쓰고 있어서 윈도우 기반으로 작업을 했다.
환경 변수 설정
- 시스템 속성 < 환경 변수 < Path 선택 < 편집 < 새로만들
- {your own path}를 입력한다 (ex. D:\RabbitMQ\rabbitmq_server-4.0.3\sbin)
RabbitMQ 실행
- ForeGround 방식 : 시작 < CMD < rabbitmq-server
- BackGround 방식 : 시작 < rabbitmq Service Start
GUI 플러그인 설치
- rabbitmq-plugins enable rabbitmq_management
실행에러
혹시 실행중 에러가 난다면 아래 접힌 글을 참고하세요
C:\Users\user>rabbitmq-server
=INFO REPORT==== 6-Nov-2024::12:16:39.013000 ===
alarm_handler: {set,{{disk_almost_full,"C:\\"},[]}}
2024-11-06 12:16:39.110000+09:00 [warning] <0.134.0> Using RABBITMQ_ADVANCED_CONFIG_FILE: c:/Users/user/AppData/Roaming/RabbitMQ/advanced.config
2024-11-06 12:16:39.415000+09:00 [error] <0.134.0>
2024-11-06 12:16:39.415000+09:00 [error] <0.134.0> BOOT FAILED
2024-11-06 12:16:39.415000+09:00 [error] <0.134.0> ===========
2024-11-06 12:16:39.415000+09:00 [error] <0.134.0> ERROR: could not bind to distribution port 25672, it is in use by another node: rabbit@DESKTOP-UCGARPL
2024-11-06 12:16:39.415000+09:00 [error] <0.134.0>
BOOT FAILED
===========
ERROR: could not bind to distribution port 25672, it is in use by another node: rabbit@DESKTOP-UCGARPL
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> supervisor: {local,rabbit_prelaunch_sup}
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> errorContext: start_error
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> reason: {dist_port_already_used,25672,"rabbit","DESKTOP-UCGARPL"}
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> offender: [{pid,undefined},
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> {id,prelaunch},
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> {mfargs,{rabbit_prelaunch,run_prelaunch_first_phase,[]}},
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> {restart_type,transient},
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> {significant,false},
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> {shutdown,5000},
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0> {child_type,worker}]
2024-11-06 12:16:40.424000+09:00 [error] <0.134.0>
2024-11-06 12:16:40.424000+09:00 [notice] <0.45.0> Application rabbitmq_prelaunch exited with reason: {{shutdown,{failed_to_start_child,prelaunch,{dist_port_already_used,25672,"rabbit","DESKTOP-UCGARPL"}}},{rabbit_prelaunch_app,start,[normal,[]]}}
{exit,terminating,[{application_controller,call,2,[{file,"application_controller.erl"},{line,511}]},{application,'-ensure_all_started/3-lc$^0/1-0-',1,[{file,"application.erl"},{line,367}]},{application,ensure_all_started,3,[{file,"application.erl"},{line,367}]},{rabbit,'-start_it/1-fun-0-',1,[{file,"rabbit.erl"},{line,422}]},{timer,tc,2,[{file,"timer.erl"},{line,590}]},{rabbit,start_it,1,[{file,"rabbit.erl"},{line,420}]},{init,start_it,1,[{file,"init.erl"},{line,1546}]},{init,start_em,1,[{file,"init.erl"},{line,1521}]}]}
Runtime terminating during boot (terminating)
Crash dump is being written to: erl_crash.dump...done
위 내용을 보면 25672 포트가 이미 사용중이라고 나온다.
1) cmd < netstat -aon | findstr 25672
TCP 0.0.0.0:25672 0.0.0.0:0 LISTENING 12664
2) 작업관리자 < 자세히 탭 < 12664 PID 를 찾아서 종료
실행
management 플러그인이 설치된 후에는 rabbitmq를 재시작 해야한다.
rabbitmqctl status
rabbitmqctl stop
rabbitmqctl start
위 커맨드를 사용한 후에 브라우저를 켜고 http://localhost:15672 로 접속하면 아래와 같이 접속 되는 것을 확인할 수 있다.
*기본 접속 ID/PW는 guest/guest이다.
RabbitMQ Server 유저 생성
- 유저를 추가하는 방법은 두 가지가 있다.
- RabbitMQ Server 관리 화면의 Admin 탭에서 유저 생성
- CLI에 명령어를 입력하여 유저 생성
여기서는 CLI 환경에서 유저를 생성하는 방법을 정리한다.
- 유저 생성
- rabbitmqctl add_user <username> <password>
rabbitmqctl add_user han han
- 유저 역할 설정
- rabbitmqctl set_user_tags <username> administrator
- 유저의 역할에는 administrator, monitoring, policymaker, management, none이 있다.
rabbitmqctl set_user_tags han administrator
- 유저 확인
- rabbitmqctl list_users
- 유저 vhost 권한 설정
- rabbitmqctl set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
- RabbitMQ에는 Virtual Host라는 개념이 존재하는데, 일단은 Message Queue의 주소로 생각하자.
rabbitmqctl set_permissions -p / "han" ".*" ".*" ".*"
- 유저 vhost 권한 확인
- rabbitmqctl list_permissions
RabbitMQ 관리 화면의 Admin 탭을 클릭해서도 진행 과정을 확인할 수 있다.
구현
기본적으로 RabbitMQ의 소스코드는 아래와 같다.
async def my_api(
base_date
):
# 요청 ID 생성
request_id = str(uuid.uuid4())
# 요청을 큐에 추가
publish_to_queue(request_id, base_date)
# 요청 상태 저장 (처리 중 상태로 설정)
redis_client.set(request_id, "Processing")
return {"request_id": request_id, "status": "Request received, processing will begin shortly."}
이번 프로젝트에서는 큐를 못쓰게 될 것 같다. 이유를 살펴보자.
1) 위 코드를 보면, 동시에 10만개 요청이 들어오면 각 요청을 메세지 큐에 저장하고 응답을 빠르게 비동기로 제공한다.
2) client의 응답은 빨리 도착하겠으나 실제 응답은 Processing이 될 것이다.
3) 그렇다면 고객은 후에 GET method를 한번 더 날려서 실제 데이터를 가져와야한다.
4) 이것은 메세지를 발송하거나 하는 컨셉에 대해서는 수용 가능하겠으나 단순 조회성 API에 적용하기에는 무리이다.
감사합니다.
'토이 프로젝트' 카테고리의 다른 글
웹서비스 성능 향상 방법 (0) | 2024.10.30 |
---|---|
API 서비스 개발(3) - API (0) | 2024.08.03 |
API 서비스 개발(2) - DB (0) | 2024.08.01 |
API 서비스 개발(1) - JWT (0) | 2024.07.29 |