현재 이력서를 작성하고 있는데, 성능 테스트 관련 내용을 정리해 작성하려 한다.
기존에 성능 테스트를 수행하고 작성한 내용이 있다. 이때, Prometheus, Grafana를 통해 모니터링 환경을 구축하고 JMeter를 사용해 대용량 트래픽 성능 테스트를 수행했는데 JMeter 사용법과 제대로된 성능 테스트 방법을 자세히 알지 못했다.
그래서 이번을 계기로 성능 테스트 관련 내용을 확실히 하고 넘어가려 한다.
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/040.gif)
성능 테스트란?
백엔드 애플리케이션에서 성능 테스트란?
백엔드 애플리케이션의 성능 테스트는 특정 워크로드에서 애플리케이션의 안정성, 속도, 확장성 및 반응성이 어떻게 유지되는지를 판별하는 과정이다. 이것은 애플리케이션의 성능을 측정하고, 개선할 수 있는 영역을 식별하기 위해 수행된다. 🚀
성능 테스트의 사전적 정의: 특정 워크로드에서 애플리케이션의 안정성, 속도, 확장성 및 반응성을 판별하는 과정
- 중요성: 백엔드 애플리케이션의 성능은 사용자 경험에 직접적인 영향을 미치며, 성능 문제는 사용자 만족도 저하로 이어질 수 있다.
- 따라서 성능 테스트를 통해 이러한 문제를 사전에 발견하고 개선하는 작업이 중요하다!!
성능 테스트 예시
- API 성능 테스트: 백엔드 애플리케이션에서 API의 응답 시간, 처리량 등을 측정하는 테스트
- 스트레스 테스트: 시스템이나 애플리케이션에 과도한 부하를 주어 최대 용량이나 한계점을 확인하는 테스트
- 이를 통해 애플리케이션의 안정성과 오류 처리 능력을 평가할 수 있다.
성능 테스트를 통해 백엔드 애플리케이션의 성능을 체계적으로 분석하고 개선할 수 있다.
사용자 경험을 최적화하고, 애플리케이션의 안정성을 확보하기 위해 정기적인 성능 테스트가 중요하다! 🌟
성능 개선 방법 예시
- 비효율적으로 동작하는 애플리케이션 로직 개선 -> GC 등
- 데이터베이스 같은 저장소에 대한 성능 개선 -> 인덱스, 데드락 등
- 시스템 설계 개선 -> 비동기적인 구조, Circuit Breaker 등
성능 테스트 배경지식
지연시간(Latency): 요청이 처리되고 응답이 반환되기까지 걸리는 시간 즉, 얼마나 빠르게 작업을 완료할 수 있는지를 나타내는 지표 (단위: ms, s)
처리량(Throughput): 단위 시간당 시스템이 처리할 수 있는 작업의 양 (단위: tps)
이러한 지연시간과 처리량은 성능 테스트에서 다음과 같이 사용될 수 있다.
ex) 초당 3000개 의 요청(처리량)이 들어올 때 99%의 요청이 100ms 미만으로 처리(지연시간)된다.
-> 99%라는 기준이 있는 이유는, 100%의 요청이 100ms 미만으로 처리되도록 만드는 것은 거의 불가능하기 때문이다.(성능 테스트에는 많은 변수가 존재한다.)
지연시간과 처리량 사이의 관계
지연 시간과 처리량을 같이 다루는 이유는 서로 비례하기 때문이다.
처리량이 낮다면 지연시간도 아주 낮을 것이고, 반대로 처리량이 높다면 지연시간도 높을 것이기 때문이다.
(처리량이 많아지면 서버가 점점 바빠지고 자원이 부족해져 요청을 처리하기 위한 대기 시간이 필요하다.)
운영체제와 서버 자원
컴퓨터의 자원은 절대 무한하지 않다!!🤨
서버에서 특정 자원이 이미 많이 사용되고 있는 상태라면, 해당 자원이 필요한 추가 요청이 왔을 때 처리가 지연될 수 있다.
따라서 성능 테스트를 수행할 때 서버가 가진 자원 중 사용률이 높은 자원(병목)이 있다면, 해당 자원의 사용률을 낮추는 방법을 고민해야 한다. 이를 위해 서버 자원에 대한 모니터링 역시 함께 진행 되어야 한다.
CPU, 메모리(RAM), 디스크
CPU (Central Processing Unit)
- 정의: 컴퓨터의 두뇌 역할을 하는 중앙 처리 장치로, 컴퓨터 프로그램의 명령어를 해석하고 처리하는 핵심 부품
- 쓰임새: 프로그램의 명령어 실행, 데이터 처리, 시스템 제어 등 컴퓨터의 모든 계산과 처리 작업
- ex) 암호화, 해시화
메모리 (RAM)
- 정의: 컴퓨터가 현재 사용 중인 데이터와 프로그램을 일시적으로 저장하는 공간
- 쓰임새: CPU가 직접 접근하여 빠르게 데이터를 읽고 쓸 수 있어, 프로그램 실행 속도와 직접적인 관련이 있다.
- CPU와 함께 많이 쓰인다.
- ex) 인스턴스 대량 생성, 캐싱, 컬렉션 객체 등
디스크 (HDD, SSD)
- 정의: 데이터를 영구적으로 저장하는 장치로, 하드 디스크 드라이브(HDD)와 솔리드 스테이트 드라이브(SSD) 등이 있다.
- 쓰임새: 운영 체제, 프로그램, 사용자 데이터 등 저장, 파일 입출력, 로그 대량 발생, 컴퓨터의 전원 상태와 관계없이 데이터를 보존한다.
- ex) 데이터베이스 데이터 대량 입출력
CPU, 메모리(RAM), 디스크 간 상호작용
- CPU와 메모리: CPU는 메모리로부터 명령어를 읽어 실행하며, 메모리는 CPU가 필요로 하는 데이터를 저장한다. CPU와 메모리 간의 상호작용은 시스템의 성능에 큰 영향을 미친다.
- CPU는 프로세스가 가진 코드에 따라 실행시킨다.
- 이때, 메모리는 코드에 작성된 내용대로 사용된다.
- 메모리와 디스크: 메모리는 빠르지만 휘발성이 있는 반면, 디스크는 느리지만 비휘발성 저장 공간을 제공한다. 프로그램 실행 시, 디스크에서 메모리로 데이터가 로드되며, 이 과정은 시스템의 전반적인 성능에 영향을 준다.
- 디스크에는 exe 파일, jar 파일 등의 프로그램(Program)이 저장되어 있다.
- 프로그램을 실행시키면 메모리(RAM) 위에서 프로세스(Process) 형태로 실행된다.
- 이때, 프로세스는 메모리(Stack, Heap 등)와 코드로 이루어진다.
- 가상 메모리를 사용하는 경우에도 메모리와 디스크는 서로 상호작용한다.
- PC에서 실행되는 프로세스 숫자가 많아지면 물리적인 램 위에서 모두 동작할 수 없다.
- 운영체제는 이러한 문제를해결하기 위해 메모리 내용 일부를 디스크에 저장했다가 다시 불러오는 작업을 수행한다.(페이징)
- CPU와 디스크: CPU는 디스크로부터 데이터를 직접 읽거나 쓰지 않는다. 대신, 디스크에서 메모리로 데이터를 로드한 후, CPU는 메모리로부터 데이터를 읽어 처리한다. 이 과정은 I/O 작업의 효율성에 따라 성능에 영향을 미친다.
네트워크
클라이언트가 서버에 요청을 보내면 서버는 데이터베이스나 또 다른 서버에 호출을 한다. 이때 당연히 네트워크 통신이 발생한다.
문제는 네트워크 통신이 매우 비용이 큰 작업이라는 것이다.
ex) 서버 내부 자원만을 사용하는 연산의 경우 일반적으로 1ms조차 걸리지 않는다. 그러나 데이터베이스나 외부 서버를 호출하는 경우 1ms를 넘기는 경우가 많다.
따라서, 클라이언트의 지연 시간을 줄이기 위해 네트워크 통신에서 성능 개선 부분을 찾는 것이 중요하다.🥸
주로 사용할 수 있는 방식은 캐시 또는 데이터베이스 최적화 작업이 존재한다.
예를 들어, 네이버 페이지 응답에 40ms 소요된다.
만약, 내가 구현한 API에서 네이버 페이지에서 응답을 받아 처리하는 작업이 포함되어 있다면 40ms 보다 오래 시간이 소요될 것이다.
그리고 당연히, 호출하는 API 간 물리적인 거리가 멀어질수록 응답 시간이 길어질 것이라 예측할 수 있다.
네트워크 대역폭과 지연시간 사이의 관계🌐💨
네트워크에서 대역폭과 지연시간은 서로 밀접한 관계를 가지고 있으며, 이 두 요소는 네트워크의 성능을 결정하는 중요한 요소다.
예시
- 대용량의 파일을 다운로드 하고 있을 때, 웹 서핑을 했더니 웹 페이지가 느리게 뜬다.
- 고해상도의 이미지가 많이 포함된 페이지에 접속한 경우 이미지가 느리게 로딩된다.
대역폭이 네트워크의 전송 용량을 결정한다면, 지연시간은 그 전송의 신속성을 결정한다. 따라서 네트워크 성능을 최적화하기 위해서는 높은 대역폭과 낮은 지연시간이 모두 중요하다. 특히 실시간 통신이 중요한 애플리케이션에서는 지연시간을 최소화하는 것이 매우 중요하다.
데이터베이스
데이터베이스는 애플리케이션의 성능에 직접적인 영향을 미치는 핵심 요소 중 하나이다.
데이터베이스 선택, 구성 및 최적화는 애플리케이션의 응답 시간, 처리량 및 확장성에 큰 영향을 미친다.
데이터베이스도 일종의 애플리케이션이다.
데이터베이스 또한 운영체제에 의해 실행되는 프로세스이다.
따라서, CPU, 메모리 그리고 디스크를 사용해 백엔드 애플리케이션이 요구하는 데이터 저장이나 조회 기능을 수행한다.
디스크(데이터 저장) <-> 메모리(RAM, CPU가 데이터를 연산할 수 있도록 준비 혹은 캐시) <-> CPU(사용자가 원하는 데이터인지 확인)
즉, 데이터베이스 또한 다른 프로세스들과 마찬가지로 작업에 디스크, 메모리, CPU가 사용된다.
그러므로 처리량이 갑자기 증가하게 되면 지연시간이 길어질 수 밖에 없다.
데이터 양
또한, 데이터베이스는 수많은 데이터가 저장되어 있다. 그러므로 데이터 양은 속도에 영향을 미칠 수 밖에 없다.
예를 들어, 10억건의 데이터가 저장된 데이터베이스와 10만건의 데이터가 저장된 데이터베이스에서 특정 값을 찾을 때 당연히 10억건의 데이터가 저장된 데이터베이스가 더 오랜 시간이 소요될 것이다.
이러한 문제를 해결하고자 검색 조건에 인덱스를 사용하고는 한다.
데이터베이스 락
데이터베이스 락은 동시에 여러 사용자나 애플리케이션이 데이터베이스에 접근할 때 데이터의 일관성과 무결성을 유지하기 위해 사용된다.
데이터베이스 락은 특정 스레드가 데이터를 제어하고 있는 경우 다른 스레드의 접근을 막는 메커니즘을 의미하며, 동시성 문제와 관련 있다.
트랜잭션을 지원하기 위해 데이터에 락이 걸린다.
-> 락이 걸리는 만큼 대기시간(지연시간)이 발생한다. 때로는 데드락이 발생하여 응답이 처리되지 않기도 한다.
데드락(Deadlock) 또는 교착 상태
데드락이란, 여러 프로세스나 스레드가 서로의 자원을 사용하기 위해 무한히 대기하는 상태를 의미한다. 이는 주로 한정된 자원을 여러 프로세스에서 동시에 사용하려고 할 때 발생한다. 각 프로세스가 다른 프로세스가 점유하고 있는 자원을 기다리면서 아무런 진행도 이루어지지 않는 상태가 되는 것이다 🔄.
데드락의 발생 조건
데드락이 발생하기 위해서는 다음 네 가지 조건이 모두 충족되어야 한다:
1. 상호 배제 (Mutual Exclusion): 한 번에 하나의 프로세스만이 자원을 사용할 수 있다.
2. 점유 대기 (Hold and Wait): 최소한 하나의 자원을 점유하면서 다른 프로세스가 점유한 자원을 추가로 기다리는 프로세스가 있어야 한다.
3. 비선점 (No Preemption): 다른 프로세스에게 자원을 강제로 빼앗을 수 없다.
4. 순환 대기 (Circular Wait): 대기하는 프로세스 간에 순환 형태의 체인이 형성되어야 한다
데드락 해결 방법 🛠️
1. 데드락 예방 (Deadlock Prevention): 데드락 발생 조건 중 하나 이상을 의도적으로 제거하여 데드락이 발생하지 않도록 하는 방법
2. 데드락 회피 (Deadlock Avoidance): 자원 할당 시 데드락의 가능성을 회피하는 방식, ex) 은행원 알고리즘
3. 데드락 탐지 및 회복 (Deadlock Detection and Recovery): 데드락이 발생했을 때 이를 탐지하고, 해결하기 위해 프로세스를 종료하거나 할당된 자원을 해제하는 방법
비관적 락과 낙관적 락
- 비관적 락 (Pessimistic Lock): 트랜잭션이 데이터에 접근하기 전에 락을 걸어 다른 트랜잭션이 해당 데이터에 접근하지 못하게 하는 방식
- 충돌이 자주 발생하는 환경에서 유리하며, 데이터 무결성을 높은 수준으로 보장할 수 있다.
- 하지만 동시성이 떨어져 성능 손해를 볼 수 있다.
- 낙관적 락 (Optimistic Lock): 데이터에 락을 걸지 않고, 트랜잭션이 커밋되는 시점에 데이터가 변경되었는지 확인하여 충돌을 처리하는 방식
- 충돌 가능성이 낮은 상황에서 성능이 좋으며, DB가 제공하는 락 기능을 사용하지 않고 어플리케이션 레벨에서 처리한다.
SSD, HDD
SSD는 HDD에 비해 용량이 작지만 속도가 훨씬 빠르다는 특징을 가진다.
이러한 특징을 살려 데이터베이스로 SSD를 사용하고는 한다. 이때 문제가 되는 부분은 비용이다. 동일한 용량을 가질 때, HDD보다 SSD가 비쌀 수 밖에 없다.
즉, 성능이 중요하다면 SSD 사용을 적극 검토해야 한다.
SSD와 HDD를 혼합해서 사용하기도 한다.
최근 저장되었거나 자주 사용하는 데이터는 SSD에 저장하고, 오래 전에 저장되었거나 거의 사용되지 않는 데이터들은 HDD에 저장하는 방식으로~
성능 테스트 관점에서의 데이터베이스
- 데이터베이스 스키마 및 인덱스 최적화: 데이터베이스 스키마와 인덱스를 최적화하여 검색 속도를 향상시키고, 자원 사용을 최소화한다.
- 쿼리 성능 분석: 쿼리 실행 계획을 분석하여 비효율적인 쿼리를 식별하고 최적화한다.
- 커넥션 및 트랜잭션 관리: 데이터베이스 커넥션 풀과 트랜잭션 관리 전략을 최적화하여 자원 사용을 효율적으로 관리한다.
성능 테스트에서 고려사항
- 락의 종류와 설정 범위: 데이터베이스 락의 종류와 락을 거는 범위(DB, 파일, 테이블, 페이지, 컬럼, 행 등)에 따라 성능에 미치는 영향이 달라진다.
- 반드시 락의 범위와 방식에 대해 파악해야 한다.
- 락을 좀 더 좁은 범위의 데이터에 그리고 더 짧은 시간 동안만 사용하도록 해야한다.
- 데드락과 성능 저하: 비관적 락을 사용할 경우, 데드락 발생 가능성과 성능 저하 문제를 주의해야 한다.
- 성능 테스트 과정에서 데드락 발생 여부와 성능 저하를 모니터링하고, 최적의 락 전략을 수립해야 한다.
스레드 풀과 커넥션 풀
스레드 풀과 커넥션 풀은 시스템의 성능과 자원 활용을 최적화하기 위해 널리 사용되는 기술이다. 성능 테스트를 통해 이러한 풀의 설정이 시스템에 미치는 영향을 평가할 수 있다. 📊
데드락이 발생하게 되면 대기 상태가 되기 때문에 실질적으로 서버의 물리 자원을 많이 소모하지는 않지만, 스레드풀이나 커넥션풀처럼 제한적인 숫자만 생성되는 자원은 빠르게 소모된다.
트래픽이 늘어나다 보면 결국 모든 스레드가 사용 중인 상태가 될 것이다. 이때 요청은 큐에 저장되었다가 스레드가 처리하지만, 큐 역시 한계가 존재한다.
스레드 풀 성능 테스트
- 스레드 수 조절: 스레드가 너무 많으면 CPU 자원을 과도하게 사용하여 시스템의 성능이 저하될 수 있고, 너무 적으면 CPU 자원을 충분히 활용하지 못해 성능이 떨어질 수 있다.
- 차라리 로드 밸런싱을 통해 여러 서버가 트래픽을 받도록 개선하거나 비동기 방식을 사용하는 것이 좋다.
- 멀티스레딩 vs 스레드 풀: 실제 성능 테스트와 분석을 통해 스레드 풀이 멀티스레딩에 비해 어떤 성능 이점을 제공하는지 평가할 수 있다.
백엔드 애플리케이션 수만 늘린다고 해결되지 않는다.
백엔드 애플리케이션이 다른 요소에 의존하고 있다면 해당 요소가 병목(Bottleneck)이 된다.
이때 병목이 되는 부분을 개선하거나 시스템 설계 자체를 변경해야 할 수도 있다.
커넥션 풀도 동일하다.
커넥션풀 또한 스레드풀과 마찬가지로 데이터베이스와의 커넥션을 미리 생성해두고 사용한다.
이로 인해, 처리량이 급격하게 늘어나면 커넥션풀 역시 빠르게 고갈될 수 있다.
성능 테스트의 방향성
실무 환경에서의 성능 테스트와 실무가 아닌 환경(예: 개발 또는 테스트 환경)에서의 성능 테스트는 여러 면에서 차이가 있다. 📊
실무 환경에서는 많은 처리량을 감당할 수 있는 충분한 인프라를 투입할 수 있지만, 실무가 아닌 경우 인프라를 제대로 구성해서 테스트하기 어렵다는 점이 있다.
실무 환경에서의 성능 테스트
- 환경의 복잡성: 실무 환경은 사용자의 실제 요청, 네트워크 트래픽, 데이터베이스의 부하 등 다양한 요소가 복합적으로 작용한다. 이로 인해 테스트 환경을 실제와 동일하게 구성하는 것이 중요하다.
- 리얼리티: 실제 사용자의 행동 패턴, 피크 타임 동안의 트래픽, 예상치 못한 시스템의 오류 등을 고려하여 테스트를 진행한다. 이는 실제 운영 환경에서 발생할 수 있는 문제를 사전에 발견하고 대비할 수 있게 한다.
- 성능 목표 설정: 실무 환경에서는 비즈니스 목표와 사용자의 기대치를 충족시키기 위한 성능 목표를 설정한다. 이를 기반으로 성능 테스트를 계획하고 실행한다.
ex) 동시접속자는 3,000명 정도로 예상되고, 이 사용자들이 발생시키는 요청은 1,000tps 정도 될 것이다.
이때, 99%의 요청은 지연시간이 50ms 미만으로 유지되어야 한다.
→ 예상되는 트래픽을 감당하기 위해 성능 테스트, 튜닝을 진행하고 필요하다면 충분한 인프라 자원을 투입할 수 있다.
실무가 아닌 환경에서의 성능 테스트
- 환경의 단순성: 개발 또는 테스트 환경에서의 성능 테스트는 실제 운영 환경보다 단순할 수 있다. 이는 테스트의 목적이 시스템의 기본적인 성능 문제를 식별하고 해결하는 데 있기 때문이다.
- 테스트의 유연성: 실무가 아닌 환경에서는 다양한 성능 테스트 시나리오를 빠르게 시도해볼 수 있다. 이는 개발 초기 단계에서 성능 문제를 식별하고 개선할 수 있는 기회를 제공한다.
- 리소스와 비용: 실무 환경과 동일한 규모의 테스트 환경을 구축하는 것은 비용과 리소스 측면에서 비효율적일 수 있다. 따라서, 실무가 아닌 환경에서는 보다 제한된 리소스로 테스트를 진행하게 된다.
ex)
1. 우선 한건씩 요청을 보내 지연시간(Latency)가 어느정도 나오는지 테스트해보기
2. 처리량(Throughput)을 높이면서 현재 인프라 구성에서 지연시간이 치솟는 지점 찾아보기
3. 어떤 부분이 병목이 되는건지 가설을 세워보고 서버 자원 모니터링, 로그 등을 통해 병목 지점 탐색
성능 개선 방법은 다양하다. 예를 들어 애플리케이션의 로직을 개선하거나 인덱스를 추가하는 방법이 해결 방법이 될 수 있고아니면 시스템 설계를 전체적으로 바꾸는 게 좋은 해결 방법이 될 수도 있다.
참고
애플리케이션 성능 테스트 / 모니터링
성능 테스트 성능 테스트란? 특정 워크로드에서 애플리케이션의 안정석과 속도, 확장성 및 반응성이 어떻게 유지되는지를 판별하는 과정 소프트웨어의 품질을 보장하는 방법이지만 나중에 고
velog.io
성능 테스트란 무엇입니까? 유형, 사례, 도구 및 기타!
이점, 과제 및 성능 테스트 유형에서 무료 및 자동화 도구에 이르기까지 성능 테스트가 무엇인지 알아야 할 모든 것을 배우십시오!
www.zaptest.com