Files
web-page-backend/CHECK_POINT.md
gahusb 20514193e8 perf(infra): NAS CPU 중기 2건 + 1건 보류 (CHECK_POINT 🟡)
#6 insta-lab Chromium Browser Pool — Playwright/Chromium 인스턴스를
모듈 레벨에서 보관하고 매 슬레이트마다 reuse. 카드 10장 렌더의
launch 비용 (~3초/회)이 사라짐. startup/shutdown lifecycle hook 추가.
crashed/disconnected 시 lazy 재초기화.

#8 realestate-lab 수집 병렬화 — collect_all과 delete_old_completed가
서로 다른 데이터 영역이라 ThreadPoolExecutor(2)로 병렬. asyncio.gather
대신 thread executor를 쓴 이유는 BackgroundScheduler+동기 함수 환경
에서 자연스럽고 추가 의존성 없기 때문. 매칭은 일관성 유지로 순차.

#7 stock async — 보류. 재진단 결과 stock은 BackgroundScheduler 사용
중이라 main loop 블로킹 없음. fetch 4회는 network I/O wait가
대부분이라 to_thread도 의미 없음. 진짜 효과를 보려면 AsyncIOScheduler
전환 + aiohttp 병렬이라 큰 리팩토링. 박재오 판단 대기.

CHECK_POINT.md 갱신.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 10:42:43 +09:00

216 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# web-backend CHECK_POINT
> NAS Docker 11 컨테이너(9 백엔드 + frontend + deployer). Synology Celeron J4025 (2C 2.0GHz) 18GB.
> 2026-05-18 작성 — uvicorn CPU 폭주 진단 결과 정리.
## 🔴 즉시 (오늘, 총 1시간 5분)
### 1. 09:00 cron 5분 스태거링 ⭐ 가장 큰 효과
**파일**: `agent-office/app/scheduler.py:72-76`
```python
# 변경 전 — 09:00 동시 실행 (CPU 폭주 원인 #1)
scheduler.add_job(_run_insta_trends_collect, "cron", hour=9, minute=0)
scheduler.add_job(_run_lotto_schedule, "cron", day_of_week="mon", hour=9, minute=0)
scheduler.add_job(_run_youtube_research, "cron", hour=9, minute=0)
# 변경 후 — 5분 스태거링
scheduler.add_job(_run_insta_trends_collect, "cron", hour=9, minute=0, id="insta_trends")
scheduler.add_job(_run_lotto_schedule, "cron", day_of_week="mon", hour=9, minute=5, id="lotto_curate")
scheduler.add_job(_run_youtube_research, "cron", hour=9, minute=10, id="youtube_research")
```
**파일**: `realestate-lab/app/main.py:51`
```python
# 변경 전
scheduler.add_job(scheduled_collect, "cron", hour=9, minute=0, id="collect")
# 변경 후
scheduler.add_job(scheduled_collect, "cron", hour=9, minute=15, id="collect")
```
- [x] agent-office scheduler.py 수정 (2026-05-18)
- [x] realestate-lab main.py 수정 (2026-05-18)
- [ ] git commit + push (Gitea Webhook 자동 빌드)
---
### 2. insta-lab Playwright Semaphore(1) ⭐
**파일**: `insta-lab/app/main.py` (모듈 레벨 추가)
```python
import asyncio
# 모듈 레벨에 한 번만 선언
RENDER_SEMAPHORE = asyncio.Semaphore(1) # Chromium 동시 실행 1개로 제한
# 카드 렌더 백그라운드 함수에 감싸기
async def _bg_render(task_id: str, slate_id: int):
async with RENDER_SEMAPHORE:
await card_renderer.render_slate(slate_id, ...)
```
- [x] card_renderer.render_slate를 Semaphore(1)로 감쌈 (2026-05-18, lazy init)
- [ ] 동시 2개 요청 테스트 (curl 동시 2회 → 순차 처리되는지 확인)
---
### 3. healthcheck interval 60s
**파일**: `docker-compose.yml` (모든 9 컨테이너)
```yaml
# 변경 전
healthcheck:
interval: 30s
# 변경 후
healthcheck:
interval: 60s
```
- [x] docker-compose.yml 10개 healthcheck 일괄 변경 (9 백엔드 + frontend, 2026-05-18)
- [ ] `docker compose up -d` 재기동
- [ ] `docker stats` 로 CPU 5% 정도 감소 확인
---
### 4. uvicorn --workers 1 명시
**모든 Dockerfile CMD**:
```dockerfile
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
```
영향 9 파일 (모두 2026-05-18 적용):
- [x] lotto/Dockerfile
- [x] stock/Dockerfile
- [x] music-lab/Dockerfile
- [x] insta-lab/Dockerfile
- [x] realestate-lab/Dockerfile
- [x] agent-office/Dockerfile
- [x] personal/Dockerfile
- [x] packs-lab/Dockerfile
- [x] travel-proxy/Dockerfile
`docker compose build --no-cache` 후 재기동.
---
### 5. lotto Monte Carlo 08:05 → 08:30
**파일**: `lotto/app/main.py:86`
```python
# 변경 전 — stock 08:00과 5분 차이로 겹침
scheduler.add_job(_run_simulation_job, "cron", hour="0,4,8,12,16,20", minute=5)
# 변경 후 — 25분 분리
scheduler.add_job(_run_simulation_job, "cron", hour="0,4,8,12,16,20", minute=30)
```
- [x] lotto/app/main.py 수정 (2026-05-18)
---
## 🟡 중기 (1~2주)
### 6. Chromium Browser Pool 재설계 (insta-lab) ✅ 2026-05-18
- 매번 launch X → 1개 인스턴스 재사용
- 카드 10장 렌더 시간 30% 단축 기대
- [x] `card_renderer.py` 내부에 모듈 레벨 `_PLAYWRIGHT`/`_BROWSER` + `init_browser`/`shutdown_browser` 함수 (별도 모듈 분리 안 함, 같은 파일에 인접 배치)
- [x] `_render_slate_locked` 본체에서 `_get_browser()` 재사용 (crashed 시 lazy 재초기화)
- [x] `main.py` startup hook에서 `init_browser()`, shutdown hook에서 `shutdown_browser()`
### 7. stock 뉴스 스크랩 비동기화 — ⚠️ 보류 2026-05-18
- **재진단**: stock은 `BackgroundScheduler` 사용 중 → main loop 블로킹 없음 (이미 별도 thread)
- `fetch_market_news`의 4개 동기 `requests.get`은 network I/O wait라 CPU 거의 사용 안 함
- `to_thread`로 wrap해도 BackgroundScheduler 환경에서 사실상 의미 없음
- 진짜 효과를 보려면 AsyncIOScheduler 전환 + scraper.py 4개 fetch를 `aiohttp` 병렬로 — **큰 리팩토링 vs 효과 불명확**
- [ ] 박재오 판단: 큰 리팩토링 진행 여부
### 8. realestate 수집 병렬화 ✅ 2026-05-18
- **파일**: `realestate-lab/app/main.py:scheduled_collect`
- `collect_all()` + `delete_old_completed_announcements()` 병렬
- BackgroundScheduler 환경이라 `asyncio.gather` 대신 `ThreadPoolExecutor(max_workers=2)` 사용 (효과 동일)
- 매칭은 순차 유지 (DB 일관성)
- [x] ThreadPoolExecutor 적용
### 9. lotto Monte Carlo 시뮬레이션 빈도 검토
- 현재 6회/일 (00·04·08·12·16·20)
- 실제 필요 빈도 박재오 결정 — 3회/일(아침·점심·저녁)로 줄이면 CPU 50% 감소
- [ ] 박재오 의사결정 후 cron 변경
---
## 🟢 장기 (1개월+)
### 10. 무거운 작업 Windows AI 서버로 이전
- 현재 stock Ollama qwen3:14b → NAS 로컬 호출 가능성 (확인 필요)
- 모든 LLM 호출을 Windows AI 192.168.45.59로 통일
- NAS CPU ~20% 감소 기대
### 11. 컨테이너 리소스 제한
```yaml
services:
insta-lab:
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
```
- [ ] insta-lab·music-lab·stock 등 무거운 컨테이너부터 적용
- 효과: OOM killer로부터 다른 컨테이너 보호
### 12. NAS 업그레이드 검토
- 현재: Celeron J4025 (2C 2.0GHz)
- 대안: Ryzen N5105 (4C 2.0GHz) NAS — 4코어로 병렬성 2배
- 박재오 자금·우선순위 결정
---
## ✅ 최근 완료 (참고)
- 2026-05-15: insta-lab 신설 (포트 18700, Jinja2 + Playwright + Claude Sonnet)
- 2026-05-16: insta-lab Playwright 1080×1350 PNG 렌더 완성
- 2026-05-17: agent-office random idle 제거, ADMIN_API_KEY 강화 (stock)
- 2026-05-17: insta-lab minimal theme + design_importer 추가
- 2026-05-17: blog-lab 트랙 완전 폐기 (docker-compose에 없음, 위키 정정 완료)
- 2026-05-18: 🔴 즉시 5건 일괄 적용 — 09:00 cron 스태거링(insta/lotto/youtube/realestate), lotto Monte Carlo 08:30, insta-lab Semaphore(1), healthcheck 60s, uvicorn --workers 1 명시 (사용자 push + NAS deployer 재기동 대기)
- 2026-05-18: 🟡 중기 2건 적용 — #6 insta-lab Chromium Browser Pool (lifecycle hook), #8 realestate ThreadPoolExecutor 병렬 (collect/delete). #7 stock async는 BackgroundScheduler 사용 중이라 재진단 후 보류 (효과 미미). #9 Monte Carlo 빈도는 박재오 결정 대기.
---
## 🔧 진단 커맨드 (NAS bash)
```bash
# 실시간 CPU 사용 (상위 15)
top -b -n 1 | head -25
# 프로세스별 CPU 정렬
ps aux --sort=-%cpu | head -15
# uvicorn·chromium·python 프로세스만
ps aux | grep -E "uvicorn|chromium|python" | grep -v grep
# 스케줄러 실행 로그 (최근 50)
docker logs agent-office 2>&1 | grep -E "APScheduler|executing" | tail -50
# insta-lab Chromium 프로세스 개수
docker exec insta-lab ps aux | grep chromium | wc -l
# 컨테이너별 CPU/메모리 실시간
docker stats --no-stream
```
---
## 📚 참고
- 진단 풀 보고서: `C:\Users\jaeoh\Documents\Obsidian Vault\raw\2026-05-18-NAS-uvicorn-CPU-진단-개선안.md`
- 위키 페이지: [[사업-개인-웹-플랫폼]] (CPU 부하 진단 섹션 + 컨테이너 표)
- docker-compose.yml: 본 디렉토리 루트
## 변경 이력
- 2026-05-18: 페이지 신설. 즉시 5건 + 중기 4건 + 장기 3건. 진단 커맨드.