데이터베이스 활용 방식

메시징 시스템 대신 데이터베이스를 중간 저장소로 활용하여 시스템 간 비동기 연동하는 방식입니다.

동작 방식

[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 부하와 실시간성 문제로 메시징 시스템으로 전환을 고려해야 합니다.

CSLOG에서 보기