TravEat 어플에서 Survey tag를 통해 자신이 원하는 tag선택하여 알맞는 음식 상품에 대한 결과가 도출되게 한다.
하지만 여기서 문제점은 Survey에 대한 저장시간이 오래걸리면서 사용자의 불편을 초래하게 된다는 것이다.
Survey의 saveSurvey 메서드를 호출하면서 해당 API (api/survey/save-survey)를 테스트한 결과 응답 시간이 39.64초로 지나치게 오래 걸리는 문제가 발견되었다. 이로 인해 사용자 경험이 저하될 가능성이 높아지고, 시스템의 성능 병목 현상이 발생할 우려가 있었다.
해당 병목 현상에 대한 문제를 해결하기 위하여 비동기 처리를 하여 성능을 개선하고자 했다.
왜 비동기 처리를 해야 하나요?
saveSurvey 메서드 내에서 여러 데이터베이스 연산과 외부 API 호출(getRecommendFoodListByOpenAI)이 포함되어 있다. 해당 작업들이 순차적으로 실행되면 전체 실행 시간이 각 작업의 누적 시간만큼 길어진다. 그래서 비동기처리를(Promise.all, async/await)를 사용하면 서로 독립적인 작업을 병렬로 처리할 수 있어 응답 시간을 크게 단축할 수 있다.
selected_tags 배열의 각 항목에 대해 SurveyResultTag.create를 병렬로 실행하도록 Promise.all을 사용했다. 이를 통해 데이터베이스에 여러 태그를 동시에 추가할 수 있다. 그리고 selected_tags에서 각 tag_id에 해당하는 SurveyTag를 조회하는 부분을 Promise.all로 병렬 처리하였다. 이를 통해 여러 태그의 이름을 동시에 가져올 수 있다.
즉 Promise.all를 사용하여 비동기 함수들을 병렬로 처리하는 것은 여러 작업이 동시에 진행되어 서버 성능을 최적화하는 데 도움이 되며 특히 데이터베이스와의 상호작용에서 여러 CREATE나 FIND 쿼리를 병렬로 실행하는 것은 응답 시간을 줄이고 시스템의 효율성을 높이는 방법이다.
왜 for문을 안쓰고 map을 사용했나요?
for 문을 없애려고 하는 이유는, for 문이 순차적으로 실행되기 때문에 성능이 떨어질 수 있다는 점과 async/await와 Promise.all을 함께 사용할 떄 for문이 async 작업을 직렬적으로 처리하게 되어 비동기 처리가 비효율적일 수 있기 때문이다.
그래서 map을 사용하여 모든 비동기 작업을 배열로 만들고 Promise.all을 사용하여 병렬로 처리한다. 이렇게 하여 여러 비동기 작업이 동시에 실행되므로 성능이 개선된다.
비동기 처리를 하여 36.94s -> 73ms로 시간 단축이 99.8%로 아주 효과적으로 단축되었다. 즉 36.94초 동안 기다리던 사용자가 즉각적인 반응(0.073초)을 경험이 가능하게 되었다. 그리고 동일한 시간동안 최대 506배 더 많은 요청을 처리가 가능하다.
성능개선 배율: 36,940/73=506
시간 단축 비율: (1-(73/36,940)*100 = 99.8%
'Node.js' 카테고리의 다른 글
Node.js 란? (2) | 2024.12.14 |
---|