반응형

두 명의 동료분이랑 함께 API 속도 개선 작업을 진행했다.
나는 검색 API를 담당했고, 동료분은 메인 페이지에서 제일 먼저 호출되는 API를 주로 개선했다.
사내 메신저 공개채널에 검색 API 속도 개선 작업 결과를 공유했고, 댓글로 어떤 식으로 작업을 진행했는 지 세부적으로 공유했다.
이런 개선 작업은 꾸준히 지속되야하기 때문에 다음 작업자들이 개선을 할 때에 이 과정을 참고해서 더 좋은 방법으로 개선한다면 좋겠다고 생각한다.


검색 페이지 뷰가 2~3배 증가했다! 사용자 한 명당 검색 페이지를 3~4번 정도 봤었다면, 개선 후에는 한 명당 10 번 정도의 페이지를 보게 된 것이다.
그리고 내가 한 작업은 아니지만 8~12 초에서 1~3초로 단축된 API도 있었다 😊
개선 작업이 진행되었던 윤곽과 세부적인 내용을 기록해본다.


1. 대상 선정

이번 API 속도 개선 작업은 서비스 이해도가 높은 분들이 아래 기준에 의해 선정해주셨다. (자주 보이는 것 중 겁나 느린 걸 기준으로 뽑았단 소리ㅎㅅㅎ)
- 최초 접근 시 제일 먼저 보이는 페이지에서 호출되는 API
- 검색 시 사용하는 API
하지만 다른 도구들을 이용하여 여러 기준으로 대상을 선정할 수 있다.
AWS RDS에 느린 쿼리 기준이라던가, 혹은 페이지 응답 시간을 기준으로도 타겟을 선정할 수 있겠다. 타겟을 선정할 때 이 API가 얼마나 자주, 혹은 크리티컬하냐도 기준으로 삼을 수 있다.

2. 검증 항목 및 작업 방식 논의

일단 개선이 이루어졌다고 판단할 수 있는 기준이 필요했다. 어떤 것을 검증해야하고 개선의 기준은 무엇인지 논의하였다.
첫번째 판단 기준은 구간별 소요 시간
개선 후 API 응답 속도가 줄어들었다고 해서 구간별로 더 나아졌다고 확신할 수는 없다.
예를 들어 하나의 API에 A 쿼리와 B 쿼리가 있다고 가정하자. A 쿼리는 속도가 다소 증가했고, B 쿼리가 속도가 많이 단축되었다면 전체적인 응답속도는 줄어들었기 때문에 좋은 개선이 이루어졌다고 판단할 수도 있다. 하지만 A 쿼리는 오히려 쿼리 최적화 전보다 속도가 나지 않기 때문에 원복을 한다거나 다른 식으로 쿼리를 개선해볼 수 있을 것이다. 그렇기 때문에 개선한 구간별로 나누어 속도를 측정하기로 하였다.
두번째 판단 기준은 동일한 응답 결과
검색 조건별로 개선 전/후 응답값과 순서가 모두 일치하는 지 확인해야했다. 속도가 빨라졌더라도 기존과 다른 응답 결과를 반환한다면 개선이 아니라 약속되지 않은 다른 기능으로 바꿔버린 꼴이기 때문이다.
최종 판단 기준은 API 응답 시간
가설을 세우고 구현하고 검증하는 모든 과정은 구간별 속도와 응답 결과를 측정했다. 그리고 최종으로 정말 개선이 이루어졌는 지를 판단할 때에는 API 응답 시간을 기준으로 판단하였다. 때문에 팀 내에 공유할 때에는 부가적인 정보 없이 '해당 API가 특정 조건에서 평균 x초 소요되었는데, 개선 후 평균 y초 소요된다' 라는 정보를 공유했다.
또한 작업 방식에 대해서도 이야기를 나누었다.
개선 전/후 결과가 동일하다는 것을 충분히 테스트하였다면 조금씩 개선된 것을 운영에 배포해도 되겠다고 판단하였다.
하지만 그렇게 진행되면 최초 결과에서 얼만큼의 개선이 있었는 지 확인하기 어렵기 때문에 원래 API에 꾸준히 개선 작업을 배포하되, 원본 API를 복사한 별도의 API를 만들어두었다. 물론 git을 사용하여 버전 관리가 가능하지만 로컬이 아닌 서버에서 API 개선 전/후를 바로바로 비교할 수 있기 때문에 별도 API를 만들었다. 작업이 끝난 후에는 불필요한 파일은 모두 제거하였다.

3. 분석 및 논의

개선 대상이 되는 API 들이 어디에서 속도가 많이 느린 지 확인했다. 대부분 쿼리가 최적화되지 않아서 발생한 문제였다고 판단했다.
대상되는 API가 많지 않아 각자 확인 후 어떤 지점이 문제였고 어떤 식으로 개선하면 좋을 것 같은 지 의견을 공유했다.
크게 아래와 같은 패턴들이 속도 저하가 많이 발생할 것이라 의심되었고 이에 대해 함께 이야기 나눴다.
- 카운트 쿼리에 모수에 영향되지 않은 부가정보들이 함께 제공되고 있음 (불필요하게 더 많은 연산을 야기)
- 서브 쿼리가 과도하게 사용되고 있음 (모수 1개마다 N개의 쿼리가 내부적으로 수행되는 꼴)
- 별도의 쿼리로 부가정보 조회 시 모수의 pk를 참고하도록 (이미 모수를 구해두었는데 이를 참조하지 않고 새롭게 모수를 추출하는 경우가 있었음)
- 존재여부와 같은 값은 한 번만 확인하면 되므로 exists 키워드 등을 활용 혹은 limit을 걸어 더 이상의 연산 방지

4. 작업 및 테스트 (반복)

각자 로컬에서 가설-개선-테스트를 오지게 반복한 후 어느정도 개선이 이루어졌다고 느낄 때 마다 PR을 주고 받았다. (하나의 API를 PR 했다고 해서 개선을 멈추지는 않았음)
앞서 말했지만, 이 개선이 정말 유효했는가를 알기 위해서는 구간별 개선된 속도를 측정해야했고 별다른 도구를 사용하지 않았기 때문에 로그를 이용해 시간을 측정했다.
그리고 나 혼자만 테스트가 정상이라는 것을 알고 넘어가면 안된다. 엑셀 파일에 Request 유형별 결과값을 모두 기재해두었다. 검증 시점에 따라 데이터가 달라질 수 있기 때문에 response를 모두 기록해두었다 (하핫)

5. 결과 공유


느낀점

우당탕 처음 하는 개선 작업이라 멋있고 편리한 도구의 도움 없이 로우하게 작업이 진행되었다.
하지만 그렇다고 하더라도 '개선' 작업의 필수적인 요소는 충분히 충족하였다고 생각한다.
그래도 다음에는 더 빨리, 더 많이, 정확하게 측정할 수 있는 도구를 이용하면 좋겠다.
딱히 쿼리 최적화를 위해 멋지고 휘황찬란한 것을 한 건 아니었는데 개선 결과가 크게 나타나서 재미있었다. 그리고 우리가 서버 비용을 좀 많이 내고 있겠구나 느꼈다.

프론트 최적화를 통한 속도 개선

속도개선을 위해 구글링하다보니 웹 프론트에서도 속도 개선을 할 수 있는 포인트들이 보였다. (이번 작업에 포함은 하지 않음)

  • <script> 태그를 불러올 때 비동기로 가져올 수 있도록 옵션을 추가
  • 이미지 같은 리소스에 대해서 지연 로딩
  • 필요한 원본 <link> 를 빨리 로드할 수 있도록 옵션 추가 등…

이 내용은 타사 JavaScript를 효율적으로 로드 라는 글을 참고함

반응형