V2 방식의 문제점
결론적으로는 구현된 대기열의 여러 가지 사항(큐를 나눈 이유, 작업 큐를 비우는 방식을 스케줄러로 구현한 이유) 등에 대해 why?를 제대로 설명할 수 없다는 문제가 있음
- 큐를 나눈 이유 부족
- Reactor core & Redis 혼용
- 스케줄러로 작업 큐에서 요청을 꺼내는 이유 부족
- 큐 자료구조에 대한 고민 부족
그 외에도 기술적으로 문제가 있을 수 있는 부분들이 여럿 존재한다.
- 대기 큐가 무한정 커질 수 있는 문제
- 여러 scheduler들 간 잠재적인 race condition 문제
- 현재 사용중인 JPA 드라이버가 동기적으로 작동하고 있는 문제
V3 개선점
- 대기 큐 & 작업 큐를 하나로 합쳐 관리
- 큐에서 요청을 꺼내 처리하는 작업을 스케줄러 대신 pub/sub을 활용하도록 수정
- 큐는 기본적인 FIFO를 사용하는 자료구조로 수정
- 대기열 처리를 위한 pub/sub 기술은 redis, kafka 등 외부 브로커 중 하나만 사용하도록 수정
- 여러 메시지 큐들을 비교할 수 있도록 인터페이스를 분리할 것
- 다른 메시지 큐 조사 및 도입은 Redis를 활용해서 구현한 이후 진행할 것
- webflux 제거하기
- 요청을 비동기적으로 처리해 스레드 당 효율을 높이는 것 자체는 좋음
- 하지만 race condition 문제, callback 지옥, 잘못된 사용으로 인한 시스템 안정성의 저하, 까다로운 디버깅 등의 문제가 생길 여지가 있음
- 따라서 요청을 동기적으로 처리하도록 수정할 예정
- 다만 publisher/subscriber 스레드 간 데이터 공유 시에는 도입을 할 수도 있음
V3 기획
요청을 받는 스레드 측면
- 사용자가 Controller 계층에 요청을 전송한다.
- Controller에서는 publisher를 호출하는 QueueingService 메서드를 호출한다.
- QueueingService에서는 의존성이 분리되어 있는 메시지 발행 인터페이스를 통해 메시지를 발행한다.
- 이후 QueueingService에서는 consumer가 처리하는 요청 결과에 대해 일정 시간 동안 비동기적으로 대기한다.
- 일정 시간 동안 요청이 전송되지 않으면 timeout 예외를 던지도록 한다.
- 요청 처리 결과를 전송받으면 이를 Controller 측으로 넘겨 최종적으로 응답을 반환한다.
요청을 가져와 처리하는 스레드
- 애플리케이션 실행 시 같이 수행된 consumer 스레드에서는 큐에 값이 추가되었을 때 Redis로부터 신호를 받는다.
- Redis 신호 전송받은 경우 요청을 처리하고 결과를 publisher 스레드에 전송한다.
참고 사항
- 두 스레드 간 데이터 공유 시에는 sinks를 활용할 예정
- sinks를 보관하는 자료구조에서는 키값을 요청이 들어온 밀리초를 사용할 예정
- 요청을 가져와 처리하는 스레드 수를 TaskExecutor를 통해 동적으로 조절할 수 있도록 할 예정