병렬로딩 및 버킷 인증&연결 사전 처리 후 부하 테스트 진행 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

1. 테스트 세팅 변경 사항

  • 사진 로딩 병렬 처리 (멀티 스레드)
  • 버킷 인증 및 연결 사전 처리

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

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("/")
def ping():
    return {"message": "FastAPI is running"}

@app.get("/images")
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 = list(executor.map(download, file_names))

    return JSONResponse(
        status_code=200,
        content={"message": f"이미지 {len(result)}장 로딩 완료"}
    )
  • 요청당 30~50장의 이미지 다운로드
  • 실패 시 즉시 500 응답 반환

c. 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. 회고

  • 주된 병목 지점들은 해결한 듯하다. 추가적으로 시간 단축할 수 있는 방안이 있는지 더 알아볼 예정.
  • 실수로 def 라우터로 구축했었다(요청들 직렬 처리됐었음) → async def 라우터로 변경하여 변경 처리하기