API 성능개선 과정에서 깨달은 성능개선의 핵심
안녕하세요. 졸린개발자입니다.
오늘은, API 성능개선 프로젝트 과정에서 깨달았던
성능 개선 포인트를 공유해보려고 합니다.
결론부터 말씀드리자면,
핵심은, 데이터를 적게 들고오는것 이였습니다.
간단한 예제부터 살펴봅시다
블로그를 만들어본다고 가정해봅시다.
블로그에는 포스트의 리스트를 보여줘야하는 페이지가 있겠죠?
- 포스트1
- 포스트2
- 포스트3
.....
한 페이지에 10,000개의 포스트를 보여줘야한다는
아주 이상한 요구사항이 있다고 가정해봅시다.
해결방법 1 - 가장 간단한 방법
가장 간단한 구현 방법은
포스트를 조회하는 API에서, 한번에 10,000개의 포스트를 내려주면 됩니다.
이때 API에서는 DB에서 한번에 10,000개의 포스트를 조회하면
가장 간단한 구현이 되겠지요.
하지만 한번에 모든 데이터를 가져오도록 구현한다면
어떤 방법을 써도, 결국에 10,000개의 데이터를 한번에 가져와야하기 때문에
10,000개의 데이터를 한번에 불러오기 위한
DB의 디스크 IO, DB와 서버의 네트워크 지연은 무시하지 못할 수준으로 올라갈 것이고
사용자는 불편함을 느낄정도로 느려지겠네요.
다른 방법을 찾아봅시다.
해결방법 2 - DB 조회를 멀티 스레드로 변경
가장 간단한 방법에서, 한단계 더 나아가 봅시다.
한번의 DB 쿼리로, 10,000개의 포스트를 불러오는것이 엄청난 시간이 소요되니,
여러번의 DB쿼리를, 병렬적으로 돌리면 문제가 해결될까요?
즉, 기존의 1번의 10,000개를 불러오는것을
10개의 스레드로, 1000개씩을 불러오는 것이지요.
DB에서 서버로 가져오는 속도는 10배가 되었습니다.
그러면 모든 문제가 해결된 것일까요?
아래 두가지 문제는 아직 해결되지 못했습니다.
1. 서버 <-> 클라간 통신에서 10,000개의 데이터를 주고받기 위한, 네트워크 지연
2. 클라(브라우저) 에서 10,000개의 데이터를 랜더링 하기 위한 시간
네트워크 지연은 말할것도 없지만
2번의 케이스가 생긴다는것을 이번 프로젝트에서 처음 알게되었습니다.
브라우저에서 10,000개의 데이터를 한번에 불러와서 랜더링한다면 어떻게 될까요?
제가 경험했던 바로는, 10,000개쯤 되니
브라우저의 탭이 뻗어버렸습니다.
해결방법 3 - 클라에서 무한 스크롤 형태로 전환
그럼 스크롤을 무한 스크롤으로 전환해
100개, 다음 100개.... 이런식으로 불러오게 수정하면 어떨까요?
서버는 한번에 100개의 포스트만을 불러오게 되니,
DB에서도 한번에 100개만 불러오고
클라와의 통신에서도 한번에 100개만 내려주게 됩니다.
서버에서는 문제가 해결되겠네요.
클라는 어떨까요?
스크롤을 통해 실제 화면에 보이는 영역만 랜더링하고
보이지 않는 영역을 랜더링하지 않는 최적화를 하면
한번에 10,000개의 데이터를 랜더링하는것이 아닌,
스크롤 영역에 해당하는 작은수의 데이터만 랜더링될 것입니다.
클라에서도 문제가 해결되었네요.
깨달음
개발을 하다보면, 정말 수많은 최적화에 대한 이론들이 쏟아집니다.
그런 최적화 이론의 결론은
필요한 데이터를, 가장 적은 수의 접근(디스크 IO, 네트워크 IO 등등...) 으로 가져오는 방법으로 귀결되죠.
어떤 최적화를 얼마나 수행하던
결국 한꺼번에 많은 데이터를 다루면, 리소스는 무제한이 아니기 때문에, 언젠가는 성능에 한계가 오게 됩니다.
깨달음2. 정규화에서 비정규화를 하는 이유
정규화된 데이터의 비정규화를 왜 할까요?
한번에 많은 데이터를 다루지 않게 하기 위해서입니다.
예를 들어보죠.
포스트의 좋아요의 개수를 보여주는 기능이 있다고 가정해봅시다.
포스트 한개에, 좋아요 데이터가 평균적으로 100개가 있다고 가정해봅시다.
포스트 100개가 되면, 좋아요는 10,000개가 되겠네요.
자 다시 10,000개의 데이터를 다루게 되었습니다.
이때 비정규화를 해서, 포스트 데이터에 좋아요 개수를 저장한다면 어떻게 될까요?
포스트 100개의 데이터만 다루면 되겠네요.
기타1.
지금까지 말한 사항은, API 성능개선에 초점이 맞추어져 있습니다.
즉각적인 응답이 필요하지 않은, 배치에 경우에는 어떻게 될까요?
예를 들면,
통계를 수행하는 배치의 경우에는, 즉각적인 응답이 필요 없는 경우가 대부분입니다.
통계 작업을 수행하는 API의 응답은 "통계 작업이 시작되었습니다." 로 빠르게 응답하고
수행이 완료되면 알림으로 "완료되었습니다." 를 보내면 되겠죠.
통계 작업은 빠르게 되어야 할 필요는 없습니다.
사용자가 알림을 받기까지 어느정도 시간이 소요됨을 알기 때문이죠.
(물론 너무 느리면 안되긴합니다 ㅋㅋ)
그래서 보통 이런 케이스에 성능 개선의 초점은
통계 작업의 time보다는, 서버 전체의 throughput에 더 초점을 맞추게 됩니다.
성능개선은, 어디를 얼마나 초점을 맞출것인지를, 잘 정하고 가는것도 중요한 포인트 중에 하나입니다.
기타2.
이런 방법은 어떨까요?
기획자를 설득하는 방법입니다.
사용자가 한번에 10,000개의 포스트를 봐야하는 이유가 어떤것인가에 대해 질문하고
그 니즈가 검색의 니즈인지, 아니면 통계의 니즈인지를 파악해서
10,000개의 포스트의 통계를 내는 api를 추가하던
검색을 하는 api를 추가하던
한 페이지에 10,000개의 포스트를 불러오지 않는 사용성을 만들어낸다면 어떨까요?
제가 다니고 있는 회사는
이런 방법을 아주 좋아합니다.
기획자가 알기 힘든, 컴퓨터의 근본적인 한계로 인한 것들을
개발자가 놓치지 않음으로써
결과적으로 더 나은 제품을 만들 수 있으니까요.
결국 개발자도 프로덕트를 만드는 일원중 하나입니다.
어떻게 하면, 더 나은 제품을 만들 수 있을지 고민하는것이
성능개선에서도 놓치지 않아야할 사항입니다.