상용에서 실행 중인 레시피 서버에 부하 테스트를 진행했다.
📌 서론
이번 포스트에서는 "레시피아" 상용 서버의 부하 테스트를 진행했다.
테스트를 통해 서버 성능을 비교하기 위해 내 노트북(M2 max)과 냉면님의 노트북(m1 air)을 사용했다.
상용 서버는 AWS의 t4g.small을 사용 중이다. (아직 사용자가 없어서 저성능 ec2를 사용하고 있다.)
지금부터 테스트 결과를 같이 확인해 보자
1. 점차 유저수를 증진시키며 테스트
"레시피 상세 조회" API에 get요청을 보내는 것으로 모든 테스트를 진행했다.
테스트 시간은 모두 1분으로 동일하게 설정했다.
상용 (t4g.small): 10명

상용 (t4g.small): 50명

상용 (t4g.small): 99명

상용 (t4g.small): 198명

테스트를 통해 얻은 결론
- 최고 TPS가 조금씩 증가하는 것을 알 수 있다.
- 평균 테스트(응답) 시간도 증가했다. (낮을수록 성능이 좋은 거다.)
- TPS 그래프를 보면 유저가 많아질수록 점점 급격한 변화를 보이는 것을 확인할 수 있다.
- 모든 테스트를 성공했으며 에러는 발생하지 않았다.
2. (로컬 vs 상용) 부하 테스트 진행
성능 비교를 위해 로컬에서 사용 중인 m2 max, m1 air를 사용하여 테스트를 진행했다.
이전과 동일하게 모든 테스트 시간은 1분이다.
상용 (t4g.small): 296명

로컬 (M1 air 16GB): 296명

로컬 (M2 Max 64GB): 296명

1분 296명 기준 테스트 결과
- 테스트 결과를 간략하게 분석해 보면, M2 Max 64GB 모델이 가장 높은 TPS(초당 처리 건수)를 기록하며 성능이 가장 우수한 것으로 나타났다. 이는 높은 램 용량과 강력한 프로세싱 파워 덕분일 것이다.
- M1 air 16GB 모델은 M2 Max에 비해 낮은 TPS를 기록했지만, 그래도 높은 성능을 보여준다.
- 반면, AWS t4g.small 인스턴스는 매우 낮은 TPS를 기록하며 성능이 상대적으로 많이 부족한 것으로 나타났다.

테스트 결론
- AWS t4g.small 인스턴스의 경우 테스트 결과를 볼 때 매우 제한된 처리 능력을 가지고 있어서, 가벼운 워크로드나 개발/테스트 환경에는 적합할 수 있지만, 높은 트래픽을 처리해야 하는 상용 환경에는 적합하지 않다고 느껴졌다.
- 우리는 ECS 클러스터에 오토 스케일링을 적용시켰으니 이대로 세팅해도 될 것 같다. 오토 스케일링을 활용하면 트래픽이 증가할 때 자동으로 인스턴스의 수를 늘려서 부하를 분산시키기 때문에 갑작스러운 트래픽 증가에도 안정적으로 서비스를 운영할 수 있다.
근데 테스트 시간에 따라 결과가 다를 수도 있지 않을까? 시간을 5분으로 늘려봤다.
3. (로컬 vs 상용) 부하 테스트 진행 (테스트 시간 )
기존과 동일한 환경에 테스트 시간만 5분으로 변경했다.
상용 (t4g.small): 296명

로컬 (M1 air 16GB): 296명

로컬 (M2 Max 64GB): 296명

상용 서버(t4g.small)에서 발생한 에러 분석하기
- 가장 먼저 결과의 "상세 보고서"에서 오류 그래프를 확인했다.
- 1분 이후부터 주기적으로 에러가 발생하고 있었다.

- nGrinder에서는 테스트 결과 로그를 남겨주기 때문에 로그를 다운로드했다.

로그를 분석해 봤다.
- 로그에 따르면 잘 동작하다가 중간중간 init headers를 하고 500 에러가 발생하고 있었다.

- 500은 서버 측 에러니까 AWS의 CloudWatch를 통해 실행 중인 ECS 클러스터의 태스크 컨테이너를 확인했다.
- 지금 검색 예시 사진은 하나만 넣어뒀지만 여러 가지를 모두 검색했는데 관련 에러는 로그에 남아있지 않았다.

생각정리
- 이것은 nGrinder 자체의 문제라기보다는, 테스트 환경과 실제 서버 환경 사이에 불일치가 있거나, 테스트 도중 네트워크 문제나 서버의 일시적인 오류로 인해 발생한 것 같다고 결론 내렸다.
- 먼저 서버 로그를 상세히 분석했으며 다음으로는 recipeId가 실제로 존재하는지 확인해 봤다. 그래도 이상이 없는 것을 보니 테스트를 다시 해보는 것이 옳다는 생각이 들었고 재시도를 진행해 봤다.
테스트 요청을 다시 해봤다. (296명 5분 테스트 요청 재시도)
- 같은 스펙으로 다시 시도했는데 에러가 더 늘어났다. (에러 코드는 이전과 동일하게 500)
- 심지어 이번에도 AWS의 Cloud Watch에는 서버에 발생한 오류가 남아있지 않았다.

근데 만약 시간은 그대로 5분으로 두고 유저수를 줄이면 어떻게 될까?
- 유저수를 줄이니 확실히 에러가 줄어들었다. 그래도 에러 자체는 조금이지만 계속해서 발생하고 있었다.


그럼 시간을 3분으로 줄이고 사용자 수는 그대로 296명으로 테스트한다면?
- 결과는 흥미로웠다. 이번 테스트에서도 에러가 1건 발생했다. (에러는 동일하게 500)
- 대체 이유가 뭘까? 같은 사용자 수인데 왜 시간을 5분에서 3분으로 줄였다고 에러가 줄어들까? 2분 동안 요청을 더 하니까 서버가 과부하가 오는 걸까?

테스트 시간을 다시 5분으로 되돌리고 사용자를 줄여서 재시도했다.
- 이번에는 시간을 기존과 동일하게 5분으로 늘려줬다. 대신 사용자를 296명에서 198명으로 확 줄였다.
- 이렇게 테스트를 진행하니 에러가 한건도 발생하지 않았다.
- 이런 결과를 받고 나니 혹시 AWS의 사양이 문제인가?라는 생각이 들어 서버의 성능 지표를 확인했다.

AWS의 ECS에서 실행 중인 태스크(컨테이너)의 성능 지표를 확인했다.
- CPU 사용률은 25% 메모리 사용률은 27.5% 이상 올라가지 않는 것을 확인했다.
- 또한 내가 5분 동안 테스트를 진행했을 때는 각 성능지표가 최고점을 찍는 것도 확인할 수 있었다.
- 근데 왜 25%가 최대치일까? 내가 설정한 태스크의 구성을 확인했다.

설정된 태스크의 구성 확인
- 내가 레시피아의 ECS 클러스터에서 사용 중인 EC2 인스턴스는 t4g.small이다. 사양은 아래의 이미지에 있듯이 (vCPU 2, 메모리 2)로 구성되어 있다.
- 롤링 배포가 진행되면 2개의 태스크가 동작하는데 이때 메모리 이슈가 발생하여 1/4 수준으로 성능을 줄여서 사용 중이었는데 이것 때문에 서버가 최고사양으로 동작하고 있지 않았다. (지금 상황에서는 200명까지만 테스트에서 에러가 발생하지 않는다.)


결론은 상용 EC2 서버(t4g.small)가 200명 이상의 사용자 요청을 버티지 못해서 에러가 발생하고 있는 것이었다.
테스트 시간이 길수록 요청은 더 많아졌고 서버 자체가 늘어난 테스트의 수를 버티지 못했다. (과부하)
시간을 줄였을 때는 오류가 확실히 줄어드는 것을 볼 수 있었고 사용자를 줄였을 때도 오류가 줄어드는 것을 확인할 수 있었다.
4. (로컬 vs 상용) 부하 테스트 결과분석
5분 296명 기준 테스트 결과 (오류 사항이 그대로 반영된 결과)

결과 분석
이전 1분짜리 테스트에 비해, 5분짜리 테스트에서는 서버의 성능 차이가 더 두드러지게 나타났다.
- M2 Max 64GB는 압도적으로 높은 TPS를 기록해서 성능 면에서 가장 우수하다. 또한 모든 테스트가 성공적으로 수행되었고 에러가 전혀 발생하지 않았다.
- M1 air 16GB는 M2 Max 64GB에 비해 낮은 TPS를 기록했지만, 여전히 안정적인 성능을 보여줬다. 이 서버도 모든 테스트가 성공적으로 완료됐고 에러는 없었다.
- AWS t4g.small은 상대적으로 매우 낮은 TPS를 기록했고, 몇몇 테스트에서 에러가 발생했다. 이는 리소스 제한과 낮은 처리 능력 때문인 것 같다.
5. (1분 vs 5분) 2가지 테스트 결과 비교
1분 대 5분 테스트 비교
- 1분과 5분 테스트를 비교해 보면 시스템이 일정한 부하를 얼마나 잘 처리하는지, 시간이 지남에 따라 성능이 어떻게 변하는지를 알 수 있다. 아래의 표에서 5분 테스트 결과는 괄호() 안에 값을 적어뒀다.

TPS(초당 처리 건수)와 최고 TPS
- 일반적으로, 테스트 시간이 길어질수록 시스템의 성능을 더 정확하게 파악할 수 있다. 초기에는 시스템이 '워밍업' 중일 수 있어서 성능이 일시적으로 높게 나타날 수 있는데, 5분 동안의 테스트는 시스템이 안정된 상태에서의 성능을 더 잘 보여준다.
평균 테스트(응답) 시간
- 테스트 시간이 길어질수록, 시스템의 응답 시간이 실제 운영 환경에서 어떻게 변할지 예측할 수 있다. 짧은 시간 동안의 평균 응답 시간은 실제 사용자 경험을 왜곡할 수 있지만, 긴 시간 동안의 평균 응답 시간은 더 정확한 지표를 제공한다.
- 아래 이미지를 보면 알 수 있는데 0~1분 사이까지는 지표가 상승했다 하락하면서 안정화를 하는 것을 볼 수 있다. 1분 이후에는 거의 비슷한 양상으로 테스트 그래프가 그려진다.

성공한 테스트와 실패한 테스트 수
- 시스템의 신뢰성을 평가하는 데 중요하다. 테스트가 길어질수록 시스템이 지속적인 부하에 얼마나 잘 대처하는지를 확인할 수 있다.
에러 수
- 테스트 기간이 길어짐에 따라 시스템의 안정성에 대한 더 정확한 지표를 제공한다. 짧은 테스트에서는 일시적인 오류가 무시될 수 있지만, 긴 테스트는 잠재적인 오류를 발견하고 해결할 기회를 준다.
결론
- 정리하자면, 테스트 시간이 길어지면 테스트 횟수가 많아지면서 더 많은 데이터가 수집되고, 시스템의 성능을 더 정확하게 평가할 수 있다. 그리고 결과의 정확성이 더 높아지며 시스템이 더 오랫동안 안정적으로 성능을 유지할 수 있는지에 대한 평가도 가능하다.
📌 잠깐! 테스트 횟수가 왜 고정이 아니라 매번 다를까?
'테스트 횟수'라 함은 사용자가 시스템에 요청을 보내는 총횟수를 의미한다.
만약 296명의 사용자가 있다면 이들 각각이 테스트 시간이 1분이든 5분이든 해당 시간 동안 여러 번의 요청을 보낼 수 있다.
예를 들어, 각 사용자가 1분 동안 10번의 요청을 보낸다고 가정해 보자. 그렇다면 총 요청 횟수는 296명 x 10 = 2960회가 될 것이다. 그럼 5분 동안은 이 횟수가 5배가 돼서 14800회의 요청을 보낼 수 있다.
실제 테스트에서는 이렇게 각 사용자가 보내는 요청의 수는 TPS(초당 처리 건수)에 따라 달라진다. 그래서 296명이 한 번씩만 요청한다고 생각하지 말고 이들이 테스트 기간 동안 계속해서 요청을 보낸다고 생각하면 된다.
테스트의 목적은 각 사용자가 실제 운영 환경에서 어떻게 시스템을 사용할지를 모사하는 거니까, 사용자들이 한 번만 요청을 보내고 끝나는 게 아니라 지속적으로 여러 번 요청을 보낼 거라고 가정하는 것이다.
팀원 "평양냉면"님의 블로그도 들려주세요. 좋은 글이 많이 있습니다.
하다보니 재미있는 개발
하다 보니 재미있는 개발에 빠져있는 중입니다. 문의사항: ysoil8811@gmail.com
yijoon009.tistory.com
'DevOps > nGrinder' 카테고리의 다른 글
[nGrinder] 서버 부하 테스트 진행 (SpringBoot) (21) | 2024.02.14 |
---|---|
[nGrinder] 스크립트 작성하기 (5) | 2024.02.14 |
[nGrinder] M1 Mac에 설치하기 (3) | 2024.02.14 |