일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 부하 테스트
- java
- Kotlin
- 코딩
- 객체지향
- OAuth
- Oidc
- kakao
- Spring
- 디프만
- 코드트리
- 코드 트리
- Redis
- 자료구조
- 코딩테스트
- dip
- 디자인 패턴
- 다형성
- 디프만16기
- pub.dev
- 코딩 테스트
- c
- 연습문제
- Sharding
- depromeet
- C언어
- flutter
- nGrinder
- 운영체제
- AOP
- Today
- Total
Nick Dev
[Outsagram] nGrinder & pinpoint로 병목 지점 파악 후, sharding을 통해 성능 개선한 경험 본문
[Outsagram] nGrinder & pinpoint로 병목 지점 파악 후, sharding을 통해 성능 개선한 경험
Nick99 2024. 12. 12. 06:06
5줄 요약
- nGrinder & pinpoint로 DB에서
getConnection()
이 오래 걸린다는걸 파악함 - 커넥션 풀 개수 조절해봄(10, 15, 20개)
- 별 차이 없었음 😢
- sharding을 통해 DB 부하를 절반으로 줄여봄
- 성능 개선됨 😊
현재 서버 아키텍처 및 상황
클라우드는 Naver Cloud Platform을 사용 중이다.
nGrinder로 가상의 유저의 행동을 스크립트로 작성하고 이를 실행해보았다.
- 한 유저가 회원가입 -> 로그인 -> 게시물 조회 100회, 게시물 생성 5회, 좋아요 누르기 15회, 북마크 누르기 15회하고 로그아웃 한다고 가정했다.
- 즉, **한 유저 당 138개의 api를 호출**하게 된다.
- connection pool(cp) size는 디폴트인 10이다.
- 이러한 가상의 유저(vuser)가 700명이 있다고 가정하고 10분간 부하를 부어보았다.
- (참고로 이미 캐싱 로직은 적용되어 있다)
✅ cp = 10 인 경우
nGrinder 결과
pinpoint 결과
DB 인스턴스 CPU 사용량
📌 결과 해석
평균 응답 시간은 매우 양호하지만, Response Max가 5.34 sec가 나오는건 좀 심각하다.
그래서 pinpoint로 해당 api 호출의 call stack을 살펴본 결과,
getConnection()
에서 대부분의 시간을 차지하는 것을 보았다.처음에는 커넥션 얻는게 오래 걸리니깐 cp가 부족한가..? 라는 생각을 했다.
하지만, Hikari CP의 공식문서에 따르면
connections = ((core_count * 2) + effective_spindle_count)
라고 명시되어 있기에 vcpu가 4개인 상황에서 디폴트인 10개면 충분한 개수로 볼 수 있다.그래도 혹시 모르니...? cp size 조절해서 성능 차이가 있을지 확인해보자
✅ cp = 15, 20 인 경우
cp가 10, 15, 20일 때, 부하 테스트 결과 사진 모음
📌 결과 정리
결과 표를 보면 알 수 있듯이, cp 개수를 변경해도 성능의 개선이 없다.
그럼 connection pool size가 문제가 아님
getConnection()
에서 오래 걸렸다면 cp size 문제 말고 DB 인스턴스의 CPU 사용량이 최대 77 % 찍은게 문제일 수 있겠다고 생각했다.- 매우 심각한 정도의 cpu 사용량은 아니지만 10분간 테스트를 진행했을 때 이정도라면 시간을 늘리게 되면 충분히 문제가 될 수 있는 포인트라고 생각함
그럼 DB에 가해지는 부하를 나누면 기본적인 성능도 개선되고 Response Max도 줄일 수 있을 것 같다.
그러면 이제 샤딩을 진행해보자!!
✅ sharding 적용 후
sharding 적용 후 서버 아키텍처
샤딩 로직 구현 과정은 아래에서~
(AOP로 routing할 db 세팅)
애플리케이션 레벨에서 DB routing 로직 구현하는 과정
nGrinder 결과
pinpoint 결과
⭐ 결과 비교
vcpu 4, cp = 10, vuser = 700 은 공통이고 DB sharding 유무의 차이만 있음
DB를 2개로 샤딩 하니깐 평균적으로
31.63%
정도 성능이 개선되었다.특히, 가장 큰 문제였던 Response Max 값이 5.34 sec ➡️ 2.57 sec으로 *50 % *정도 감소하면서 샤딩을 통해서 원하는 바를 어느정도 이뤘다고 볼 수 있다.
그리고 샤딩을 통해서 같은 시간동안 263,028개(30%)의 api를 더 처리할 수 있었다.
✅ 성능 개선하는 과정 요약
1. nGrinder & pinpoint로 부하 테스트 후 call stack 살펴본 결과, getConnection()
에서 오래 걸린다는걸 파악함(최대 5.34 sec 소요)
2. 현재 vcpu가 4개이기에 이론적으로 cp 10이면 적당하지만 그래도 커넥션 풀 개수 조절해보고 테스트 후 결과 비교해봄(10, 15, 20개)
3. 역시나 별 차이 없었음 😢
4. 서버 모니터링 결과, DB 인스턴스의 cpu 사용량이 높은걸 확인함
5. DB 인스턴스의 부하를 줄이려면 물리적으로 DB를 나눠보자 = sharding
6. sharding 전후 비교해보니, 평균적으로 31.63 % 성능이 개선되었고, 가장 문제였던 Response Max 값이 5.34 ➡️ 2.57초로 약 50 % 감소했음 😊
느낀점
실제 유저의 트래픽이 아니라 내가 만든 스크립트에 따른 트래픽인게 좀 아쉽긴 하다
그래도, 내가 서비스를 론칭했을 때 받을 유저의 트래픽보단 일부로 좀 더 오버해서 트래픽을 부어보았다.
pinpoint로 각 api의 call stack을 확인하고 어디서 많은 시간을 잡아먹는지 보는게 신기했고, 이론적으로 알고있던 connection pool에서의 병목 현상을 직접 경험해봐서 재밌었다.
- 애플리케이션 로직이 매우 복잡한게 없기도 했지만, 쿼리 자체 수행하는데는 1
10ms 밖에 안걸리고 connection pool 얻으려고 기다리는 시간이 훨씬 길다는 것을 직접 확인해볼 수 있었다.
- 애플리케이션 로직이 매우 복잡한게 없기도 했지만, 쿼리 자체 수행하는데는 1
Cloud DB 안쓰고 Server를 DB로 쓰는 이유
네트워킹, Pulbic IP, 로드 밸런서 등 비교할게 많지만 간단하게 비교해보면 같은 스펙으로 1달 사용했을 때, 비용이 2배 차이가 난다.
그래서 Server에 docker 설치해서 mysql db를 실행시켜 사용했다.
'Outstagram' 카테고리의 다른 글
[Outstagram] AOP 활용해 동적으로 DB Source 바꾸기 (1) | 2024.12.12 |
---|---|
[Outstagram] kafka 메시지 큐를 활용해 비동기 메시지 전송을 도입한 이유 (0) | 2024.12.12 |
[Outstagram] Cache 유무에 따른 성능 비교해보기 (0) | 2024.12.12 |
[Outstagram] nGrinder를 활용한 부하 테스트 후 성능 튜닝 과정 (0) | 2024.12.12 |
[Outstagram] Redis에서도 동시성 이슈가 발생한다고...? (lua script 적용기) (0) | 2024.12.12 |