# M1 — ProcessingQueue Throughput Baseline **측정일**: 2026-05-02 **대상**: GPU 서버 `hyungi_document_server-postgres-1` (DB pkm) **범위**: read-only SELECT 만. 4.0 가드 준수 (docker-compose / migration / queue stage / worker restart / source_channel='web' insert / SearXNG·Crawl4AI 도입 모두 0건). **plan 참조**: `~/.claude/plans/users-hyungiahn-library-cloudstorage-sy-binary-dongarra.md` §4 (LocalResearch Feasibility). --- ## 1. Stage별 7일 throughput ```sql SELECT stage::text, COUNT(*) FILTER (WHERE status='pending') AS pending, COUNT(*) FILTER (WHERE status='processing') AS processing, COUNT(*) FILTER (WHERE status='completed') AS completed, COUNT(*) FILTER (WHERE status='failed') AS failed, ROUND(AVG(EXTRACT(EPOCH FROM (completed_at - started_at))) FILTER (WHERE status='completed')::numeric, 2) AS avg_sec, ROUND((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM (completed_at - started_at))) FILTER (WHERE status='completed'))::numeric, 2) AS p50_sec, ROUND((PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM (completed_at - started_at))) FILTER (WHERE status='completed'))::numeric, 2) AS p95_sec FROM processing_queue WHERE created_at > NOW() - INTERVAL '7 days' GROUP BY stage ORDER BY stage; ``` | stage | pending | processing | completed | failed | avg_sec | p50_sec | p95_sec | |---|---:|---:|---:|---:|---:|---:|---:| | chunk | 4 | 0 | 453 | 0 | 1.36 | 0.76 | 5.19 | | classify | 8 | 2 | 642 | 1 | **42.89** | 33.71 | **82.17** | | deep_summary | 4 | 0 | 467 | 0 | 25.65 | 16.37 | 73.26 | | embed | 13 | 0 | 2,839 | 0 | 0.26 | 0.10 | 1.75 | | extract | 2 | 0 | 345 | 0 | 0.02 | 0.01 | 0.08 | | markdown | 4 | 0 | 89 | 1 | 11.62 | 0.01 | 77.13 | | preview | 13 | 0 | 332 | 0 | 0.01 | 0.01 | 0.02 | | summarize | 0 | 0 | 2,395 | 0 | 3.74 | 3.61 | 5.67 | **핵심 관찰**: - **classify**: 가장 무거운 stage (avg 42.89초, p95 82초) — MLX gemma 호출 dominant - **deep_summary / summarize**: 두 번째로 무거움 (LLM 호출) - **embed**: 가장 가벼움 (avg 0.26초) + 처리량 최대 (2,839건) - **markdown**: bimodal (p50 0.01초 = skip, p95 77초 = 실제 marker-pdf 변환). 2026-05-01 Phase 1B 배포 첫날 가동. - **failed**: classify 1건, markdown 1건 (총 2건, 0.06%) — 무시 수준 --- ## 2. 일별 처리량 분포 ```sql SELECT date_trunc('day', completed_at)::date AS day, stage::text, COUNT(*) FROM processing_queue WHERE completed_at > NOW() - INTERVAL '7 days' AND status='completed' GROUP BY 1, 2 ORDER BY 1 DESC, 2; ``` | day | classify | deep_summary | embed | summarize | chunk | markdown | extract | preview | |---|---:|---:|---:|---:|---:|---:|---:|---:| | 2026-05-02 | 6 | 1 | 66 | 73 | 1 | 1 | 15 | 2 | | 2026-05-01 | 55 | 55 | 377 | 322 | 55 | **88** | 55 | 55 | | 2026-04-30 | — | — | 450 | 412 | — | — | — | — | | 2026-04-29 | — | — | 396 | 434 | — | — | — | — | | 2026-04-28 | — | 15 | 342 | 342 | — | — | — | — | | 2026-04-27 | **258** | 257 | 627 | 369 | 258 | — | 273 | 273 | | 2026-04-26 | — | — | 283 | 283 | — | — | 2 | 2 | | 2026-04-25 | 139 | 139 | 341 | 186 | 139 | — | — | — | **해석**: - 2026-04-25 / 04-27: 가스기사 학습자료 일괄 업로드 batch (PDF/markdown 2,100문항 흐름 흔적, 메모리 `project_gas_engineer_study.md`) - 2026-05-01: Phase 1B marker_worker 배포 첫날, markdown 88건 첫 가동 - 평일 비-batch 일은 classify 0~6건, embed 280~450건 (study_topics PR-4 자동 임베딩 포함) - **편차 매우 큼**: classify 0~258/일, embed 66~627/일. 일 평균보다 peak 일 capacity 가 운영 게이트의 의미 있는 기준. --- ## 3. Capacity 분석 (concurrency=1 가정, LLM stage) LLM stage 는 `feedback_analyzer_async_only.md` + Phase 2 측정 (gemma-4 ~10초, semaphore=1 필수) 기반 **concurrency 1 직렬 처리 가정**. embed 는 GPU batch 가능, chunk/extract/preview 는 CPU light. | stage | avg_sec | concurrency | max capacity (건/일) | 7일 평균 처리량 (건/일) | utilization | |---|---:|---:|---:|---:|---:| | classify | 42.89 | 1 | 2,014 | 91.7 | **4.6%** | | deep_summary | 25.65 | 1 | 3,368 | 66.7 | 2.0% | | summarize | 3.74 | 1 | 23,101 | 342.1 | 1.5% | | markdown (PDF) | 11.62 | 1 | 7,436 | 12.7 | 0.2% | | embed | 0.26 | (GPU batch) | ≫ 100k | 405.6 | < 0.5% | | chunk | 1.36 | (CPU) | 63,529 | 64.7 | 0.1% | **peak 일 (2026-04-27) 부하**: - classify 258건/일 = 11,065초 = **3.07시간/일** = 12.8% utilization (concurrency 1, peak day) - deep_summary 257건/일 = 6,592초 = 1.83시간/일 = 7.6% utilization 평일 평균은 여유롭지만 **peak batch 일에는 classify utilization 13% 까지 도달**. web 추가 부하는 평균이 아닌 peak 기준으로 평가해야 함. --- ## 4. Web 30 URL/일 추가 부하 추정 PDF 시나리오: 사용자 검색 1회당 web 30 URL 수집 → 각 URL 이 markdown / classify / embed / chunk / summarize stage 진입 가정. | stage | 추가 건/일 | 단위 시간 (초) | 추가 시간/일 (초) | peak 일 utilization 증가 | |---|---:|---:|---:|---:| | markdown (web HTML) | 30 | ~5 추정¹ | 150 | +0.2% | | classify | 30 | 42.89 | 1,287 | **+1.5%** | | deep_summary | 30 | 25.65 | 770 | +0.9% | | summarize | 30 | 3.74 | 112 | +0.1% | | embed | 150 (5 chunks/doc) | 0.26 | 39 | +0.05% | | chunk | 150 | 1.36 | 204 | +0.2% | ¹ web HTML → trafilatura 변환은 marker-pdf (PDF 11.62초) 보다 훨씬 빠름 (보통 0.5~3초). 5초는 보수적 가정. **총 추가 capacity 사용** (가장 무거운 LLM stage 기준): - classify utilization 증가: peak 일 12.8% → **14.3%** (+1.5%p) - 평일 평균 utilization 증가: 4.6% → **6.0%** (+1.4%p) --- ## 5. M1 게이트 판정 **plan §4.1 게이트 1**: web 30 URL/일 추가 부하가 현재 ProcessingQueue 처리 capacity 의 **10% 이하**. | 측정 | 값 | 임계값 | 판정 | |---|---|---|---| | classify capacity 추가 사용량 | +1.5%p (절대) | ≤ 10%p | ✓ PASS | | 전체 LLM stage 합산 추가 사용량 | +2.5%p (1.5+0.9+0.1) | ≤ 10%p | ✓ PASS | | peak 일 classify utilization (after) | 14.3% | < 50% (여유) | ✓ PASS | **M1 게이트 1: PASS** (추가 부하가 capacity 의 10% 보다 충분히 작음 — peak 일 기준 +1.5%p). --- ## 6. 보강 관찰 (참고) - **Failed 건 2건만 발생** (classify 1, markdown 1) — 운영 안정. - **Phase 1B markdown stage 가동 검증**: 88 completed / 1 failed / 4 pending — 정상 가동 (메모리 `project_markdown_canonical_layer.md` Phase 1B 배포 일치). - **embed 의 처리량은 chunks 단위**: 1 doc 당 평균 ~5 chunks 가정 → 150 chunks/일 추가는 GPU bge-m3 capacity 에 비해 매우 작음 (M3 에서 배치 처리량 측정 후 재확인). ## 7. 다음 단계 - M2 (MLX gemma-4 N=1/N=2 capacity 벤치) — 차단 조건 (error_rate>0, p95 3배 증가, healthcheck fail, /api/search/ask 또는 eval runner 시간대 충돌) 사전 점검 후 진행.