768fc36746
Storage Backbone NAS 트랙의 첫 PR. plan v6 명시대로 read-only inventory PR — 운영 변경 / mount 변경 / file_path 갱신 / asset 이동 모두 0건. 문서만. 산출물: - docs/storage_layout.md 영구 정책 문서 (정책 / 마운트 매트릭스 / NFS 옵션 baseline) - reports/storage_inventory_2026-05-11.md 측정 결과 snapshot 핵심 인사이트: 1. NAS binary layer 는 이미 잘 분리되어 있음 — PKM/extracted_images/ study_question_images 모두 이미 NAS. 추가 이관 PR-3/4 작업량 거의 없음. 2. 현 GPU NFS mount = plan v6 권고안 baseline 과 정확히 같음 (soft, vers=4.1, timeo=10, retrans=3) — PR-2 는 mount 옵션 변경 아닌 애플리케이션 layer (정규화 wrapper / 장애 처리 / uid 매핑) 에 집중. 3. fastapi 만 NAS rw, worker 는 ro — 원본 안전 분리 OK. 4. Postgres pgdata = 1.1GB (DB 본체 이관 안 함, plan 결정 = GPU 잔류). 5. PR-4 도입 시 extracted_emails/ 신규 디렉토리 추가 예정 (Storage PR-5 합류). 실측 명령: SSH 100.111.160.84 → df/mount/du/docker volume ls/docker run -v ... alpine du. 모두 read-only. 운영 영향 0.
143 lines
8.3 KiB
Markdown
143 lines
8.3 KiB
Markdown
# Storage Layout — Document Server
|
||
|
||
**버전**: 2026-05-11 (Storage PR-1 read-only inventory 결과 반영)
|
||
**역할 분리 원칙**: `feedback_knowledge_in_db_blob_in_nas.md` — 지식·검색 대상 = DB, binary·source = NAS.
|
||
**Plan 정합**: `~/.claude/plans/beszel-tingly-sloth.md` v6 의 Storage Backbone 트랙.
|
||
|
||
## 전제
|
||
|
||
- DB 본체 (Postgres) = GPU 서버 잔류 (CPU/RAM 우위, 결정 라운드 9).
|
||
- NAS = bulk binary / source / 변경 적은 자료 backbone.
|
||
- AI 호출은 GPU/맥미니로 라우팅 (Document Server 와 별 채널).
|
||
|
||
## 머신 / 마운트 토폴로지 (2026-05-11 실측)
|
||
|
||
| 머신 | 역할 | IP | 디스크 |
|
||
|---|---|---|---|
|
||
| GPU 서버 (RTX 4070 Ti Super, Ubuntu) | Docker 호스트 — fastapi / postgres / worker / Caddy / frontend | LAN 192.168.1.186 / Tailscale 100.111.160.84 | rootfs 936G / 182G used / 715G free |
|
||
| DS1525+ (Synology) | NFS export + Hyper Backup + DR Tier 1 | LAN 192.168.1.227 / Tailscale 100.101.79.37 | `/volume4` 3.5TB / 401GB used / 3.1TB free |
|
||
| Mac mini M4 Pro | MLX inference (Document Server 외부) | LAN 192.168.1.x / Tailscale 100.76.254.116 | (Document Server storage 영역 0) |
|
||
|
||
GPU 서버의 NFS mount (`/proc/mounts` 실측):
|
||
|
||
```
|
||
192.168.1.227:/volume4/Document_Server /mnt/nas/Document_Server
|
||
nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,
|
||
soft,proto=tcp,timeo=10,retrans=3,_netdev
|
||
```
|
||
|
||
**의미**:
|
||
- 이미 **soft mount + timeo=10 + retrans=3** 적용 중 → plan v6 Storage PR-2 의 "실측 후 mount 전략 결정" 의 *현 baseline 이 곧 권고안*. 변경 필요 X.
|
||
- vers=4.1, NFSv4 (NFSv3 아님 → grace period / lock 처리 OK).
|
||
- LAN 직결 (Tailscale 경유 아님) — D10 (DS1525+ Tailscale TCP 차단) 영향 없음.
|
||
|
||
## NAS volume 안 Document Server layout
|
||
|
||
`/mnt/nas/Document_Server/` (= NAS `/volume4/Document_Server/`):
|
||
|
||
| 경로 | 용도 | 크기 | 변경 빈도 | 분류 |
|
||
|---|---|---|---|---|
|
||
| `PKM/` | 사용자 컨텐츠 원본 (knowledge + 입력 inbox + references) | **38GB** | 일 단위 | 이미 NAS ✓ |
|
||
| `PKM/Knowledge/` | 정리된 지식 자료 (압력용기, ASME, 가스, 등) | 31GB | 일 단위 | 이미 NAS ✓ |
|
||
| `PKM/References/` | 레퍼런스 PDF | 5.5GB | 주 단위 | 이미 NAS ✓ |
|
||
| `PKM/Inbox/` | 업로드 진입 (drag-drop / file_watcher) | 1.5GB | 시간 단위 | 이미 NAS ✓ |
|
||
| `PKM/.preview/` | LibreOffice PDF 변환 cache | (소량, 6 entry) | 신규 업로드 시 | 이미 NAS ✓ (검토: GPU 로 이동 가치 작음) |
|
||
| `PKM/Recordings/` | 음성 녹음 | 20KB | 거의 X | 이미 NAS ✓ |
|
||
| `PKM/Videos/` | 비디오 | 116KB | 거의 X | 이미 NAS ✓ |
|
||
| `PKM/Archive/` | 아카이브 | 0 | — | 이미 NAS ✓ |
|
||
| `Main/` | 별 디렉토리 (의미 확인 필요) | 14GB | ? | 이미 NAS ✓ |
|
||
| `extracted_images/` | Markdown Phase 1B.5 추출 이미지 (`document_images`) | 1.2MB | 변환 시 | 이미 NAS ✓ |
|
||
| `study_question_images/` | 가스기사 문제 첨부 이미지 (PR-8) | 12MB | 회차 업로드 시 | 이미 NAS ✓ |
|
||
| `프로그래밍 전 참고 자료/` | (소량) | 56KB | 거의 X | 이미 NAS ✓ |
|
||
|
||
**결론**: NAS 의 binary/source layer 는 **이미 잘 구성되어 있음**. 추가 이관 후보 (Storage PR-3/4 candidate) 는 사실상 없음 — 단, **PR-4 MailPlus ingest** 도입 시 `extracted_emails/` 신규 디렉토리 추가 예정.
|
||
|
||
## GPU 서버 local storage (Postgres + worker 모델 + 로그)
|
||
|
||
| 경로 / Volume | 용도 | 크기 | 분류 |
|
||
|---|---|---|---|
|
||
| Postgres data dir (`pgdata` named volume) | DB 본체 | **1.1GB** | GPU 잔류 (plan 결정) |
|
||
| `hyungi_document_server_ollama_data` | Ollama 모델 weight (embedding / 분류 / 임베딩 등) | **11.9GB** | GPU 잔류 (GPU 인접 필수) |
|
||
| `hyungi_document_server_stt_models` | STT (faster-whisper 등) 모델 | 3.0GB | GPU 잔류 |
|
||
| `hyungi_document_server_reranker_cache` | bge-reranker-v2-m3 cache | 2.1GB | GPU 잔류 |
|
||
| `hyungi_document_server_ocr_models` | OCR 모델 | 1.4GB | GPU 잔류 |
|
||
| `hyungi_document_server_marker_models` | marker-pdf cache | 4KB (외부 HF cache 사용 추정) | GPU 잔류 |
|
||
| `hyungi_document_server_caddy_data` | Caddy ACME / log | (작음) | GPU 잔류 |
|
||
| `~/Documents/code/hyungi_Document_Server/logs/` | fastapi 로그 (rotation) | 21MB | GPU 잔류 |
|
||
|
||
**합계**: AI 모델 캐시 ~18.5GB + Postgres 1.1GB + 로그/Caddy < 100MB ≈ GPU local 20GB 사용 중.
|
||
|
||
## 컨테이너 마운트 매트릭스 (`docker-compose.yml` 발췌)
|
||
|
||
| 컨테이너 | 마운트 | 모드 | 비고 |
|
||
|---|---|---|---|
|
||
| postgres | `pgdata:/var/lib/postgresql/data` + `./migrations:/docker-entrypoint-initdb.d` | rw | DB 본체 named volume |
|
||
| kordoc-service | `${NAS}/Document_Server:/documents` | **ro** | PDF/HWP parse |
|
||
| ocr-service | `${NAS}/Document_Server:/documents` + `ocr_models:/root/.cache` | **ro** + rw | |
|
||
| marker-service | `${NAS}/Document_Server:/documents` + `marker_models:/models` | **ro** + rw | PDF→markdown |
|
||
| stt-service | `${NAS}/Document_Server:/documents` + `stt_models:/root/.cache` | **ro** + rw | |
|
||
| ai-gateway / ollama | `ollama_data:/root/.ollama` | rw | GPU 인접 |
|
||
| reranker | `reranker_cache:/data` | rw | |
|
||
| fastapi | `${NAS}/Document_Server:/documents` + `./config.yaml ./domain_policy.yaml ./scripts ./logs ./migrations` | **rw** + ro/rw | NAS 쓰기 권한은 fastapi 만 |
|
||
| caddy | `./Caddyfile + caddy_data:/data` | rw | |
|
||
|
||
**관찰**:
|
||
- worker 컨테이너 (kordoc/ocr/marker/stt) 는 모두 NAS **read-only** 마운트 → 원본 안전.
|
||
- fastapi 만 NAS **rw** → 업로드/preview/extracted_images 쓰기 단일 책임.
|
||
- `./migrations` 이 postgres 의 `docker-entrypoint-initdb.d` 와 fastapi 의 `/app/migrations` 양쪽에 마운트. 단 실제 migration runner 는 fastapi `init_db()` 만 사용 (postgres init scripts 는 첫 생성 시만 실행 → 효과 X, 안전).
|
||
|
||
## 정책 정리
|
||
|
||
### NAS 에 두는 것 (binary / source / 변경 적음)
|
||
- 사용자 컨텐츠 원본 (`PKM/*`)
|
||
- 변환 cache (`PKM/.preview/`, `extracted_images/`)
|
||
- 학습 자료 첨부 (`study_question_images/`)
|
||
- 향후: `extracted_emails/` (PR-4)
|
||
|
||
### GPU 서버 local 에 두는 것 (latency 민감 / hot path / 큰 caching)
|
||
- Postgres data dir (DB 본체)
|
||
- HNSW index, pgvector index (Postgres 내부)
|
||
- AI 모델 weight cache (embedding / OCR / STT / reranker / marker / ollama)
|
||
- worker 임시 캐시 (각 컨테이너 named volume)
|
||
- 로그 (`./logs`)
|
||
|
||
### 명확하게 어디에 두지 않음
|
||
- 검색 인덱스: Postgres 안 (pgvector + pg_trgm) — NAS X
|
||
- chunk text: Postgres 안 (`document_chunks.text_content`) — NAS X
|
||
- 메모 본문: Postgres 안 (`documents.extracted_text`) — NAS X
|
||
- AI 분류 결과: Postgres 안 (`documents.ai_domain/ai_tags`) — NAS X
|
||
|
||
## NFS mount 옵션 권고 (Storage PR-2 baseline)
|
||
|
||
현 GPU 서버 mount = 이미 권고안과 같음:
|
||
|
||
```
|
||
192.168.1.227:/volume4/Document_Server /mnt/nas/Document_Server nfs4
|
||
rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,
|
||
soft,proto=tcp,timeo=10,retrans=3,_netdev
|
||
```
|
||
|
||
**근거**:
|
||
- `soft` — NAS down 시 process 영구 hang 회피 (plan v6 Storage PR-2 핵심 요구). 단 쓰기 도중 부분 실패 위험 → fastapi 의 `upload` / `extract` / `marker` worker 가 fsync + rename(atomic) + DB row 작성 ordering 필수 (코드 검토는 PR-2 영역).
|
||
- `timeo=10/retrans=3` — 1초 단위 timeout × 3회. 30초 안 NAS 응답 없으면 EIO. 운영 1년+ 안정 (별 incident 없음).
|
||
- `vers=4.1` — NFSv3 의 lock daemon 불필요, idempotent.
|
||
- `_netdev` — boot 시 network 이후 마운트.
|
||
|
||
### Storage PR-2 시 점검 항목 (read-only PR-1 scope 외)
|
||
- 한글 NFC/NFD 정규화 wrapper (`feedback_nfs_korean_path_normalize.md`) — 기존 `document_images` 경로 처리 코드 일반화
|
||
- uid/gid 매핑 (Synology user ↔ Docker container user)
|
||
- NAS 장애 시뮬레이션 gate (운영 mount 아닌 isolated test mount 부터)
|
||
- 쓰기 경로 fsync + rename(atomic) + 실패 명시 처리
|
||
|
||
## 백업 정책
|
||
|
||
- NAS = Synology Hyper Backup (DR Tier 1, 별 트랙 `project_db_backup.md` 참조)
|
||
- Postgres = pkm DB → Tier 0 GPU + Tier 1 DS1525+ Vol3 + Tier 2 C2 Hyper Backup (별 트랙)
|
||
- AI 모델 캐시 = 백업 불필요 (재다운로드 가능)
|
||
|
||
## 다음 단계
|
||
|
||
- Storage PR-2 (NFS 표준화 + 정규화 wrapper + 장애 시뮬 gate) — 운영 변경 동반 → 별 PR
|
||
- Storage PR-3/4 (원본 이관) — **현 상태 이미 NAS, 추가 작업 0**
|
||
- Storage PR-5 (events `raw_metadata` 첨부 = extracted_emails) — events PR-4 (MailPlus ingest) 와 합류
|