요청 병렬 처리 후 테스트 진행 - 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%
  • 이미지

    image


3. 회고

  • p95는 동일하지만 내부 수치 확인했을 때, 개선된 것을 볼 수 있다.