1. 내가 구성한 백엔드 서버는 1초당 몇 개의 요청을 견딜 수 있을까?
부하 테스트의 기본 개념
백엔드 서버를 구현하고 나서 배포를 하게 될 경우 요청이 몰려서 서버가 터질까 봐 불안하다거나 내 서버가 어느 정도의 사용자 요청을 견딜 수 있는지 궁금해질 수도 있음
- 이런 불안감을 없애기 위해 서비스를 배포하기 전, 백엔드 서버가 어느 정도의 요청을 견딜 수 있는지 부하 테스트를 해봐야 함
부하 테스트
- 실제 사용자인 척 요청을 막 보내서, 여러 사용자가 한 번에 몰리는 상황을 가정하여 많은 트래픽인 것처럼 서버에 때려보는 것
- Throughput(처리량)
- 서비스가 1초당 처리할 수 있는 작업량으로, 단위는 TPS(Transaction Per Second, 1초당 처리한 트랜잭션의 수)
우리가 구축한 서비스의 Throughput 측정하기
- EC2 - t3a.small
- Spring Boot & Redis
- RDS - t3.micro
2. 부하 테스트를 위한 환경 셋팅 (K6)
k6란?
k6는 사용자인 척 요청을 보내는 툴이다. 원래라면 사용자가 직접 서비스에 요청을 보내야 하는데, k6는 여러 명의 사용자를 대신해서 요청을 보낼 수 있다.
부하 테스트를 하기 위해 부하를 만들어내는 프로그램(부하 테스트 툴)을 사용해야 함
- 성능 비교를 위해 k6라는 부하 테스트 툴을 사용할 것임
- 부하 테스트 툴에는 k6 이외에도 ngrinder, jmeter, ab, locust 등 다양한 툴이 있음
k6를 사용하면 간단하고 빠르게 테스트할 수 있고, 높은 정확도와 고부하를 발생시킬 수 있는 부하 테스트 툴이기 때문에 현업에서도 자주 쓰임
윈도우 k6 설치 방법
1. Windows PowerShell을 관리자 모드로 실행해 아래 명령어 입력 (Chocolatey 패키지 매니저 설치)
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
2. 설치가 완료되면 choco 명령어를 사용해 k6 설치
choco install k6 --version 0.34.1
API에 부하를 주기 위해 k6 스크립트 작성
터미널에서 아래 명령어 입력
New-Item {파일명} -ItemType File
k6 스크립트
import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
http.get('http://{EC2 IP 주소}:8080/boards');
}
3. Redis를 적용하기 전후 Throughput(처리량) 비교해 보기
캐싱을 적용하기 전의 Throughput 측정
a. 캐싱 코드 주석 처리하기
@Service
public class BoardService {
...
// @Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size", cacheManager = "boardCacheManager")
public List<Board> getBoards(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
return pageOfBoards.getContent();
}
}
b. Spring Boot 서버 빌드 및 백그라운드 실행
- 백그라운드에서 실행시키기 위해선 명령어 뒤에 '&'를 붙이면 됨
# 스프링 프로젝트 경로로 들어가서 아래 명령어 실행
$ ./gradlew clean build -x test
# 정확한 테스트를 위해 Spring Boot 서버를 백그라운드에서 실행시키자.
$ cd build/libs
$ nohup java -jar -Dspring.profiles.active=prod {빌드된 jar 파일명} &
# 8080번 포트에 Spring Boot 서버가 잘 실행되고 있는 지 확인
$ lsof -i:8080
c. 로컬 환경에서 k6로 성능 테스트 해보기
- vus 30: vus는 Virtual Users의 약자로 30명의 가상 유저를 의미함
- --duration 10s: 부하 지속 시간 10초로 설정
# K6의 스크립트 파일이 위치한 경로에서 아래 명령어 실행시키기
$ k6 run --vus 30 --duration 10s {js 파일명}
평균적으로 1초에 3.2개의 요청을 처리했다는 뜻
- 즉, 이 서비스는 1초에 최대 처리할 수 있는 요청의 처리 개수가 3.2개라는 뜻임
- 현재 구축한 서비스에서 게시글 조회 API의 Throughput이 3.2 TPS임
캐싱을 적용시킨 후의 Throughput 측정
a. 캐싱 코드 주석 해제하기
@Service
public class BoardService {
...
@Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size", cacheManager = "boardCacheManager")
public List<Board> getBoards(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
return pageOfBoards.getContent();
}
}
b. Spring Boot 서버 빌드 및 백그라운드 실행
- 백그라운드에서 실행시키기 위해선 명령어 뒤에 '&'를 붙이면 됨
# 스프링 프로젝트 경로로 들어가서 아래 명령어 실행
$ ./gradlew clean build -x test
# 기존 서버 종료
$ lsof -i:8080
$ kill {PID 값}
# 정확한 테스트를 위해 Spring Boot 서버를 백그라운드에서 실행시키자.
$ cd build/libs
$ nohup java -jar -Dspring.profiles.active=prod {빌드된 jar 파일명} &
# 8080번 포트에 Spring Boot 서버가 잘 실행되고 있는 지 확인
$ lsof -i:8080
c. 로컬 환경에서 k6로 성능 테스트 해보기
- vus 30: vus는 Virtual Users의 약자로 30명의 가상 유저를 의미함 (API 요청을 보내는 사용자가 30명인 것처럼 부하 생성)
- --duration 10s: 부하 지속 시간 10초로 설정 (10초 동안 테스트를 유지)
# K6의 스크립트 파일이 위치한 경로에서 아래 명령어 실행시키기
$ k6 run --vus 30 --duration 10s {js 파일명}
평균적으로 1초에 222개의 요청을 처리했다는 뜻
- 즉, 이 서비스는 1초에 최대 처리할 수 있는 요청의 처리 개수가 222개라는 뜻임
- 현재 구축한 서비스에서 게시글 조회 API의 Throughput이 222 TPS임
4. 참고자료