본문 바로가기

개발일지/TIL

[230827] 입찰 API 병목 현상 로직 수정

입찰 API 로직 개선

💬 입찰 API 로직에서 95%정도 차지하는 SSE를 통해 이벤트를 클라이언트로 전송하는 로직을 분리를 하기로 했습니다.

 

✔ 로직 수정 기준

1. SSE 전송은 순서가 보장이 되어야 했습니다.
    ➡ 입찰된 가격이 순서가 보장이 되지 않는다면 실시간 경매에 정상적으로 진행이 되지 않을 것입니다.
    ➡ 그동안 트랜잭션에서 걸린 비관적 락 때문에 순서가 보장되고 있었습니다.
2. SSE 전송이 분리가 되거나, 비동기로 이루어지도록 만들어야 했습니다.
    ➡ 병목을 해결하기 위해 트랜잭션 처리 시간이 줄어들어야 하기 때문입니다. 

 

✔ 로직 수정 후보군

1. Java에서 제공하는 ExecutorService
    ➡ BlockingQueue를 통해 SSE 전송 순서를 보장해줍니다.
    ➡ 별도의 스레드를 생성해 비동기로 처리를 해줍니다.

2. Kafka
    ➡ Producer/Consumer 형태로 이벤트를 주고 받을 수 있어서, SSE 전송 로직을 분리할 수 있습니다.
    ➡ Consumer에서 이벤트를 순서대로 받아 처리할 수 있습니다.

 

✔ 로직 수정

💬 입찰 API와 SSE 기능이 한 서버 안에 있기 때문에 더 적은 자원을 사용해서 해볼 수 있는 ExecutorService를 사용하기로 했습니다.
    ➡ ExcutorService에서 사용하는 BlockingQueue의 크기는 Integer.MAX(0x7fffffff) 입니다.
    ➡ 사용할 Thread 개수를 정할 수 있지만, 순서 보장을 위해 한 개의 아이디어에는 한 개의 스레드만 사용하도록 설정했습니다.

 

// 수정 전
sseService.send(SseConnect.BID,SseEvent.BID_PRICE_UPDATE,ideaId,newBid.getBidPrice());
noticeService.noticeBidEvent(userId, idea, request.bidPrice());

// 수정 후
bidExcutorService.submit(()-> sseService.send(SseConnect.BID,SseEvent.BID_PRICE_UPDATE,ideaId,newBid.getBidPrice()));
noticeExecutorService.submit(()->noticeService.noticeBidEvent(userId, idea, request.bidPrice()));

 

✔ 결과

💬 SSE를 통해 입찰을 보내는 부분을 비동기로 변경하니 0ms로 단축된 것을 볼 수 있습니다.