개발/Denamu 프로젝트

[Denamu 스테이징 서버] DB 조회를 어떻게 최적화할 수 있을까?

codesparkling 2025. 2. 2. 01:03

DB 페이지네이션 성능 개선 과정

우리 프로젝트의 서버는 처음에 커서 기반 페이지네이션으로 동작하도록 설계되었다.
무한스크롤을 처음 구현해보기도 했고, 커서 기반 페이지네이션이 가장 이해하기 쉽고 구현하기에도 편해보였다.
auto_increment가 설정되어 있는 PK를 기준으로 동작하도록 구현했다.
그래서 최신 글부터 보여주기 위해 데이터가 순차적으로 삽입되어야 했다.

초기 구현과 비동기 삽입의 한계

처음 데이터 삽입을 구현하면서 promise.all을 활용한 비동기로 데이터 삽입 요청을 했다.
하지만 비동기로 동작하면 DB 요청은 반복문을 통해 순차적으로 진행되어도 실제 DB 접근에서 순차적인 삽입이 보장되지 않는 것을 알게 되었다.

개발 기간이 얼마 남지 않아 은행처럼 하나씩 순차적으로 삽입하는 방식으로 변경했다.
삽입 성능이 좋지 않을 것임을 예상했지만, 당시에는 서비스 규모가 작아 추후 개선을 고려했다.

성능 테스트 시작

부스트캠프에서 제시했던 프로젝트 기간이 끝나고 수료식을 마쳤다.
우리 Denamu 팀원들은 수료한 뒤에도 함께 서비스를 배포하고 리팩토링하자는 이야기가 예전부터 있었기에 이 DB 삽입 부분 또한 리팩토링 하기로 결정되었다.
그 과정에서 담당 팀원이 데이터베이스 view 기능을 찾아왔다.

처음에는 데이터베이스에 대해 잘 몰라서 view가 캐싱 같은 기능을 지원하는 줄 알았다.
(논리적 테이블이라는 말에서 테이블에 속았던 것이다. view는 쉽게 말하면 보통의 SELECT문이랑 다를 게 없다.
view는 쿼리를 사용하기 쉽도록 저장해주는 용도 혹은 보안적으로 숨기기 위해 사용한다.)

찾아보니 PostgresQL이나 MSSQL 등의 DB에서는 materialized view나 view index를 지원하기도 했지만,
우리가 사용하는 MySQL이나 mariadb에서는 그런 기능이 없었다.
어찌됐든, DB에 데이터를 비동기로 넣어주고 view로 조회하니까 ID가 순차적이지 않아도 차례대로 정렬해서 값을 반환하기에 날짜순으로 잘 보장되어 출력됐다.

여기서 모든 문제가 해결된 줄 알았는데 부하테스트를 진행해보면서 문제가 생김을 알게 되었다.
DB에 10만 개의 테스트 데이터를 삽입하고 테스트를 진행하니 응답이 모두 시간초과를 뱉는 문제가 있었다.
데이터가 너무 많은 것 같아 1000개로 줄이고 테스트를 진행했다.
결과적으로 80±5/rps에서 시간초과가 터지기 시작했고 100/rps에서는 모든 요청에 대해 시간 초과가 발생했다.

병목지점 확인

view가 의심스러워서 view를 삭제하고 기존 로직대로 조회하도록 테스트를 했다.
결과는 초당 100개 요청 정도는 쉽게 응답했다.
view에 대해 깊게 알고 있는 것도 아니고, 내가 맡았던 부분도 아니라서
잘은 모르지만 예상가는 건 view를 조회하기 위해 모든 데이터를 다 join 하면서 1000건, 10만건의 데이터를 join 연산하고 있을 것 같다는 점이었다. (어떤 로직으로 동작하는 건지는 코드 리뷰를 통해 파악했다. view가 내부적으로 인덱스 등을 어떻게 이용하는지를 모르겠다는 의미이다.)
이전 로직은 limit을 걸어서 10개면 10개, 20개면 20개를 조회하도록 해놨기 때문에 조회 성능이 더 뛰어난 것 같다.

개선 방향 모색

vuser 요청이 실패하는 경우가 발생해도 response가 시간초과로 실패하는 것은 없어졌다.
이제 조회 성능을 올리기 위해 아래 두 가지 기준을 가지고 생각해봤다.
프론트 코드를 고치지 않을 수 있는가?, view를 사용해야 하는가?
그에 따라 여러 생각을 대략적으로 떠올릴 수 있었다.

  1. view에 limit을 걸 수 있을까?
  2. view를 삭제하고 다시 기존 로직으로 변경할까?
  3. 아예 프론트 로직도 수정하고 DB에 대해 더 공부한 다음 최적화를 시킬 방법을 찾아볼까?
  4. 프론트 로직은 수정하지 않으면서 DB를 최적화 할 수 있는 방법이 있을까?
  5. Feed 테이블의 생성 날짜에 index를 걸어주면 view의 성능이 index 덕분에 나아질 수 있을까?

아직 어떻게 해야 할지 감이 안 잡혀서 위 생각들을 정리해보고 태스크를 진행할 것 같다.


2025-02-04 수정)
1번 개선 방향에서 limit을 걸 수 있을까라는 말의 의미는 view 자체의 크기를 줄여보자는 것이었다.
현재 행 번호로 게시글의 순서를 파악하고 있기 때문에 이렇게 개선하면 결국 무한스크롤에서 게시글이 중복, 누락되는 버그가 발생할 것이다.
그래서 다른 방법을 모색해야 할 것 같다.