요청 병렬 처리 후 테스트 진행 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki
1. 테스트 세팅 변경 사항
- def → async def : 요청 병렬 처리
a. VM 인프라 구성
역할 | 인스턴스 스펙 | 설명 |
---|---|---|
FastAPI 서버 | n2d-standard-4 (vCPU 4개, 메모리 16GB) |
GCS에서 이미지 30~50개 다운로드 처리 |
K6 서버 | e2-medium (vCPU 2개, 메모리 4GB) |
테스트 트래픽 생성기 |
b. FastAPI 서버 코드 요약
from fastapi import FastAPI, Query
from typing import List
from fastapi.responses import JSONResponse
from concurrent.futures import ThreadPoolExecutor
from google.cloud import storage
from starlette.concurrency import run_in_threadpool
app = FastAPI()
# GCS 버킷 초기화 (앱 시작 시 1회)
client = storage.Client.from_service_account_json("team5-457107-91e3baf044af.json")
bucket = client.bucket("my-bucket1008")
# ThreadPoolExecutor 전역 재사용
executor = ThreadPoolExecutor(max_workers=10)
print("서버 준비 완료")
@app.get("/")
async def ping():
return {"message": "FastAPI is running"}
@app.get("/images")
async def get_images(file_names: List[str] = Query(...)):
def download(file_name):
# 객체 생성은 빠른 편이며 내부적으로 재사용
blob = bucket.blob(f"test-images/{file_name}")
_ = blob.download_as_bytes() # 다운로드 자체가 주요 I/O 비용
return file_name
# 병렬 다운로드
result = await run_in_threadpool(lambda: list(executor.map(download, file_names)))
return JSONResponse(
status_code=200,
content={"message": f"이미지 {len(result)}장 로딩 완료"}
)
- 요청당 30~50장의 이미지 다운로드
- 실패 시 즉시 500 응답 반환
c. K6 부하 테스트 스크립트
import http from 'k6/http';
import { sleep } from 'k6';
import { check } from 'k6';
export const options = {
vus: 30, // 동시 가상 유저 수
duration: '10m', // 테스트 시간
};
function getRandomImageList() {
const total = Math.floor(Math.random() * 21) + 30; // 30~50개
...
}
export default function () {
const query = getRandomImageList();
const res = http.get(`${BASE_URL}/images?${query}`);
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(Math.random() * 2 + 3);
}
2. 테스트 결과 요약
-
평균 응답 시간(P95): 약
1초
-
요청 성공률:
100%
지표 수치 P95 응답 시간 약 1초 실패율 0% -
이미지
3. 회고
- p95는 동일하지만 내부 수치 확인했을 때, 개선된 것을 볼 수 있다.