이전 nGrinder 성능테스트 관련하여 글을 포스팅하였는데요! 이전 글에서는 왜 성능테스트가 필요한지, 간단한 테스트 작성법 등을 다루어보았다면 이번 포스팅은 결과 분석 관련하여 다루어보려 합니다.
(이전 작성글은 아래의 링크로 첨부하도록 하겠습니다!)
2024.07.06 - [분류 전체보기] - 2024-07-06 [nGrinder 성능 테스트]
2024-07-06 [nGrinder 성능 테스트]
성능테스트의 필요성대부분 해당 포스트를 읽는 분들은 성능 테스트의 필요성을 인지하고 있을 것이라 생각하지만... 그래도 필요성을 간략하게 설명하면애플리케이션이나 웹사이트에는 사용
hongjinkwon.tistory.com
이번 프로젝트 중, 검색을 통해 관련 Post를 찾는 Method (SearchPost)에 Cache를 적용했는데, Cache를 적용하기 전과 적용 후 성능 차이를 비교하기 위해 nGrinder 도구를 활용해 보았습니다.
테스트 환경 설정
- Dummy Data (Post Data) : 23,153
- Spring Memory Setting (Maximum Heap Size) : 1024MB
- TTL : 1Min
- Run Time : 5Min
애플리케이션 가용 메모리 사이즈가 1024MB는 사실 한없이 작은 것을 알고 있지만, EC2 micro를 함께 띄어놓았다고 가정하고 Test를 진행하기 위해 용량을 제한하였습니다.
Amazon EC2 Micro 인스턴스의 메모리 크기는 인스턴스 유형에 따라 다르며, 가장 일반적인 Micro 인스턴스 유형인 t2.micro와 t3.micro의 메모리 크기는 다음과 같습니다.
1. t2.micro: 1 GiB (Gibibyte) 메모리
2. t3.micro: 1 GiB 메모리
테스트 결과
각 진행한 Test 결과는 아래와 같습니다. Version1의 스크립트를 하단에 함께 기재해놓도록 하겠습니다!.
Version1 (Cache 미적용)
- TPS 임계점 (Saturation point) : 약 35 ~ 38 / vUser : 50
Version2 (In-Memory Cache 적용)
- TPS 임계점 (Saturation point) : 약 9000 ~ 9500 / vUser : 100
Version3 (Remote Cache 적용)
- TPS 임계점 (Saturation point) : 약 7500 ~ 8500 / vUser : 100
테스트 진행 방식은 vUSer를 조금씩 증가시키는 방식으로 TPS가 최고치에 도달하는 시점을 파악합니다.
* TPS는 초당 Transaction 처리 수로 throughput(시간당 처리량)과 동일한 의미이며,
throughput에 대한 그래프를 그려가면 어느 순간 throughput이 이전보다 떨어지는 경우가 발생하기 때문에 인원을 조금씩 증가시키면 최고의 효율을 보여주고 있는 시점을 찾는 것이 중요합니다.
주로 x 축은 동시 사용자, y 축은 throughput의 형태로 그래프를 표현하며, 사용자는 시스템의 규모에 따라서 다르지만 일반적으로 100단위 수준으로 증가시켜 가면서 테스트를 진행합니다. (저의 경우 시스템의 규모가 크지 않기 때문에, 10씩 증가하며 Test를 진행하였습니다.)
확실히 Cache를 적용하기 전과 후 TPS차이가 큰 것을 확인할 수 있습니다
테스트 결과 분석
튜터님께 질문을 했을 때는 TPS를 파악하는 것만으로 유의미한 성능 테스트라고 말씀하셨으나, TPS를 통해 여러 가지 결과를 도출해 보고 싶어 이런저런 시도를 해보았는데요..
첫번째로 리틀의 법칙을 통해 해당 서비스가 수용이 가능한 동시 사용자 수를 파악해보았습니다. 리틀
1. Little’s Law 계산식
사용가능 유저 = TPS * (RESPONSE TIME + THINK TIME)
해당 법칙을 성능테스트에 적용해 보기 전 반드시 이해하고 넘어가야 할 부분이 있습니다.
nGrinder와 같은 성능테스트 도구에서 실행하는 부하테스트는 요청의 응답을 받자마자 요청을 바로바로 보낸다는 점입니다. 즉 실제 사용자의 ThinkTime을 고려해야 한다는 점입니다.
Version2를 예시로, 동시 사용자를 산출해보려 합니다.
"사용가능 유저 = 9,000 * (RT + TT)"인데, 서비스 이용 시 사용자 최적의 환경을 고려해줍니다.
이전 포스팅에서도 설명한 것처럼, 응답시간이 1초가 넘어갈 시 사용자의 이탈확률은 증가하니 0.3초를 평균 응답시간으로 설정하고,
사용자는 요청의 응답을 받은 뒤, 다음 요청까지 약 1초라는 평균적인 시간이 소요된다고 가정, 1초를 ThinkTIme으로 가정하면
동시사용자는 9,000 * (0.3+1.0) = 11,700명이 됩니다.
(성능테스트에 리틀의 법칙을 적용하는 다른 사람들의 포스팅을 확인했을 때는 다 조금씩 다른긴 해서 참고만해주시면 좋을 것 같습니다.)
유의해야 할 부분은 응답시간과 ThinkTime을 최대한 보수적으로 잡아야 한다는 점이며, API마다 TPS 차이가 크기 때문에 무거운 API를 기준으로 동시 사용자를 집계해 보는 것이 좋은 방법이 될 수 있습니다!
2. Redis Cache
In-Memory Cache 비교 Redis TPS 성능이 비교적 떨어지는 이유는 Redis와 통신하는 과정을 거쳐야 하기 때문입니다.
그럼에도 Redis 사용이 가져올 수 있는 이점은 애플리케이션 서버를 Scale-out 하게 되면 동일한 메모리를 사용하지 못하기 때문에 동기화 이슈를 해결하기 위해 Remote cache redis를 사용합니다.
추가적으로 Cache 활용하여 높은 부하를 걸게 될 경우, Error가 높은 비율은 아니지만 함께 발생하는 것을 확인해볼 수 있는데요!
원인은 동시성 문제(Concurrency Issues)로,
여러 사용자가 동시에 동일한 캐시 항목을 업데이트하거나 접근할 때 동기화 문제가 발생할 수 있습니다. 이는 캐시의 일관성을 유지하기 위해 적절한 동기화 메커니즘이 필요하며, 이를 처리하지 않으면 에러가 발생할 가능성이 높습니다.
주말동안 동시성 문제를 해결해볼 수 있는 여러가지 방법들을 학습해보고, 적용해보도록 하겠습니다!
** 학습용으로 블로그를 작성, 그러다보니 개인적인 주관이 많이 들어간 포스팅이어서 잘못된 부분이 있다면 말씀 대대환영입니다. 감사합니다!..