- Published on
비동기 처리 아키텍처 이해하기: async를 넘어서
- Authors
- Name
- devnmin
⚙️ 비동기 처리 아키텍처 이해하기: async를 넘어서
코드에서 async
/await
를 사용하는 비동기 프로그래밍은 익숙하지만,
실제 시스템 설계에서는 이보다 더 넓은 의미에서의 비동기 처리 전략이 필요합니다.
이 글에서는 시스템 수준에서 자주 사용되는 비동기 처리 방법들과 그 특징을 정리해보았습니다.
1. 비동기란?
비동기 처리란 요청을 받은 후 결과를 기다리지 않고 즉시 응답하거나 다른 처리를 동시에 진행하는 방식을 말합니다.
단일 사용자 기준이 아니라 시스템 전체의 흐름과 병렬 처리 능력을 고려하는 것이 핵심입니다.
2. 주요 비동기 처리 방식
🔹 1. 별도 스레드 (Thread Pool)
- 일정 개수의 스레드를 미리 만들어 놓고 작업을 분산 처리
- 고성능이나 빠른 응답이 필요할 때 유용
- 과도한 스레드는 오히려 리소스 낭비로 이어질 수 있음
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=10)
executor.submit(some_function)
🔹 2. 메시징 시스템 기반 처리
• Kafka, RabbitMQ 같은 메시지 큐를 활용하여 비동기 처리를 수행 • 발신자는 메시지만 큐에 넣고, 수신자는 자신이 처리 가능한 속도로 가져감 • 트래픽 급증 상황에서도 시스템 부하를 분산할 수 있어 확장성과 안정성이 높음
FastAPI → Kafka → 소비자 서비스
🔹 3. 트랜잭션 아웃박스 패턴
• DB 트랜잭션과 Kafka 메시지 발송을 직접 묶는 것이 어렵기 때문에, 메시지를 우선 DB의 outbox 테이블에 저장 • 별도의 백그라운드 프로세스(예: Celery, 스케줄러)가 해당 테이블을 조회하여 메시지를 Kafka로 발송
주문 저장 + 메시지 저장 (같은 트랜잭션)
백그라운드 작업이 메시지 발송
성공 시 outbox 상태 변경
• 데이터 일관성을 보장하면서도 메시지를 안전하게 처리할 수 있는 방식
🔹 4. 배치 연동
• 주기적으로 실행되는 배치 프로그램이나 스케줄러를 통해 비동기적으로 데이터를 처리 • 실시간성은 낮지만, 대용량 처리에 적합
예: 매일 새벽 3시에 사용자 활동 로그 집계
🔹 5. CDC (Change Data Capture)
• DB의 **변경 로그(binlog)**를 감지해 Kafka 등으로 메시지를 자동 발행 • Debezium과 같은 CDC 도구를 사용하여 서비스 코드 변경 없이도 DB의 변경을 실시간으로 추적 가능
MySQL → binlog → Debezium → Kafka → 소비자
• 트래픽이 많은 시스템이나 마이크로서비스 연동에 효과적
3. 설계 시 고려사항
항목 | 고려 포인트 |
---|---|
데이터 일관성 | 트랜잭션과 메시지의 정합성 필요 (→ 아웃박스 패턴) |
장애 복구 | 메시지 누락, 중복 전송에 대한 대비 |
처리 순서 보장 | 메시지 순서가 중요한 경우 파티션 또는 큐 설계 필요 |
처리 속도 | 동시 처리량 및 병목 분석 필요 |
모니터링 | 메시지 큐 상태, 처리 지연, 실패율 등을 지표로 관찰 |
4. 개인적인 인사이트
처음에는 비동기라고 하면 단순히 async def 같은 코드 관점만 떠올렸습니다. 하지만 시스템 전반을 바라보며 아키텍처 차원에서 비동기를 이해하니 훨씬 흥미롭고 깊이 있는 시야가 생겼습니다. 특히 트랜잭션 아웃박스 패턴이나 CDC 기반 설계는 실무에서의 신뢰성과 유연성을 높이는 데 큰 도움이 될 수 있겠다는 확신이 들었습니다.
💡 Tip: 비동기 시스템은 단순히 빠르게 만드는 것이 목표가 아니라, 신뢰성, 확장성, 일관성을 균형 있게 고려하는 것이 중요합니다.