Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@ package-lock.json
package.json

### temp directory ###
/temp/
/temp/

### K6 performance reports ###
k6/results/*
!k6/results/.gitkeep
89 changes: 89 additions & 0 deletions k6/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# DEVNOGI Batch 조회 API K6 실행 가이드

`batch_readonly_portfolio.js`는 BATCH 서버에 존재하는 조회 전용 API 20종을 운영 도메인과 로컬 도메인에서 같은 방식으로 측정하기 위한 K6 시나리오다.

## 실행 스크립트

```bash
cd open-api-batch-server
./k6/run-batch-readonly.sh [target] [profile]
```

## Target

| target | 기본 BASE_URL | TARGET_MODE | 설명 |
|---|---|---|---|
| `local` | `http://localhost:8090` | `local-batch` | batch 서버 직접 호출 |
| `prod` | `https://www.memonogi.com` | `proxy` | 운영 사용자 경로(`/api/*`) 호출 |
| `custom` | 환경 변수 `BASE_URL` 필수 | 기본 `local-batch` | 임의 도메인/포트 |

## Profile

| profile | RATE | DURATION | VU 설정 | 용도 |
|---|---:|---|---|---|
| `smoke` | 2 req/s | 20s | pre 3, max 6 | 조회 API 20종 상태 확인 |
| `portfolio` | 4 req/s | 2m | pre 5, max 10 | 포트폴리오 제출용 기본 측정 |
| `load` | 10 req/s | 5m | pre 15, max 30 | 로컬/개발 환경 부하 확인 |

모든 값은 환경 변수로 덮어쓸 수 있다.

```bash
RATE=6 DURATION=3m ./k6/run-batch-readonly.sh local portfolio
```

실제 API 호출 없이 저장 경로와 실행 설정만 확인하려면 `DRY_RUN=1`을 사용한다.

```bash
DRY_RUN=1 ./k6/run-batch-readonly.sh prod portfolio
```

## 결과 저장 규칙

실행할 때마다 `yyyyMMdd_HHmmSS` 형식의 `RUN_ID`가 자동 생성된다.

```text
k6/results/
local/
20260514_081500/
batch_readonly_local_portfolio_20260514_081500.md
batch_readonly_local_portfolio_20260514_081500.json
batch_readonly_local_portfolio_20260514_081500.log
batch_readonly_local_portfolio_20260514_081500.env
prod/
20260514_082000/
batch_readonly_prod_portfolio_20260514_082000.md
batch_readonly_prod_portfolio_20260514_082000.json
batch_readonly_prod_portfolio_20260514_082000.log
batch_readonly_prod_portfolio_20260514_082000.env
```

| 파일 | 내용 |
|---|---|
| `.md` | 포트폴리오에 붙일 수 있는 Markdown 결과 리포트 |
| `.json` | K6 summary 원본과 endpoint별 상세 지표 |
| `.log` | K6 콘솔 출력 전체 |
| `.env` | 실행 당시 target/profile/부하 설정 |

## 자주 쓰는 명령

```bash
# 로컬 batch 서버 직접 측정
./k6/run-batch-readonly.sh local portfolio

# 운영 도메인 사용자 경로 측정
./k6/run-batch-readonly.sh prod portfolio

# 로컬 smoke 테스트
./k6/run-batch-readonly.sh local smoke

# localhost:8092 같은 임의 포트 측정
BASE_URL=http://localhost:8092 TARGET_MODE=local-batch \
./k6/run-batch-readonly.sh custom smoke
```

## 주의사항

- 시나리오는 GET 조회 API만 호출한다.
- 인증 필요 API, 관리자 API, batch sync/write API는 제외한다.
- 운영 도메인에서 `load` 프로필은 서비스 영향이 있을 수 있으므로 트래픽이 적은 시간대에만 사용한다.
- JMeter는 이 저장소에 별도 시나리오를 추가하지 않았다. 현재 표준 산출물은 K6 Markdown/JSON 리포트다.
1 change: 1 addition & 0 deletions k6/results/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

143 changes: 143 additions & 0 deletions k6/run-batch-readonly.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/env bash
# DEVNOGI batch read-only API K6 runner.
#
# Usage:
# cd open-api-batch-server
# ./k6/run-batch-readonly.sh local smoke
# ./k6/run-batch-readonly.sh local portfolio
# ./k6/run-batch-readonly.sh prod portfolio
# BASE_URL=http://localhost:8092 TARGET_MODE=local-batch ./k6/run-batch-readonly.sh custom smoke

set -euo pipefail

BATCH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SCRIPT_PATH="${BATCH_ROOT}/k6/scenarios/batch_readonly_portfolio.js"

TARGET="${1:-local}"
PROFILE="${2:-portfolio}"
RUN_ID="${RUN_ID:-$(date +%Y%m%d_%H%M%S)}"
OUT_ROOT="${OUT_ROOT:-${BATCH_ROOT}/k6/results}"

case "${TARGET}" in
local)
BASE_URL="${BASE_URL:-http://localhost:8090}"
TARGET_MODE="${TARGET_MODE:-local-batch}"
;;
prod|production)
TARGET="prod"
BASE_URL="${BASE_URL:-https://www.memonogi.com}"
TARGET_MODE="${TARGET_MODE:-proxy}"
;;
custom)
if [ -z "${BASE_URL:-}" ]; then
echo "[ERR] custom target requires BASE_URL." >&2
exit 1
fi
TARGET_MODE="${TARGET_MODE:-local-batch}"
;;
*)
echo "[ERR] Unknown target: ${TARGET}" >&2
echo " Use one of: local | prod | custom" >&2
exit 1
;;
esac

case "${PROFILE}" in
smoke)
RATE="${RATE:-2}"
DURATION="${DURATION:-20s}"
PRE_ALLOCATED_VUS="${PRE_ALLOCATED_VUS:-3}"
MAX_VUS="${MAX_VUS:-6}"
;;
portfolio)
RATE="${RATE:-4}"
DURATION="${DURATION:-2m}"
PRE_ALLOCATED_VUS="${PRE_ALLOCATED_VUS:-5}"
MAX_VUS="${MAX_VUS:-10}"
;;
load)
RATE="${RATE:-10}"
DURATION="${DURATION:-5m}"
PRE_ALLOCATED_VUS="${PRE_ALLOCATED_VUS:-15}"
MAX_VUS="${MAX_VUS:-30}"
;;
*)
echo "[ERR] Unknown profile: ${PROFILE}" >&2
echo " Use one of: smoke | portfolio | load" >&2
exit 1
;;
esac

if [ ! -f "${SCRIPT_PATH}" ]; then
echo "[ERR] K6 scenario not found: ${SCRIPT_PATH}" >&2
exit 1
fi

RESULT_DIR="${OUT_ROOT}/${TARGET}/${RUN_ID}"
REPORT_BASENAME="batch_readonly_${TARGET}_${PROFILE}_${RUN_ID}"
REPORT_MD="${RESULT_DIR}/${REPORT_BASENAME}.md"
REPORT_JSON="${RESULT_DIR}/${REPORT_BASENAME}.json"
CONSOLE_LOG="${RESULT_DIR}/${REPORT_BASENAME}.log"
RUN_META="${RESULT_DIR}/${REPORT_BASENAME}.env"

mkdir -p "${RESULT_DIR}"

cat > "${RUN_META}" <<EOF
RUN_ID=${RUN_ID}
TARGET=${TARGET}
PROFILE=${PROFILE}
BASE_URL=${BASE_URL}
TARGET_MODE=${TARGET_MODE}
RATE=${RATE}
DURATION=${DURATION}
PRE_ALLOCATED_VUS=${PRE_ALLOCATED_VUS}
MAX_VUS=${MAX_VUS}
REPORT_MD=${REPORT_MD}
REPORT_JSON=${REPORT_JSON}
CONSOLE_LOG=${CONSOLE_LOG}
EOF

echo "[INFO] DEVNOGI batch read-only K6 test"
echo "[INFO] target : ${TARGET}"
echo "[INFO] profile : ${PROFILE}"
echo "[INFO] base url : ${BASE_URL}"
echo "[INFO] target mode : ${TARGET_MODE}"
echo "[INFO] load : ${RATE} req/s, ${DURATION}, preVUs=${PRE_ALLOCATED_VUS}, maxVUs=${MAX_VUS}"
echo "[INFO] result dir : ${RESULT_DIR}"
echo "[INFO] markdown : ${REPORT_MD}"
echo "[INFO] json : ${REPORT_JSON}"
echo "[INFO] console log : ${CONSOLE_LOG}"

if [ "${DRY_RUN:-0}" = "1" ]; then
echo "[INFO] DRY_RUN=1, skip k6 execution."
echo "[INFO] saved metadata: ${RUN_META}"
exit 0
fi

if ! command -v k6 >/dev/null 2>&1; then
echo "[ERR] k6 is not installed. Install with: brew install k6" >&2
exit 1
fi

set +e
BASE_URL="${BASE_URL}" \
TARGET_MODE="${TARGET_MODE}" \
RATE="${RATE}" \
DURATION="${DURATION}" \
PRE_ALLOCATED_VUS="${PRE_ALLOCATED_VUS}" \
MAX_VUS="${MAX_VUS}" \
REPORT_MD="${REPORT_MD}" \
REPORT_JSON="${REPORT_JSON}" \
k6 run "${SCRIPT_PATH}" 2>&1 | tee "${CONSOLE_LOG}"
exit_code=${PIPESTATUS[0]}
set -e

echo "[INFO] saved metadata: ${RUN_META}"

if [ "${exit_code}" -eq 0 ]; then
echo "[OK] K6 test completed."
else
echo "[WARN] K6 test finished with exit code ${exit_code}." >&2
fi

exit "${exit_code}"
Loading
Loading