대기열 구현 아이디어 V2

김형준·2025년 2월 21일
0

수정된 흐름 초안

  1. Controller 측에서는 Service 계층의 메서드를 호출한 후 비동기 방식을 통해 결과를 기다림
  2. Service 측에서는 들어온 요청 검증 후 유효하다면 Waiting Queue에 저장
    1. Waiting Queue가 꽉 찼다면 요청 폐기(backpressure 매커니즘)
    2. 요청이 많이 몰리는 경우 일정 시간 동인 Waiting Queue에 값 저장을 시도해보는 식으로 구현해도 될 것
  3. Processing Queue를 확인 후 여유가 있다면 Waiting Queue → Processing Queue로 요청을 이동시킴
    1. Processing Queue가 꽉 찬 경우 여유가 생길 때 까지 Processing Queue에서 대기
  4. 별도의 스케줄러 등이 Processing Queue에서 요청을 하나씩 pop해 비즈니스 로직 수행
  5. 요청 처리 이후 비동기 방식을 통해 대기하고 있는 Controller 측에 결과 전달

의문점

  1. Waiting Queue와 Processing Queue의 관리 주체는 각각 무엇인가?

    answer

    서버 애플리케이션 시스템의 과부화 방지를 위해 Waiting Queue는 Redis와 같은 별도의 저장소에서 관리됨

    Processing Queue는 Worker Thread Pool, Scheduler, 서비스 계층 등을 통해 관리됨

  2. Controller를 실행하는 스레드 측에서 결과를 비동기로 받아오는 동안에는 스레드 실행이 멈추는 건가?

    1. 그렇다면 스레드가 계속 멈출 수 있는 상황을 어떻게 예방할 수 있나?
    2. 또한 성능 측면에서 문제와 개선 방안은 없나?

    answer

    Spring Webflux, CompletableFuture, callback 기반 non-blocking I/O를 사용하면 요청 처리를 대기하는 동안 스레드가 멈추지 않음

    I/O 혹은 외부 시스템 호출과 같이 대기 시간이 발생하는 작업은 별도의 스레드 또는 이벤트 루프에서 처리됨

    스레드 풀, 큐의 크기를 적당히 조절하고 모니터링을 통해 병목 구간을 추적할 수 있도록 할 것

  3. 비동기 방식 도입 시 요청 처리 결과를 기다리는 스레드, 요청을 대기 큐 및 작업 큐로 옮기는 스레드, 별도의 스케줄러 등을 통해 비즈니스 로직을 처리하는 스레드 각각이 수행되는 건가?

    answer

    요청한 스레드는 non-blocking 사용 시 sleep하지 않음

    대기 큐 저장: Controller 혹은 초기 요청 처리 로직에서 수행

    작업 큐 저장: 스케줄러 or Worker Thread에서 담당

    비즈니스 처리: 스케줄러 or Worker Thread에서 담당

  4. 대기 큐 하나만 관리하는 것에 비해 장단이 무엇인가?

    answer

    • pros
      • 부하 분산 가능
        • 대기 큐가 급증하는 요청을 임시 저장해 과부화 방지
        • 작업 큐는 실제 처리 가능한 작업만 선별 가능
      • 각 큐에 대한 소비자를 별도로 확장 가능
      • 대기 큐, 작업 큐 사이의 추가적인 스케줄링 및 우선순위 적용 가능
      • 처리 실패 시 대기 큐에서 재시도하는 매커니즘 구현이 쉬워짐
    • cons
      • 시스템 복잡도 증가
        • 두 개의 큐를 관리하는 방식의 직관성이 떨어질 수 있음
      • 추가 지연 가능성
        • 대기 큐 → 작업 큐로 옮겨오는 과정이 추가되기에 오버헤드 발생
      • 자원 관리 및 추적 부담
        • 각 큐의 상태들을 관리해야 하므로 관리 포인트 증가

큐가 적용될 범위

예약 추가 & 취소 시에만 적용되도록 해야 하나?

요청별로 큐를 분리하자.

분리하는 이유

  1. 제네릭 타입으로부터 자유롭다.
    1. 기존 DTO들을 하나의 인터페이스로 묶어 처리 시 전용 로직을 적용하기 어려움
    2. 또한 인터페이스 타입에 기반해 큐 로직 구현 시 직렬화/역직렬화 문제가 해결하기 어려워짐
  2. 요청 별 스케일링을 유연하게 할 수 있다.
    1. 요청별로 트래픽이 다른 경우 각각에 맞게 큐 사이즈를 조절 가능해진다.

요청 객체와 비동기 객체 간 분리

비동기 객체를 사용해야 하는 비동기 방식의 경우 둘을 분리해서 관리하는 게 용이하다고 생각된다.

둘을 Redis 큐에 같이 저장할 경우 비동기 객체의 (역)직렬화가 어렵고 분산 시스템에 적절하지 않다.

또한 둘을 분리하면 요청 처리 및 결과 전달이 느슨하게 결합되어 독립적으로 최적화 할 수 있을 뿐 아니라 분산 시스템에서 확장이 용이해진다.

반면 비동기 객체를 사용하지 않고도 요청 처리 결과를 전달 가능한 기술을 사용한다면 이러한 고민은 깔끔하게 해결된다.

다만 해당 기술이 요구하는 러닝 커브를 극복해야 한다는 문제는 존재한다.

0개의 댓글

관련 채용 정보