티스토리 뷰

728x90

"성능 최적화를 했던 경험을 말씀해 주세요."

한창 취업 시장의 문을 두드렸을 때 면접에서 들었던 내용이다.

 

주니어 개발자에게,

한 번 실수 하면 큰 일 날 대규모 트래픽 분산 작업이나, 성능 최적화를 어떤 회사에서 시켜준단 말이냐..

 

하지만 이번에 입사한 회사에서 운 좋게도 경험할 수 있게 되었는데,

해당 태스크를 진행하게 된 계기, 과정, 결과를 공유한다.

 

서버 비용 줄이기 태스크가 

맨 처음 나에게 태스크로 할당 되어서 작업을 진행한 것은 아니였고,

 

우리 회사 서비스의 앱을 사용해 보는데, 앱 기본 동작이 너무 느렸다.

친구 관계를 맺고, 댓글을 쓰고, 피드를 조회하는데 속도가 너무 느려서 너무너무 해결하고 싶었다. 
이러한 경험은 고객 관점에서 최악으로 느껴졌고, 앱의 사용성 개선을 우선적으로 해결해야 할 태스크라고 느꼈다.

그렇게 스스로 문제를 진단하고, 팀 내에 해당 태스크를 공유한 다음

성능 최적화를 진행했다.

 

결과부터 말하자면 AWS 서버 비용을 3분의 1로 줄였고, 쿼리 조회 속도도 개선되었다.

추가적으로 내가 적용했던 다양한 성능 최적화 방법과, AWS RDS 결과도 제공한다.

 

-04.03일자로 적용-

 

 

🌠 목차
✅ 문제 진단
✅ 내가 적용한 성능 최적화 방법
      - 기타 성능 최적화 
✅ 결론: AWS RDS 모니터링 데이터

 

 

문제를 진단하자. 


서비스 직접 사용

내가 직접 앱을 사용하면서 고객 경험을 해치는 부분을 모두 체크했다. 

참고로 난 QA도, QC도, 프런트 개발자도 아니다.

그다음 AWS RDS 모니터링 서비스에서 속도가 느린 쿼리를 체크했다. 

 

AWS RDS 모니터링 SQL 결과 보기

 

 상위 SQL, 즉 현재 실행 중인 쿼리 중 속도별로 정렬한 표를 볼 수 있다.

 

 

SQL 쿼리를 직접 실행하여 속도를 알아보기

나의 경우는 nestjs + prisma를 사용하였다. 

포스트맨으로 API를 날려 prisma 쿼리의 log를 조회하였다. 

위 이미지는 예전에 내가 저장해 둔, 속도가 오래 걸리던 쿼리이다.

1063ms가 걸렸다. 1초 이상 걸리는 경우는 매우 느린 축에 속한다.  

고객의 디바이스 사양이 떨어지는 경우와 네트워크 환경에 따라 3~5초 이상의 속도로 느려질 수 있기 때문이다. 

 

 

 

 

내가 적용할 수 있는 성능 최적화 


먼저 내 서비스를 모두 훑어보았다. 

내가 적용할 수 있는 부분은 크게 

 

1. Index를 통해 성능 최적화

2. count 쿼리 역정규화 적용

3. 페이지네이션 offset -> cursor 적용 

4. Hard Delete -> Soft Delete

5. Aurora 

 

이렇게 존재했다. 

(이외에도 Redis 캐싱 전략등이 있었지만 마케팅 이후 적용하기로 하여 Redis 적용 태스크는 몇개월 밀렸다.)

다음은 위에 작성한 최적화 방법들에 대해 설명한다.

꼭 꼼꼼히 읽어보자!

 

 

✅ Index를 통한 성능 최적화 

https://youtu.be/IMDH4 iAQ6 zM? si=r0_qtGmWA2 ALmHis

 

Index에 대해 정말 잘 설명한 유튜브 영상이다.

 

Index는 데이터베이스에서 특정 칼럼의 값을 빠르게 검색하기 위해 사용되는 구조다.

특정 칼럼에 대해 인덱스를 생성하면 그 컬럼의 값들이 새로 정렬되어 저장되며,
이를 통해 해당 컬럼에 대한 검색 및 정렬 작업을 더 효율적으로 수행할 수 있다.

인덱스는 데이터베이스 내부에서 B-tree와 같은 트리 구조를 사용하여 구현된다.
이 구조를 활용하면 데이터를 효율적으로 저장하고 검색할 수 있다.
(1~100 중 70을 탐색하려면 50 기준으로 위아래 비교 -> 50~100에서 75 기준 위아래 비교 -> 반복 탐색)

 

그러나 인덱스를 생성하는 것은 새로운 공간을 생성한다.
인덱스를 많이 생성하면 데이터베이스의 용량이 증가하고 쓰기 연산의 속도가 느려질 수 있습니다.
따라서 인덱스를 생성할 때에는 어떤 컬럼에 인덱스를 생성할지 신중하게 결정해야 한다.

 

 Count 쿼리 역정규화 적용하기

count 쿼리를 이용하여 전체 피드 수, 친구 수 등을 조회할 때 속도가 상당히 느리다.

그 예시로 인스타그램에서 저스틴 비버가 피드를 작성하면, 수억 개의 좋아요가 발생했고,

실시간으로 count를 해야 해서 인스타그램이 다운됐던 적이 있다고 한다. 

이를 역정규화로 해결할 수 있다. 

 

역정규화란 테이블 칼럼에 숫자를 담을 수 있는 칼럼을 생성하고, 

로직에서  좋아요 클릭, 회원 탈퇴, 시에 좋아요 숫자를 +1, -1 해주는 것을 의미한다. 

이렇게 하면 로직에서 처리할 부분과 사이드이팩트가 있을 곳 모두 로직에서 연산을 해줘야 한다는 단점이 있다.

하지만 count쿼리로 발생하는 속도문제를 해결할 수 있다. 

 

 

 페이지네이션 Offset -> Cursor 적용하기

2024.03.31-[Cursor 페이지네이션] nestJS + Prisma - cursor 페이지네이션 방식 (성능 최적화, 직접 cursor 구현)

offeset과 cursor 방식에 정리한 글이다. 

여기서는 자세히 다루지 않고 위 포스팅 글을 참고하길 바란다.

실제로 offset에서 cursor 페이지네이션 방식으로 변경하고 속도가 눈에 띄게 달라졌다. 

 

 

 Hard Delete -> Soft Delete 적용하기

쉽게말해 delete연산대신 update로 처리하는 것이다.

삭제(Delete) 연산이 업데이트(Update) 보다 느린 이유는 데이터베이스 시스템의 내부 동작 및 최적화와 관련이 있다.

 

업데이트

보통 데이터베이스 시스템은 업데이트 연산에 대한 최적화를 많이 수행하는데, 이는 데이터를 업데이트할 때 기존 레코드를 갱신하거나 덮어쓰는 작업을 하기 때문이다. 이런 경우 인덱스를 효율적으로 활용하거나 로그 기록을 최적화하여 업데이트 속도를 높일 수 있다.

 

삭제

데이터를 삭제할 때마다 해당 레코드를 실제로 제거하고, 데이터베이스의 구조를 재정리해야 한다.

삭제된 데이터가 차지하던 공간을 다시 활용하기 위해 공간 재사용을 위한 작업도 필요하다. 

이런 추가적인 작업들 때문에 삭제 연산의 속도가 오래 걸린다.  

 

따라서 delete를 할 때, 실제 데이터를 삭제하는 것이 아니라,
테이블에 status 값을 추가하여 delete, pending, 등의 상태로 보여줄지 말지 정하도록 하자. 

 

📣 회원이 탈퇴할 경우 예제

인스타를 예시로 회원이 탈퇴할 경우 회원과 맺었던, 팔로우 관계, 상대방에게 보낸 알림등 삭제를 해줘야한다.

이때 hardDelete는 당연하고, softDelete로 할 경우에도 트랜잭션 타임아웃이 발생할 수 있다. 

이에 따라 회원 탈퇴 등은 batch로 빼도록 하자.

배치 테이블에 회원 탈퇴한 유저의 id를 저장해둔 뒤, 회원 탈퇴시 삭제해야할 데이터를 부하가 적은 매일 새벽 시간대에 삭제하도록 했다.

 

성능 최적화 결과 


2024.04.03일 기준으로 적용한 결과이다. 

 

1. 4.3일 기준 디비 read 비용이 (오로라 디비사용 중) 8분의 1로 줄어들었다.

    - 80% 임계점을 찍던 DB 부하가 10%~20%대로 감소했다.

2. RDS Monitoring에서 쿼리 확인 결과, 1,2,3 순위를 차지하던 친구 맺기, 거절, 수락등의 속도가 눈에 띄게 빨라졌다.

    - 기존 3ms -> 0.3ms

 

 

 

성능을 줄이고 나서


비용과 성능을 개선하고 나서 나는 약간 눈이 돌았다,,,

"약간의 노력으로 회사의 비용을 이렇게나 많이 줄일 수 있구나,,,"

"지금 우리 서비스에서 최적화 시킬 수 있는 것은 뭐가 더 있지?"

등에 대해 계속 고민하고 있다.

회사를 다니면서 또 성능을 개선하거나 비용을 줄이는 태스크를 하게 된다면 새로운 포스팅으로 돌아오겠다. 

 

 

2024.03.31-[Cursor 페이지네이션] nestJS + Prisma - cursor 페이지네이션 방식 (성능 최적화, 직접 cursor 구현)

 

[Cursor 페이지네이션] nestJS + Prisma - cursor 페이지네이션 방식 (성능 최적화, 직접 cursor 구현)

nestjs, prisma를 이용해 cursor 페이지네이션을 구현한다. 서버 부하를 줄이는 많은 태스크가 있지만, 오늘은 페이지네이션 방식인 cursor를 통해 어떻게 부하를 줄이는지 알아보자. 참고로 Prisma를 적

study-easy-coding.tistory.com

 

 

 

 

 

글 재미나게 보셨으면 좋아요 눌러주고 가세요

관심받는 거 좋아합니다

 

728x90
댓글
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday