# M2 — MLX gemma-4 동시 처리 Capacity Bench **측정일**: 2026-05-02 **대상**: Mac mini MLX :8801 `gemma-4-26b-a4b-it-8bit` (Tailscale 100.76.254.116) **범위**: read-only `/v1/chat/completions` 호출만. 4.0 가드 준수 (compose / migration / queue / worker restart / source_channel insert / SearXNG 도입 모두 0건). config.yaml / Ollama 모델 변경 없음. **bench 스크립트**: `/tmp/bench_M2_mlx.py` (격리, main pipeline 미연결) **plan 참조**: `~/.claude/plans/users-hyungiahn-library-cloudstorage-sy-binary-dongarra.md` §4. --- ## 1. 사전 점검 | 항목 | 상태 | |---|---| | MLX `/v1/models` healthcheck | OK (`gemma-4-26b-a4b-it-8bit` 단일 모델) | | 진행 중 background queue (사전) | classify 1건 processing, classify 10건 pending, deep_summary 4건 pending — **MLX 자원 사용 중** | | eval runner / `/api/search/ask` 동시 진행 | 별도 호출 없음 (Document Server 자체 ask 트래픽은 배치 외 시점) | | 시간대 | 평일 오후 (한국시간) — peak 외 | 배경 queue 가 MLX 동시 사용 중인 상태에서 측정 진행 — **운영 환경 reflective benchmark** 로 의미 있음. --- ## 2. 시나리오 | 항목 | 값 | |---|---| | 입력 본문 | ~500 토큰, 한·영 mixed (ASME B16.5 / KGS Code / 가스기사 도메인 sample) | | 프롬프트 작업 | "한국어 200자 이내 요약, technical key points only" | | `max_tokens` | 200 (stop 보장) | | `temperature` | 0 | | 입력 prompt_tokens | ~500 (실측 19 tokens 단순 프롬프트와 별도. 실제 PROMPT 본문 포함 길이) | 각 응답은 모두 `finish_reason='stop'`, `completion_tokens=120` 으로 일관 — **출력 토큰 수가 일정**해 latency 비교가 깨끗함. --- ## 3. N=1 baseline (5 serial) ``` call 1: ok=True elapsed=3.67s ctok=120 call 2: ok=True elapsed=3.41s ctok=120 call 3: ok=True elapsed=3.42s ctok=120 call 4: ok=True elapsed=3.60s ctok=120 call 5: ok=True elapsed=3.47s ctok=120 ``` | metric | value | |---|---| | n | 5 | | min | 3.41s | | max | 3.67s | | avg | **3.51s** | | p50 | 3.47s | | p95 | 3.67s | | error_count | 0 | | error_rate | 0% | | completion_tokens_avg | 120 | **관찰**: 매우 안정 (편차 0.26초). 메모리 `project_search_v2.md` 의 "gemma-4 ~10.5초" (Phase 2 측정) 와 차이는 본 시나리오가 짧은 출력 (120 tok vs Phase 2 의 더 긴 출력) + 검색 query 성격 차이 때문. --- ## 4. N=2 parallel (6 calls, 3 batches via thread pool) ``` call 4: ok=True elapsed=14.38s ctok=120 call 5: ok=True elapsed=14.37s ctok=120 call 6: ok=True elapsed=17.12s ctok=120 ... (call 1~3 도 모두 ok) ``` | metric | value | |---|---| | n | 6 | | min | 6.74s | | max | 35.01s | | avg | **19.88s** | | p50 | 15.75s | | p95 | **35.01s** | | error_count | 0 | | error_rate | **0%** | | completion_tokens_avg | 120 | **해석**: - **error 0** — concurrency 2 client 호출에 대해 MLX 안정. - **latency 큰 폭 증가** — N=1 대비 p95 9.54×, p50 4.54×, avg 5.66×. - 원인: MLX server (`mlx_vlm server`) 가 단일 프로세스 + GPU 1 → 본질적으로 **concurrency=1 직렬 처리**. N=2 client 호출은 MLX 내부 큐에서 직렬화. 추가로 background classify 1건 processing 중이라 경합. - 6 calls × ~3.5초 = ~21초 총 직렬 처리 시간. max 35초는 background queue 점유 + 큐잉. - 이는 메모리 `feedback_analyzer_async_only.md` ("semaphore concurrency=1 필수") 와 일치하는 **이미 알려진 특성**. 새로운 위험 신호 아님. --- ## 5. plan 4.0 중단 조건 점검 | 조건 | 측정 | 판정 | |---|---|---| | `error_rate > 0` | 0% | 미발생 | | **p95 latency N=1 대비 3배 이상 증가** | **9.54×** | **트리거** | | MLX healthcheck 실패 | OK | 미발생 | | `/api/search/ask` 또는 eval 시간대 겹침 | 사전 점검 시 ask/eval 없음 | 미발생 | **결론**: p95 3× 트리거 발생 → **N=4 자동 진행 금지**. plan 명시 (`N=4 는 N=2 에서 error_rate=0 AND p95 acceptable 일 때만`). N=4 는 별도 사용자 승인 후 수행. 다만 latency 9.5× 증가는 MLX concurrency=1 본질적 특성이지, 새로운 운영 위험은 아님. 이미 운영 중인 ask / classify 트래픽이 동시에 들어오면 동일하게 늘어남. --- ## 6. plan 4.1 게이트 판정 (M2 관련) ### 게이트 2 — Gemma 요약 30건/일 ≤ 10분 (concurrency 1) | 항목 | 값 | |---|---| | 단위 시간 (avg) | 3.51s | | 30건 직렬 처리 시간 | 30 × 3.51s = **105.4s = 1.76분** | | 임계값 | ≤ 10분 | | **판정** | **✓ PASS** (여유 5.7×) | ### 게이트 3 — concurrency 2 error_rate 0 = 여유 있음 | 항목 | 값 | |---|---| | N=2 error_rate | 0% | | 임계값 | error_rate = 0 | | **판정** | **✓ PASS** | ### 게이트 3 보강 — latency 영향 (참고용) - N=2 동시성 시 평균 19.88초, p95 35초 — LocalResearch 본격 가동 시 **운영 ask 트래픽과 동일 시간대 web 요약이 겹치면 응답 약 5~10× 지연** 가능. - 완화책 (Phase 1 본격 plan 단계 결정): (a) web 요약은 background queue + concurrency 1 직렬 (실시간 아님) (b) ask 와 시간대 분리 (야간 배치) --- ## 7. M2 단계 요약 - **N=1 baseline**: avg 3.51s, p95 3.67s, error 0 → 매우 안정 - **N=2 parallel**: avg 19.88s, p95 35.01s, error 0 → MLX 직렬 처리로 latency 9.5× 증가, 단 안정성/완성도는 유지 - **N=4 미실시**: plan 4.0 중단 조건 트리거 (p95 3× 초과). 사용자 승인 후 별도 수행. - **plan 게이트 2 + 3 모두 PASS** ## 8. 다음 단계 M3 (bge-m3 batch 1/8/32 임베딩 벤치) — 운영 embed worker 시간대 분리 후 진행.