부하 테스트를 통해 FastAPI 웹 애플리케이션의 성능 최적화를 목적으로 진행한 내용입니다. 본 테스트는 Guicorn으로 Uvicorn의 워커 프로세스수를 조절하며 응답 속도를 비교하는 실험으로, 테스트느 AWS t2.medium instance 에서 진행했습니다.
Guicorn으로 워커 프로세스(uvicorn) 수를 조정하여 응답 속도를 확인.
uvicorn 자체적으로도 workers수를 지정하여 multi-processing을 지원하지만 제공하는 기능들이 제한적이라 공식문서에서 gunicorn과 함께 사용할 것을 권장합니다.
https://www.uvicorn.org/#running-with-gunicorn
아래는 InfluxDB와 Grafana를 실행하기 위한 docker-compose.yml입니다.
version: "3.7"
services:
influxdb:
image: bitnami/influxdb:1.8.5
container_name: influxdb
ports:
- "8086:8086"
- "8085:8088"
environment:
- INFLUXDB_ADMIN_USER_PASSWORD=bitnami123
- INFLUXDB_ADMIN_USER_TOKEN=admintoken123
- INFLUXDB_HTTP_AUTH_ENABLED=false
- INFLUXDB_DB=myk6db
granafa:
image: bitnami/grafana:latest
ports:
- "3000:3000"
Grafana 대시보드는 해당 링크에 있는 부하 테스트 템플릿을 사용했습니다.
k6의 options 객체를 사용해 테스트를 구성했습니다.
150명의 사용자가 동시에 요청하며, 요청은 20초간 지속됩니다.
(vus: 150, duration: 20s)
export const options = {
vus: 150,
duration: '20s',
};
사용자가 소유한 책 목록을 토큰기반으로 조회하는 API입니다.
export default function() {
// 그룹핑된 API 요청 테스트
group('Books API Performance', () => {
const params = {
headers: {
'Authorization': `Bearer ${USER_TOKEN}`,
'Content-Type': 'application/json'
}
};
const url = baseUrl + '/api/books';
// 책 목록 조회 API 호출
const bookResponse = http.get(url, params);
// 응답 검증
const checkResult = check(bookResponse, {
'status is 200': (r) => r.status === 200,
});
// 약간의 대기 시간 (실제 사용자 행동 시뮬레이션)
sleep(1);
});
}
Gunicorn의 worker process를 1부터 5까지 늘리면서 테스트를 진행한 결과값입니다.
gunicorn main:app -w "Number of workers" -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
워커 수 | 평균 응답 시간 (mean) | 최대 응답 시간 (max) | 중앙값 응답 시간 (med) |
---|---|---|---|
1 | 1.87s | 3.29s | 1.93s |
2 | 1.78s | 4.14s | 1.95s |
4 | 1.50s | 2.28s | 1.27s |
5 | 1.36s | 2.22s | 1.16s |
워커 수를 증가시킬수록 평균 응답 시간(mean) 및 중앙값 응답 시간(median)이 점진적으로 감소하는 경향을 보였으며, 응답시간이 최적화되는 워커 설정은 4~5개가 나타남을 볼 수 있었습니다. 이는 권장되는 worker 개수인 (2 x $num_cores) + 1 과 유사합니다.
위 테스트를 통해 Guicorn의 워커 프로세스를 적절히 설정하면 응답 시간을 단축할 수 있다는 것을 알 수 있게 되었습니다.