#!/usr/bin/env bash # # LPS 부하 테스트 — Locust 웹 UI(GUI) 실행 (대화형). # 브라우저(:8089)에서 동시 유저 수·spawn rate 를 조절하며 실시간 그래프로 RPS/지연을 본다. # 대상 = API 서버(web_main, :9600). enqueue/조회 경로에 부하를 준다. # # ⚠️ 워커는 끄고 실행하라 — 부하 중 실제 크롤(프록시/AI 비용)이 발생한다. # 쌓인 부하 잡 정리: psql -h 127.0.0.1 -U postgres -d lps_db -c "TRUNCATE job;" # set -euo pipefail cd "$(dirname "$0")" # lps/ VENV=".venv" PY="$VENV/bin/python" LOCUST="$VENV/bin/locust" HOST="http://localhost:9600" PORT=9600 WEBUI_PORT=8089 # 1) venv + locust 보장 if [[ ! -d "$VENV" ]]; then echo "[setup] venv 생성 + 의존성 설치..." python3 -m venv "$VENV" "$PY" -m pip install -q --upgrade pip "$PY" -m pip install -q -r requirements.txt fi if [[ ! -x "$LOCUST" ]]; then echo "[setup] locust 설치..."; "$PY" -m pip install -q locust fi # 2) 워커가 떠 있으면 경고(부하 중 실제 크롤=비용) if pgrep -f worker_main.py >/dev/null 2>&1; then echo "[warn] 워커(worker_main.py)가 실행 중입니다 — 부하 중 실제 크롤 비용(프록시/AI)이 발생합니다." read -rp " 워커를 종료할까요? [Y/n]: " k [[ "${k:-Y}" =~ ^[Nn] ]] || { pkill -f worker_main.py || true; sleep 1; echo " 워커 종료"; } fi # 3) API 기동 확인 — 없으면 띄울지 물어본다 API_STARTED="" if curl -s "$HOST/healthz" >/dev/null 2>&1; then echo "[info] API 서버 감지됨 ($HOST)" else echo "[info] API 서버($HOST)가 응답하지 않습니다." read -rp " 이 스크립트가 API 를 띄울까요? [Y/n]: " s if [[ ! "${s:-Y}" =~ ^[Nn] ]]; then read -rp " 멀티코어 PROCESS_COUNT [1] (풀은 자동 산정): " PC; PC="${PC:-1}" echo " [run] web_main.py (PROCESS_COUNT=$PC) 백그라운드 기동..." PROCESS_COUNT="$PC" APP_ENV=local "$PY" web_main.py > /tmp/lps_api_loadtest.log 2>&1 & API_STARTED=$! for _ in $(seq 1 20); do curl -s "$HOST/healthz" >/dev/null 2>&1 && break; sleep 1; done if curl -s "$HOST/healthz" >/dev/null 2>&1; then echo " API 기동 완료 (로그: /tmp/lps_api_loadtest.log)" else echo " [error] API 기동 실패 — /tmp/lps_api_loadtest.log 확인"; kill "$API_STARTED" 2>/dev/null || true; exit 1 fi else echo " [안내] 먼저 다른 터미널에서 ./run_local_server.sh 로 API 를 띄우세요."; exit 1 fi fi # 4) 부하 생성기 멀티프로세스(locust 자체가 병목되지 않게). 코어 많으면 늘린다. CORES=$("$PY" -c "import os;print(os.cpu_count())") read -rp "부하 생성기 프로세스 수 --processes [4] (CPU=$CORES): " LP; LP="${LP:-4}" # API 를 이 스크립트가 띄웠으면 종료 시 함께 내린다 cleanup() { [[ -n "$API_STARTED" ]] && { echo ""; echo "[info] 스크립트가 띄운 API 종료"; kill "$API_STARTED" 2>/dev/null || true; }; } trap cleanup EXIT echo "" echo "════════════════════════════════════════════════════════" echo " Locust 웹 UI: http://localhost:$WEBUI_PORT" echo " 대상 API : $HOST" echo " → 브라우저에서 users/spawn rate 입력 후 START" echo " 중단: Ctrl+C · 끝나면 쌓인 잡 정리:" echo " psql -h 127.0.0.1 -U postgres -d lps_db -c 'TRUNCATE job;'" echo "════════════════════════════════════════════════════════" echo "" # API 를 이 스크립트가 띄웠으면 exec 하지 않는다(종료 시 trap 으로 API 를 함께 내리기 위해). if [[ -n "$API_STARTED" ]]; then "$LOCUST" -f loadtest/locustfile.py --host "$HOST" --web-port "$WEBUI_PORT" --processes "$LP" else exec "$LOCUST" -f loadtest/locustfile.py --host "$HOST" --web-port "$WEBUI_PORT" --processes "$LP" fi