test(lps): 부하테스트 상품셋 100종 카탈로그 분리 — 실제 입력 분포 재현

- loadtest/catalog.json 신설(실존 상품 100종): 규격만 54 · 모델포함 26 ·
  이름만 20 · 기준가 포함 7 (price→가격밴드 필터 경로 포함)
- loadtest.py 는 인라인 6종 대신 카탈로그 로드, 실행 시 구성 요약 출력

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
민헌 2026-07-10 10:50:28 +09:00
parent 5e485e9b6e
commit fbd2cec1da
2 changed files with 125 additions and 12 deletions

View File

@ -1,16 +1,23 @@
"""LPS 부하 테스트 — 여러 상품을 한 번에 제출하고 처리량·지연·비용을 집계한다. """LPS 부하 테스트 — 여러 상품을 한 번에 제출하고 처리량·지연·비용을 집계한다.
여러 상품 동시 검색을 재현한다. 워커 동시성(WORKER_CONCURRENCY)만큼 상품이 병렬 처리된다. 여러 상품 동시 검색을 재현한다. 워커 동시성(WORKER_CONCURRENCY)만큼 상품이 병렬 처리된다.
python loadtest.py # 기본 상품셋 python loadtest.py # 카탈로그 앞 6개
N=8 python loadtest.py # 상품 8개(기본셋에서 반복 확장) N=100 python loadtest.py # 상품 100개(loadtest/catalog.json 전체)
BASE=http://localhost:9600 python loadtest.py BASE=http://localhost:9600 python loadtest.py
상품셋 = loadtest/catalog.json (100, 실존 상품): 규격만(식품·생활용품) / 규격+모델(가전·디지털)
/ 이름만 / 회사 포함 / 일부 기준가(price가격밴드 필터 경로) 섞어 실제 입력 분포를 재현한다.
N > 카탈로그 크기면 반복 확장. product_code 부하테스트 전용 프리픽스(LT###, 매회 유니크라
dedupe·네거티브캐시에 걸림).
측정: 벽시계 총시간, 처리량(상품/), 상품별·집계 지연(p50/p95), AI·DECODO·총비용. 측정: 벽시계 총시간, 처리량(상품/), 상품별·집계 지연(p50/p95), AI·DECODO·총비용.
워커가 있어야 하고, 워커 동시성이 낮으면 상품들이 큐에서 순차 대기한다(그게 부하의 핵심 관측). 워커가 있어야 하고, 워커 동시성이 낮으면 상품들이 큐에서 순차 대기한다(그게 부하의 핵심 관측).
""" """
import asyncio import asyncio
import json
import os import os
import pathlib
import time import time
import httpx import httpx
@ -18,15 +25,9 @@ import httpx
BASE = os.environ.get("BASE", "http://localhost:9600") BASE = os.environ.get("BASE", "http://localhost:9600")
N = int(os.environ.get("N", "6")) N = int(os.environ.get("N", "6"))
# 실제 매칭 잘 되는 상품셋(반복해서 N개로 확장). product_code 는 부하테스트 전용 프리픽스. _CATALOG = json.loads(
_CATALOG = [ (pathlib.Path(__file__).parent / "loadtest" / "catalog.json").read_text(encoding="utf-8")
{"product_name": "코카콜라 제로", "specification": "355ml 24캔"}, )
{"product_name": "농심 신라면", "specification": "1박스 40개입"},
{"product_name": "오리온 초코파이", "specification": "12개입"},
{"product_name": "제주 삼다수", "specification": "2L 12개입"},
{"product_name": "맥심 모카골드 커피믹스", "specification": "1박스 160개입"},
{"product_name": "스탠리 텀블러", "specification": "887ml"},
]
def _products(n): def _products(n):
@ -37,6 +38,15 @@ def _products(n):
return out return out
def _composition(products) -> str:
"""상품셋 구성 요약 — 어떤 입력 분포로 테스트하는지 리포트에 남긴다."""
model = sum(1 for p in products if p.get("model"))
spec_only = sum(1 for p in products if p.get("specification") and not p.get("model"))
name_only = sum(1 for p in products if not p.get("specification") and not p.get("model"))
priced = sum(1 for p in products if p.get("price"))
return f"모델포함 {model} · 규격만 {spec_only} · 이름만 {name_only} · 기준가 포함 {priced}"
def _pct(values, p): def _pct(values, p):
if not values: if not values:
return 0 return 0
@ -47,7 +57,8 @@ def _pct(values, p):
async def main(): async def main():
products = _products(N) products = _products(N)
print(f"■ 부하 테스트: 상품 {N}개 → {BASE} (워커 동시성만큼 병렬 처리)\n") print(f"■ 부하 테스트: 상품 {N}개 → {BASE} (워커 동시성만큼 병렬 처리)")
print(f" 구성: {_composition(products)}\n")
async with httpx.AsyncClient(timeout=30) as c: async with httpx.AsyncClient(timeout=30) as c:
# 큐/헬스 사전 확인 # 큐/헬스 사전 확인

102
lps/loadtest/catalog.json Normal file
View File

@ -0,0 +1,102 @@
[
{"product_name": "코카콜라 제로", "specification": "355ml 24캔", "price": "21000"},
{"product_name": "농심 신라면", "specification": "1박스 40개입", "price": "33000"},
{"product_name": "오리온 초코파이", "specification": "12개입"},
{"product_name": "제주 삼다수", "specification": "2L 12개입", "price": "13000"},
{"product_name": "맥심 모카골드 커피믹스", "specification": "1박스 160개입"},
{"product_name": "서울우유 멸균우유", "specification": "1L 10팩"},
{"product_name": "햇반 백미밥", "specification": "210g 24개입"},
{"product_name": "스팸 클래식", "specification": "200g 10캔"},
{"product_name": "카누 마일드 아메리카노 미니", "specification": "0.9g 100T"},
{"product_name": "동원 라이트스탠다드 참치", "specification": "100g 10캔"},
{"product_name": "크리넥스 데코앤소프트 3겹 화장지", "specification": "27m 30롤", "price": "24000"},
{"product_name": "다우니 섬유유연제 실내건조", "specification": "8.5L"},
{"product_name": "리스테린 쿨민트", "specification": "750ml 2개"},
{"product_name": "페리오 캐비티케어 치약", "specification": "160g 6개"},
{"product_name": "베베숲 시그니처 블루 물티슈", "specification": "70매 10팩"},
{"product_name": "백설 하얀설탕", "specification": "3kg"},
{"product_name": "오뚜기 진라면 매운맛", "specification": "120g 40개입"},
{"product_name": "롯데 빼빼로 오리지널", "specification": "54g 10갑"},
{"product_name": "매일 바이오 플레인 요거트", "specification": "450g 4개"},
{"product_name": "광동 옥수수수염차", "specification": "500ml 20병"},
{"product_name": "칠성사이다", "specification": "250ml 30캔"},
{"product_name": "롯데 레쓰비 마일드", "specification": "175ml 30캔"},
{"product_name": "농심 새우깡", "specification": "90g 20봉"},
{"product_name": "CJ 비비고 왕교자", "specification": "1.05kg 2개"},
{"product_name": "풀무원 국산콩 두부", "specification": "300g 4모"},
{"product_name": "청정원 순창 재래식 된장", "specification": "2kg"},
{"product_name": "오뚜기 3분 카레 약간매운맛", "specification": "200g 10개"},
{"product_name": "샘표 진간장 금F3", "specification": "1.7L"},
{"product_name": "케라시스 러블리 데일리 샴푸", "specification": "980ml 2개"},
{"product_name": "테크 액체세제 드럼겸용", "specification": "4.5L"},
{"product_name": "홈스타 맥스프레쉬 곰팡이싹", "specification": "900ml 2개"},
{"product_name": "3M 스카치브라이트 다목적 수세미", "specification": "10개입"},
{"product_name": "유한락스 레귤러", "specification": "1L 4개"},
{"product_name": "깨끗한나라 순수 소프트 3겹", "specification": "30m 30롤"},
{"product_name": "코멧 일회용 마스크 대형", "specification": "50매"},
{"product_name": "정식품 베지밀A 담백한맛", "specification": "190ml 24팩"},
{"product_name": "남양 프렌치카페 카페믹스", "specification": "162T"},
{"product_name": "크라운 참크래커", "specification": "280g 4개"},
{"product_name": "삼성전자 갤럭시 버즈2 프로", "model": "SM-R510", "specification": "블루투스 이어폰"},
{"product_name": "삼성전자 970 EVO Plus NVMe M.2 SSD", "model": "MZ-V7S1T0BW", "specification": "1TB"},
{"product_name": "삼성전자 T7 포터블 외장 SSD", "model": "MU-PC1T0T", "specification": "1TB"},
{"product_name": "로지텍 K380 멀티디바이스 블루투스 키보드", "model": "K380", "specification": "무선", "price": "33000"},
{"product_name": "로지텍 MX Master 3S 무선 마우스", "model": "MX Master 3S"},
{"product_name": "ipTIME 기가비트 유무선공유기", "model": "A3004T"},
{"product_name": "티피링크 무선 공유기", "model": "Archer AX53", "specification": "AX3000 Wi-Fi 6"},
{"product_name": "샤오미 미밴드 8", "model": "Mi Band 8", "specification": "스마트밴드"},
{"product_name": "애플 에어팟 프로 2세대", "model": "MTJV3KH/A", "specification": "USB-C", "price": "300000"},
{"product_name": "WD 마이 패스포트 외장하드", "model": "WDBYVG0020BBK", "specification": "2TB"},
{"product_name": "필립스 1000시리즈 전기면도기", "model": "S1121/41"},
{"product_name": "샤오미 미지아 전기면도기", "model": "S500"},
{"product_name": "쿠쿠 6인용 전기압력밥솥", "model": "CRP-P0610FD"},
{"product_name": "소니 노이즈캔슬링 헤드폰", "model": "WH-1000XM5"},
{"product_name": "소니 노이즈캔슬링 이어폰", "model": "WF-1000XM5"},
{"product_name": "벤큐 아이케어 모니터", "model": "GW2480", "specification": "24인치 FHD"},
{"product_name": "델 프로페셔널 모니터", "model": "P2422H", "specification": "24인치 FHD"},
{"product_name": "앱코 해커 기계식 키보드", "model": "K660", "specification": "청축"},
{"product_name": "레고 테크닉 부가티 시론", "model": "42083"},
{"product_name": "레고 클래식 라지 조립 박스", "model": "10698"},
{"product_name": "샤오미 공기청정기 4 라이트", "model": "AC-M17-SC"},
{"product_name": "다이슨 V15 디텍트 무선청소기", "model": "SV22"},
{"product_name": "보쉬 충전 드릴드라이버", "model": "GSR 12V-15"},
{"product_name": "고프로 히어로12 블랙", "model": "CHDHX-121"},
{"product_name": "삼성전자 흑백 레이저프린터", "model": "SL-M2030"},
{"product_name": "샌디스크 울트라 USB 3.0", "model": "SDCZ48-064G", "specification": "64GB"},
{"product_name": "다이슨 에어랩"},
{"product_name": "스탠리 퀜처 H2.0 텀블러"},
{"product_name": "닌텐도 스위치 OLED"},
{"product_name": "플레이스테이션5 슬림 디스크 에디션"},
{"product_name": "애플 매직 마우스"},
{"product_name": "갤럭시 워치7"},
{"product_name": "에어팟 맥스"},
{"product_name": "몰스킨 클래식 노트 라지 하드커버"},
{"product_name": "라미 사파리 만년필"},
{"product_name": "킨들 페이퍼화이트"},
{"product_name": "발뮤다 더 토스터"},
{"product_name": "네스프레소 버츄오 팝"},
{"product_name": "마샬 액톤3"},
{"product_name": "JBL 플립6"},
{"product_name": "인스타360 X4"},
{"product_name": "조지루시 스테인리스 보온병"},
{"product_name": "브리타 정수기 마렐라"},
{"product_name": "옥소 팝컨테이너"},
{"product_name": "루메나 무선 선풍기"},
{"product_name": "크록스 클래식 클로그"},
{"product_name": "진라면 순한맛", "company": "오뚜기", "specification": "120g 20개입"},
{"product_name": "초코송이", "company": "오리온", "specification": "36g 10개"},
{"product_name": "바나나맛우유", "company": "빙그레", "specification": "240ml 8개"},
{"product_name": "갈아만든배", "company": "해태htb", "specification": "1.5L 12병"},
{"product_name": "2080 진지발리스 치약", "company": "애경", "specification": "120g 5개"},
{"product_name": "자연퐁 솔잎 주방세제", "company": "LG생활건강", "specification": "1.2L 2개"},
{"product_name": "딱풀", "company": "아모스", "specification": "35g 5개"},
{"product_name": "하이테크C 볼펜", "company": "파이롯트", "specification": "0.4mm 검정"},
{"product_name": "모나미 153 볼펜", "company": "모나미", "specification": "0.7mm 12자루", "price": "4000"},
{"product_name": "포스트잇 노트 654", "company": "3M", "specification": "76x76mm 5패드"},
{"product_name": "곰표 밀가루 중력분", "specification": "1kg"},
{"product_name": "종가집 포기김치", "specification": "3.3kg"},
{"product_name": "동서 보리차 티백", "specification": "300g 30T"},
{"product_name": "락앤락 밀폐용기 세트", "specification": "10P"},
{"product_name": "델몬트 오렌지 주스", "specification": "1.8L 2병"},
{"product_name": "니베아 립케어 오리지널", "specification": "4.8g 2개"}
]