안녕하세요. 프로젝트를 진행하면서 기존에 구상했던 기능들을 구현할 때 대용량 트래픽 환경을 가정하고 최대한 신중히 코드를 작성해 왔습니다. CI와 CD를 구현해서 배포를 하고 나니 그간 공들여 진행한 프로젝트를 직접 public한 환경에서도 사용해볼 수 있게 되었는데요. 그러면서 문득 실제로도 많은 트래픽을 수용할 수 있는지와, 그러한 환경 속에서도 얼마나 빠르고 안정적인 속도로 서비스를 제공할 수 있는지가 궁금해지게 되었습니다. 때문에 성능 테스트를 진행하게 되었으며, 이번 포스팅은 이러한 과정에서 제가 마주했던 문제점과 그러한 문제들을 해결해가는 과정을 공유해보고자 합니다.
성능테스트의 필요성
성능 테스트란 그 이름이 의미하는 것처럼 해당 서비스의 성능적인 측면을 직접 테스트해보는 것을 의미합니다. 모든 서비스는 목표를 가지고 있고, 이러한 목표를 달성하기 위해서는 서비스를 사용하는 이용자가 동시다발적으로 요청을 보낸다고 할 때, 어느 수준까지 안정적으로 처리가 가능해야 하는지에 대한 기준을 정하게 됩니다.
그리고 기능 구현이 끝나면, 직접 서버에 부하를 가하여 초기에 목표했던 수준의 성능을 낼 수 있는지 알아보게 되는데 이 과정이 바로 성능테스트입니다. 물론 실제 운영환경에는 예측할 수 없는 변수가 더욱 많이존재하기 때문에 모든 부분을 테스트해 볼 수는 없지만 성능테스트를 함으로써 기준 트래픽 속에서의 목표성능 달성여부를 알 수 있고, 기준에 미치지 못한다면 문제의 원인을 찾고(ex. 병목 발생지점) 이를 개선할 수 있는 지표를 획득할 수 있으므로 설계, 테스트만큼이나 중요한 단계라고 할 수 있습니다.
성능테스트의 기준 지표는?
여러 지표 중에서 성능을 측정할 때 가장 핵심이 되는 지표는 처리량(Throughput)과 응답시간(Response Time)입니다.
1) 처리량
처리량이란 서버가 일정시간 내 처리하는 트랜잭션의 양, 즉 간단하게 말하면 시간당 처리량을 의미합니다. 서비스를 사용자들이 필요한 내용을 얼마나 빠르게 처리할 수 있는지를 의미하며, 이를 측정하는 단위로는 주로 초당 처리하는 작업 수(TPS, Transaction Per Second), 초당 처리하는 페이지 수(PPS, Page Per Second), 초당 처리하는 히트 수(HPS, Hit Per Second) 등으로 다양합니다. 본 테스트에서는 TPS를 기준으로 사용하였습니다.
2) 응답속도
응답시간은 사용자가 요청(Request)을 보낸 후부터 응답(Response)을 받을 때까지 소요된 시간을 의미하며, 측정하는 위치에 따라 클라이언트 응답시간, 네트워크 응답시간, 서버 응답시간의 여러 유형으로 나뉘게 되는데요. 어떤 유형으로 측정을 결정하든 핵심은 응답시간은 빠르면 빠를 수록 더 좋다는 점이며, 네트워크 지연시간(latency) 또한 응답속도를 늦추는데 영향을 미친다는 점을 인지할 필요가 있습니다.
TPS 해석 시 주의점과 성능 개선
성능 측정을 진행하는 서버의 구조는 'Web Server - Web Application Server - Database'로 세 서버가 서로 연결되어 동작하고 있습니다. 때문에 각 서버의 사양이 다를 수 있고, 처리하는 내용 또한 각자의 성격에 따라 다르기에 대부분 서버마다 다른 TPS 수치를 가지게 점입니다.
예시)
종류 | Web Server | Web Application Server | Database |
TPS | 2000 | 2500 | 500 |
문제는 각 계층에 대한 TPS가 위와 같이 주어졌을 때, 전체 TPS는 어떻게 계산하는지에 대한 부분입니다. 이때 기억할 점은 가장 낮은 TPS를 가지고 있는 서버가 TPS가 전체 TPS를 결정한다는 것입니다. 4차선인 도로가 2차선으로 줄었다가 6차선으로 늘어난다고 했을 때, 4차선과 6차선 부분에 소통이 원할하더라도 2차선 구간으로 접어드는 순간 여러 선로에 분배되었던 차들이 두 개의 선로로 한 꺼번에 좁혀 들어와야 하므로 막히는 구간이 생기게 되는 것과 같은 이치입니다.
이처럼 각 서버 또한 TPS가 현저히 낮은 서버가 다른 서버의 전체 처리량을 따라가지 못해 막히는 구간(병목 지점)을 만들게 되므로 그 구간의 처리 속도가 전체 TPS가 되는 것입니다. 즉, 성능 개선이란 이처럼 전체 TPS를 저해하는 구간을 찾아 그 원인을 해결함으로써 서버의 전체적인 처리 성능을 목표에 맞게 끌어올리는 과정을 대변한다고 할 수 있습니다.
부하 도구 및 측정 도구 선택
서버에 부하를 가해줄 도구로는 nGrinder를 선택하였습니다. 오픈소스일 뿐만 아니라, 테스트 케이스를 작성할 때 자바와 비슷한 groovy를 활용해 스크립트로 작성할 수 있어 learning curve가 적을 뿐만 아니라 구상한 시나리오를 스크립트에 담아 직접 테스트해볼 수 있습니다.
또한 nGrinder는 위의 그림처럼 컨트롤러에 에이전트를 연결하는 방식으로 동작하기 때문에, Scale up이 제한되는 환경에서 Agent 서버의 사양이 부족하더라도 별도의 Agent 서버를 Scale out 방식으로 추가한 뒤 각 Agent 서버별로 vUser를 생성하도록 만들어줄 수 있기 때문에 부담 없이 부하 수를 줄이거나 늘릴 수 있다는 장점도 있었습니다.
Agent 외에도 성능을 측정할 대상 서버 구동시 nGrinder Monitor를 추가하면 구동하면 실시간 CPU, Memory 상태와 오류등에 대한 각종 정보를 받을 수 있습니다. 하지만 여기서는 트랜잭션 처리 시 좀 더 자세한 정보를 직관적으로 살펴볼 수 있도록 APM, 그 중에서도 nGrinder와 더불어 Naver에서 만든 오픈소스인 핀포인트(Pinpoint)를 사용하기로 했습니다.
(핀포인트의 특징과 사용하면서 얻을 수 있는 장점은 아래 링크로 대체하겠습니다.)
https://d2.naver.com/helloworld/1194202)
핀포인트가 제대로 작동하도록 만들기 위해서는 다양한 사전 구성요소(Hbase, flink, zookeeper 등)가 필수적이기에 설치가 상당히 복잡합니다. 그래서 Naver Cloud에서 SaaS(Software as a Service) 형식으로 서비스를 제공하고 있으므로 이것을 활용하면 좀 더 손쉽게 pinpoint를 활용할 수 있습니다. 다만 저의 경우에는 여러 지표를 보여주는 Inspector가 제대로 작동하지 않아서, 핀포인트 Docker 파일을 받아서 Docker Compose로 설치하여 사용했습니다. 도커의 경우도 네이버 클라우드와 마찬가지로 설치 시 필수요소가 모두 컨테이너에 들어있기 때문에 설치가 끝나면 별도의 설정 없이도 핀포인트 바로 사용이 가능합니다. 설치는 다음의 두 링크를 참고하였습니다.
1. 우분투에 도커 다운로드
https://velog.io/@dudu/Docker-Docker-compose-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0-Ubuntu-18.04
2. 도커 핀포인트 다운로드 후 설치하기
https://lemontia.tistory.com/806
측정할 서버는 이미 배포된 상태이고, 성능 테스트 환경도 구성이 완료되었으니 다음 포스팅부터는 실제 성능테스트를 진행하면서 발생했던 문제점과 이를 해결하는 과정을 본격적으로 살펴보도록 하겠습니다.
https://github.com/f-lab-edu/Hello-World
f-lab-edu/Hello-World
언어교환 상대찾기 서비스. Contribute to f-lab-edu/Hello-World development by creating an account on GitHub.
github.com