데이터베이스 활용 방식
메시징 시스템 대신 데이터베이스를 중간 저장소로 활용하여 시스템 간 비동기 연동하는 방식입니다.
동작 방식
[Polling 방식]
A 서비스 → DB에 작업 저장
B 서비스 → 주기적으로 DB 조회 → 작업 처리
A 서비스: INSERT INTO jobs (status) VALUES ('PENDING')
B 서비스: SELECT * FROM jobs WHERE status = 'PENDING'
→ 처리 후 UPDATE status = 'DONE'
구현 패턴
1. Polling (폴링)
@Scheduled(fixedDelay = 1000) // 1초마다 실행
public void processJobs() {
List<Job> jobs = jobRepository
.findByStatus(JobStatus.PENDING);
for (Job job : jobs) {
job.setStatus(JobStatus.PROCESSING);
jobRepository.save(job);
// 실제 처리
process(job);
job.setStatus(JobStatus.DONE);
jobRepository.save(job);
}
}
2. Transactional Outbox 패턴
트랜잭션과 메시지 발행을 원자적으로 처리
1. 비즈니스 로직 + Outbox 테이블에 이벤트 저장 (같은 트랜잭션)
2. 별도 프로세스가 Outbox 테이블 조회
3. 메시징 시스템으로 발행 후 삭제
@Transactional
public void createOrder(Order order) {
orderRepository.save(order); // 주문 저장
outboxRepository.save( // 이벤트 저장
new OutboxEvent("ORDER_CREATED", order.toJson())
); // 같은 트랜잭션 → 둘 다 성공 or 실패 O
}
// 별도 스케줄러
@Scheduled(fixedDelay = 1000)
public void publishEvents() {
List<OutboxEvent> events = outboxRepository.findUnpublished();
events.forEach(event -> {
messagingSystem.publish(event);
outboxRepository.delete(event);
});
}
DB 활용 vs 메시징 시스템
| DB 활용 | 메시징 시스템 | |
|---|---|---|
| 구현 복잡도 | 낮음 | 높음 |
| 인프라 | 기존 DB 활용 | 별도 구축 필요 |
| 처리량 | 낮음 | 높음 |
| 실시간성 | 낮음 (폴링 주기) | 높음 |
| DB 부하 | 증가 | 없음 |
| 적합한 규모 | 소규모 | 대규모 |
문제점
Polling 방식의 단점
1. DB 부하 증가
→ 주기적으로 SELECT 쿼리 발생
2. 실시간성 부족
→ 폴링 주기만큼 지연 발생
3. 중복 처리 위험
→ 여러 Consumer가 같은 작업 동시 처리 가능
→ 락(Lock) 처리 필요
SELECT * FROM jobs WHERE status = 'PENDING'
FOR UPDATE SKIP LOCKED ← 락으로 중복 방지
언제 사용하나?
O 소규모 서비스
O 메시징 시스템 도입 전 단계
O 트랜잭션 일관성이 매우 중요한 경우
O 인프라 복잡도를 낮추고 싶을 때
X 대용량 트래픽
X 실시간성이 중요한 경우
DB 활용 방식은 별도 인프라 없이 간단하게 구현 가능하지만, 규모가 커지면 DB 부하와 실시간성 문제로 메시징 시스템으로 전환을 고려해야 합니다.