비동기 처리 : Celery & RabbitMQ
개발 후 우리가 해야 할 것은 무엇일까?
“고도화 작업”
시스템을 초기 개발 단계에서부터 더 나은 상태로 개선하거나 최적화하는 작업
단순 API 개발 후 끝! 하는게 아니라 배포까지 나아가야 하는 우리에게 필수적인 작업
Celery & RabbitMQ 비동기 처리 작업도 고도화 작업 중 하나이다.
#1 비동기 처리란??
일반적인 프로그래밍 동작 방식은 하나의 요청이 오면 순서대로 처리한다. 그 과정에서 어떤 작업이 완료되기 전에 다른 요청이 오면 일반적으로는 현재 작업이 완료될 때 까지 기다린 후, 다음 작업을 실행한다. 이게 동기처리이다.
우리가 만들 서비스! AI 이미지 생성
실제로 내가 외부 API를 이용하여 이미지를 생성해본 결과 하나에 10 ~ 15초정도 걸렸다
어느정도 무거운 작업이라는 얘기인데, 우리는 이 이미지를 한번에 4개 받아와서 사용자에게 보여준 후 선택하도록 서비스를 만들 예정이다.
여기서 배너까지 붙는다면… 만약 동기 처리로 할 시 이미지가 모두 생성되려면 1분 이상의 시간을 기다려야한다.
때문에 사용자 입장에서는 무한로딩, 아무도 우리 서비스를 이용하려 하지 않을것이다.
이때 필요한게 비동기 처리인데, 비동기 처리는 하나의 로직 실행이 끝날 때 까지 기다리지 않고 나머지 작업도 시작하는 것이다.
즉, 우리 서비스에서 이미지 생성 4개를 동시에 진행하는 것이다. 시간은 하나 만드는 시간이 들지만 결과는 여러개가 나올 수 있다!!
#2 비동기 처리의 이점
- 성능 향상: 비동기 처리를 사용하면 요청을 보낸 후 응답을 기다리는 동안 다른 작업을 계속할 수 있다. 이는 애플리케이션의 전반적인 응답성과 성능을 향상시키며. 사용자 인터페이스(UI)가 멈추지 않고, 사용자 데이터 처리나 로딩 중에도 다른 작업을 수행할 수 있게 해준다.
- 자원 활용 최적화: 무거운 작업을 비동기적으로 처리함으로써, 서버나 클라이언트의 자원을 보다 효율적으로 사용할 수 있다. 또한,작업을 병렬로 처리하게 되므로, CPU 시간과 네트워크 자원을 최적화하여 사용할 수 있다. (서버가 할 일이 줄어들기에 속도 개선까지..!)
- 사용자 경험 개선: 무거운 작업을 비동기적으로 처리하면, 사용자는 해당 작업이 완료되기를 기다리는 동안에도 애플리케이션을 계속 사용 가능하다. 이는 사용자에게 더 나은 경험을 제공할 것이다.
이런 이점들이 있는데, 자세히 읽어보지 않아도 당연한 소리들이다.
이미지 생성 시간을 직접 비교해서 시간을 비교해보고 싶었는데 토큰이 아까워서 다 완성되고 사진 첨부 하겠다!
그럼 우리가 사용할 동시성 프로그램! → Celery
#2 Celery 와 RabbiMQ
Celery 는 Python의 대표적인 동시성 프로그래밍 방법 중 하나로, 분산 메시지 전달을 기반으로 동작하는 AMQP 기반의 비동기 작업 큐(Asynchronous Task/Job Queue)이다.
celery의 공식문서를 참고해보세욥
https://docs.celeryq.dev/en/stable/getting-started/introduction.html
왜 셀러리인가!
→ 여러가지 비동기 작업 큐가 존재하지만( Celery ,Redis Queue, Django-Q )우리 backend 개발 framework는 Python을 기반으로하는 Django이기 때문에 비동기 작업 큐를 Python 친화적이며, 무거운 작업을 처리하기에 대규모 분산 시스템을 구축에 적합한 Celery를 쓰자
그래서 우리가 사용 할 셀러리의 핵심 구성 요소를 살펴보면
Celery communicates via messages, usually using a broker to mediate between clients and workers.
- Messages = 작업 (이미지 생성이나 이미지 업로드 과정)
- Broker = 메세지를 전달하는 친구 = (우리는 RabbitMQ를 사용)
- Worker = 작업을 수행하는 친구 (Celery workers)
- Client = 작업을 요청하는 친구
<작동 원리>
Celery의 작업 과정을 그림에서 살펴보자
Django 서버 에서 발생한 요청(Task=Message)를 Message Broker(RabbitMQ)에서 받아 Celery를 이용하여 비동기적으로 분산 처리를 진행한다. Celery에서는 작업이 완료된 event를 DB 에 저장하는 방식으로 진행된다. 이렇듯이, Celery는 message broker가 꼭 필요하다.
그럼 Message Broker가 뭔데?
Message Broker는Publisher(송신자)로부터 전달받은 메시지를Subscriber(수신자)로 전달해주는 중간 역할 : 그니까 장고와 셀러리를 연결해준다~
따라서 응용 소프트웨어 간에 메시지를 교환할 수 있게 한다. 그리고 이 때 메시지가 적재되는 공간을Message Queue(메세지 큐)라고 한다. (RabbitMQ 뿐만 아니라 Redis 등 다른 애들도 많다)
그럼 RabbitMQ란?
RabbitMQ는 AMQP를 구현한 오픈소스 메세지 브로커로 producers에서 consumers로 메세지(요청)를 전달할 때 중간에서 브로커 역할을 한다.(메세지 = 작업을 뜻함)
AMQP(Advanced Message Queuing Protocol)는 분산 시스템에서 메시지 기반의 미들웨어를 통해 응용 프로그램 간 비동기 통신을 가능하게 하는 오픈 스탠다드 프로토콜 : Celery는 AMQP 기반, Rabbit MQ는 AMQP를 구현 따라서 같이 써버리자
다른 그림도 보자
- Producer: 요청을 보내는 주체, 보내고자 하는 메세지를 exchange에 publish한다. (=Django)
- Consumer: producer로부터 메세지를 받아 처리하는 주체(=Celery workers)
- Exchange: producer로부터 전달받은 메세지를 어떤 queue로 보낼지 결정하는 장소, 4가지 타입이 있음
- Queue: consumer가 메세지를 consume하기 전까지 보관하는 장소(RabbitMQ에서 관리)
- Binding: Exchange와 Queue의 관계, 보통 사용자가 특정 exchange가 특정 queue를 binding하도록 정의한다.