개발지식/Backend Engineering

비동기 처리란 무엇인가?(MQ / Kafka)

우루쾅 2026. 1. 23. 16:46
728x90
반응형
SMALL

백엔드 개발을 하다 보면 이런 말을 자주 듣는다.

  • “이건 비동기로 처리해야 해요”
  • “Kafka로 이벤트 흘리면 됩니다”
  • “MQ로 분리하세요”

그런데 막상 물어보면
👉 왜 비동기가 필요한지,
👉 동기/비동기가 실제로 뭐가 다른지,
👉 MQ와 Kafka가 왜 등장했는지
명확하게 설명하기는 쉽지 않다.

이 글에서는 아무 배경지식 없는 상태에서도 이해할 수 있도록
비동기 처리의 등장 배경부터 차근차근 설명해본다.


1. 우리가 처음 만드는 시스템은 전부 “동기 처리”다

대부분의 웹 서비스는 이렇게 시작한다.

클라이언트 요청 → 서버 처리 → 응답
 

이를 동기(Synchronous) 처리라고 한다.

 

예시: 주문 API

주문 요청 
→ 결제 처리 
→ 재고 차감 
→ 주문 저장 
→ 알림 발송 
→ 응답
 

이 구조는 이해하기 쉽고, 구현도 단순하다.
그래서 대부분의 초보 단계 서비스는 이 방식으로 시작한다.


2. 동기 처리의 진짜 문제는 “속도”가 아니다

많은 사람들이 이렇게 생각한다.

“동기 처리는 느리고, 비동기는 빠르다”

반은 맞고, 핵심은 아니다

동기 처리의 진짜 문제는 결합도와 장애 전파다.

 

2-1. 하나라도 느리면 전체가 느려진다

결제: 50ms 
재고: 20ms 
알림: 300ms (외부 API)
 

→ 전체 응답: 370ms

알림 하나 때문에 주문 API 전체가 느려짐

 

2-2. 하나라도 실패하면 전체가 실패한다

결제 성공 
재고 차감 
성공 알림 
서버 장애 ❌

 

👉 결과

  • 주문 API 실패
  • 이미 결제는 됐는데 사용자에겐 “실패” 응답

이런 상황, 실제 서비스에서 엄청 자주 발생한다.

 

2-3. 트래픽이 늘수록 서버는 버틴다

동기 구조에서는 요청 하나가 처리될 때까지
서버의 스레드/리소스를 계속 점유한다.

요청 증가 
→ 처리 대기 증가 
→ 응답 지연 
→ 타임아웃

 

👉 결국 전체 서비스가 느려지거나 죽는다


3. 그래서 등장한 개념이 “비동기 처리”

비동기 처리의 핵심 아이디어는 간단하다.

“지금 당장 응답할 것”과
“나중에 처리해도 되는 것”을 분리하자

 

3-1. 비동기 처리의 기본 구조

요청 
→ 핵심 처리 
→ 이벤트/메시지 발행 
→ 응답 

(뒤에서) 
→ 부가 처리

 

주문 예시로 다시 보면

주문 요청 
→ 결제 
→ 주문 저장 
→ 응답 

(비동기) 
→ 알림 발송 
→ 통계 집계 
→ 로그 저장
 

👉 사용자 입장:

  • 주문은 빨리 완료됨

👉 서버 입장:

  • 무거운 작업을 뒤로 미룸

 


4. “그럼 그냥 Thread로 빼면 되지 않나?”

처음엔 이런 생각이 든다.

new Thread(() -> sendNotification()).start();

 

❌ 이 방식의 문제

  • 서버 재시작 → 작업 유실
  • 장애 발생 시 재처리 불가
  • 분산 환경에서 관리 불가능

👉 “비동기”는 Thread 문제가 아니라 “신뢰성” 문제


5. 여기서 등장하는 게 MQ(Message Queue)

RabbitMQ, ActiveMQ 같은 MQ는
“비동기 처리를 안전하게 하기 위한 중간 저장소”다.


6. MQ는 어떤 문제를 해결하나?

MQ가 없을 때

서버 → 알림 서버 
(직접 호출)
  • 알림 서버 장애 → 요청 실패
  • 알림 서버 느림 → 전체 지연

MQ가 있을 때

서버 → MQ → 알림 서버

MQ의 역할

  • 메시지를 큐에 저장
  • Consumer가 자기 속도로 처리

👉 서버는 “던지고 끝”


7. MQ 동작을 아주 쉽게 비유하면

요청자 = 주문 직원 
MQ = 접수함 
Consumer = 처리 담당자
  • 직원은 접수함에 서류만 넣고 다른 일 함
  • 담당자는 하나씩 꺼내 처리

👉 업무 분리 + 안정성 확보


8. MQ 예시 코드 (감만 잡기)

Producer (메시지 발행)

rabbitTemplate.convertAndSend(
    "order.queue",
    new OrderCreatedEvent(orderId)
);
 

Consumer (메시지 처리)

 
@RabbitListener(queues = "order.queue")
public void handle(OrderCreatedEvent event) {
    sendNotification(event);
}

 

중요한 점:

  • Producer는 Consumer가 누구인지 모름
  • 느리든, 잠시 멈추든 영향 없음

9. 그런데 MQ로는 부족한 순간이 온다

서비스가 커지면 이런 요구가 생긴다.

  • 같은 이벤트를 여러 시스템이 사용하고 싶다
  • 과거 이벤트를 다시 처리하고 싶다
  • 초당 수십만 건 이상 처리하고 싶다

👉 이때 MQ만으로는 한계가 온다.


10. 그래서 Kafka가 등장한다

Apache Kafka
단순 큐가 아니라 이벤트 로그 시스템 이다.

메시지를 “전달”하는 게 아니라
이벤트를 “기록”한다


11. Kafka를 한 문장으로 말하면

Kafka는
시스템에서 발생한 모든 일을 시간순으로 저장하는 로그 다.


12. Kafka가 MQ와 다른 핵심 포인트

구분 MQ Kafka
메시지 구조 Queue Log(Stream)
소비 방식 1번 소비 여러 번 소비 가능
재처리 어려움 매우 쉬움
확장성 매우 높음
용도 작업 분리 이벤트 중심 아키텍처

13. Kafka 예시 (이벤트 중심 사고)

주문 생성 이벤트
  • 결제 서비스
  • 알림 서비스
  • 통계 서비스

👉 모두 같은 이벤트를 각자 소비

Producer

kafkaTemplate.send(
    "order.created",
    orderId.toString(),
    new OrderCreatedEvent(orderId)
);

Consumer (결제)

@KafkaListener(topics = "order.created", groupId = "payment")
public void pay(OrderCreatedEvent e) { }

Consumer (알림)

@KafkaListener(topics = "order.created", groupId = "notification")
public void notify(OrderCreatedEvent e) { }

14. 정리: 왜 비동기가 필수가 되었는가

  • 동기 구조는 단순하지만 잘 깨진다
  • 비동기는 속도가 아니라 안정성을 위한 선택
  • MQ는 작업 분리
  • Kafka는 이벤트 흐름 관리

15. 요약

비동기 처리는
“지금 당장 끝낼 일”과
“나중에 해도 되는 일”을 분리하는 설계다.

MQ는 작업을 안전하게 미루는 도구이고,
Kafka는 시스템의 모든 이벤트를 기록하는 스트림 엔진이다.

728x90
반응형
LIST