# `src/` — 구현 코드 본 디렉터리는 **AIoT gRPC 고성능 통신 모듈** 프로젝트의 구현 코드 루트다. 프로젝트 전체 개요·연구 목적·비교 대상은 [상위 디렉터리의 `README.md`](../README.md)를, 연구 방향과 평가 지표는 [`../CLAUDE.md`](../CLAUDE.md)를 참고한다. --- ## 1. 현재 구현 단계 현재 빌드는 **Phase 0 — Terminal UI 데모**다. 실제 gRPC/REST 서버나 `tc` 연동 없이, 파라미터에 반응하는 시뮬레이션 값으로 최종 목표 화면을 가시화한다. | Phase | 상태 | 내용 | |------|------|------| | **0. Demo UI** | ✅ 완료 | Bubble Tea 기반 TUI · mock 시뮬레이터 | | 1. Proto + gRPC 서버/클라이언트 | ☐ | `proto/`, `cmd/server`, `cmd/client` | | 2. REST 비교군 | ☐ | `cmd/rest-server`, `internal/client/rest_client.go` | | 3. gRPC over QUIC 전송 계층 | ☐ | `internal/transport/quic_*.go` | | 4. tc 스크립트 + 벤치마크 러너 | ☐ | `scripts/tc-*.sh`, `cmd/benchmark-runner` | | 5. UI ↔ 실측 데이터 연결 | ☐ | `internal/ui/simulator.go` 교체 | | 6. Mininet 토폴로지 | ☐ | Phase 2 평가 환경 | --- ## 2. 사전 요구사항 - **Go 1.22+** (현재 빌드는 1.26에서 검증됨) - 256색 / UTF-8 지원 터미널 - (Linux, Phase 1+) `iproute2` 패키지의 `tc` 명령 ```bash go version # 1.22 이상 확인 ``` --- ## 3. 빌드 및 실행 ### 3.1. Terminal UI 데모 ```bash # 본 src/ 디렉터리에서 go mod tidy # 최초 1회 의존성 다운로드 go run ./cmd/benchcli # 즉시 실행 # 또는 바이너리 빌드 go build -o ../bin/benchcli ./cmd/benchcli ../bin/benchcli ``` ### 3.2. 검증 ```bash go vet ./... # 정적 분석 go build ./... # 전체 컴파일 go test ./... # (테스트 추가 후) 단위·통합 테스트 ``` --- ## 4. 디렉터리 구조 (src/) ``` src/ ├── go.mod # 모듈명: aiot-grpc-bench, Go 1.22 ├── go.sum │ ├── cmd/ │ └── benchcli/ │ └── main.go # Terminal UI 진입점 │ └── internal/ └── ui/ # Bubble Tea + Lipgloss 기반 TUI ├── app.go # Model + Update + View dispatcher ├── types.go # Config / Result / RunState 정의 ├── styles.go # Lipgloss 색상·스타일 ├── components.go # progressBar / sparkline / slider / formatBytes ├── simulator.go # ★ mock 시뮬레이터 (Phase 5에서 교체 예정) ├── screen_menu.go # 메인 메뉴 ├── screen_config.go # 시나리오·네트워크·시스템 설정 ├── screen_running.go # 실시간 진행 화면 ├── screen_results.go # 비교 차트 화면 └── screen_about.go # 테스트베드 정보 ``` 향후 Phase 1 이후 추가될 디렉터리는 [`../IMPLEMENTATION.md`](../IMPLEMENTATION.md) 1절(프로젝트 구조)을 따른다(`proto/`, `gen/`, `internal/transport/`, `internal/server/`, `internal/gateway/` 등). --- ## 5. UI 사용법 ### 5.1. 화면 흐름 ``` [메인 메뉴] │ ├─ 새 실험 시작 ─→ [Config] ─→ [Running] ─→ [Results] │ │ │ └─ r: 같은 조건 재실행 │ └─ n: 새 실험 │ └─ 테스트베드 정보 ─→ [About] ``` ### 5.2. 키 바인딩 | 키 | 동작 | |----|------| | `↑/↓` `j/k` | 항목 이동 | | `←/→` `h/l` | 파라미터 값 조정 | | `Space` | 비교 시스템 선택 토글 | | `Enter` | 선택 / 실험 시작 | | `r` | (결과 화면) 같은 조건으로 재실행 | | `n` | (결과 화면) 새 실험 시작 | | `Esc` | 한 단계 뒤로 / 진행 중단 | | `q` `Ctrl+C` | 종료 | ### 5.3. 조절 가능한 파라미터 | 파라미터 | 범위 | 단위/단계 | |---------|-----|----------| | 시나리오 | Small-Many / Small-Medium / Large-Few | 3-way 순환 (←/→, 1/2/3) | | 링크 지연 (편도) | 0 – 500 | ms (10ms 단위) | | 패킷 손실율 | 0.0 – 5.0 | % (0.5% 단위) | | 대역폭 | 1, 5, 10, 25, 50, 100, 250, 500, 1000 | Mbps (이산) | | 디바이스 수 | 1 – 100 | 1/5/10 단위 (값 크기에 따라) | | 비교 시스템 | rest-h2 / grpc-h2 / grpc-h3 | 개별 토글 | --- ## 6. 의존성 ``` github.com/charmbracelet/bubbletea v1.2.4 # TUI 프레임워크 github.com/charmbracelet/lipgloss v1.0.0 # 스타일링 ``` 간접 의존성은 `go.mod`의 `// indirect` 블록 참고. --- ## 7. 측정 지표 (KPI) 본 테스트베드가 측정·표시하는 지표는 [`../CLAUDE.md`](../CLAUDE.md) §5.2에 정의된 KPI 집합이다. 본 절은 각 지표가 *무엇을 의미하고, UI에서 어떻게 표시되며, 어떻게 해석해야 하는지*를 실용적 관점에서 정리한다. > Phase 0(현재)에서는 모든 수치가 시뮬레이션 값이며, Phase 5 이후 실측으로 대체된다. 측정 방법·warm-up·반복 횟수·신뢰 구간 등 *실험 설계의 세부 사항*은 [`../CLAUDE.md`](../CLAUDE.md) §5.2 및 §5.5를 따른다. ### 7.1. Latency 분포 — P50 / P95 / P99 - **무엇**: 단일 요청의 응답 시간(클라이언트 측 wall-clock). P50은 중앙값, P95/P99는 상위 5 %·1 % 지연 - **왜**: 평균은 outlier에 가려져 사용자 체감을 반영하지 못한다. 분포의 꼬리(P95/P99)가 실제 시스템 안정성을 가늠하는 핵심 - **단위**: ms - **UI 표시**: 진행/결과 화면의 시스템별 행에 `P50 / P95 / P99` 숫자, 결과 화면의 Latency 비교 막대 차트(낮을수록 좋음) - **해석 팁**: P50과 P99의 격차가 크면 분포의 꼬리가 길다는 뜻이다. 패킷 손실 환경(Lossy-3, Lossy-5)에서 이 격차가 시스템 간 차이를 가장 잘 드러낸다 — gRPC-H3는 격차가 좁고, REST/gRPC-H2는 넓을 것으로 가정 ### 7.2. Throughput (RPS) - **무엇**: 초당 정상 처리된 요청 수 - **왜**: 시스템의 처리 능력 한계 측정. 동일한 부하 하에서 RPS가 클수록 같은 자원으로 더 많은 작업 처리가 가능 - **단위**: requests/sec - **UI 표시**: 진행 화면의 `RPS=…`, 결과 화면의 처리량 비교 막대 차트(높을수록 좋음), 표의 ★ 마커는 최고 RPS - **해석 팁**: AI Agent 시나리오는 burst 패턴이므로 평균 RPS만 보지 말고 burst 처리 능력을 함께 살핀다. IoT 시나리오에서는 대역폭이 지배적이므로 RPS 한계가 곧 대역폭 한계에 근접 ### 7.3. Payload Size — 데이터 전송량 - **무엇**: 단일 요청·응답이 wire에서 차지하는 바이트 수의 누적 - **왜**: 직렬화 효율(Protobuf vs JSON)과 헤더 오버헤드의 차이를 정량화. 모바일/IoT 환경에서는 데이터 비용과 직결 - **단위**: B / KB / MB / GB (UI에서 자동 변환) - **UI 표시**: 진행 화면의 `데이터=…`, 결과 표의 「총 데이터」 컬럼 - **해석 팁**: AI Agent 시나리오(1–8 KB)에서는 직렬화 차이가 latency를 거의 좌우하지 않으므로 **보조 지표**. IoT 시나리오(MB 단위)에서는 전송 시간을 결정하는 **주요 지표**. CLAUDE.md §5.4의 시나리오별 KPI 가중치 표 참고 ### 7.4. Connection Overhead — 연결 수립 시간 - **무엇**: 첫 요청과 재사용 요청의 latency 차이. 핸드셰이크(TCP/QUIC + TLS)에 드는 비용 - **왜**: AI Agent의 짧은 단발성 RPC에서는 이 비용이 전체 latency를 지배. QUIC의 0/1-RTT가 핵심 차별점이 되는 영역 - **단위**: ms - **UI 표시**: 결과 화면의 「연결 수립 시간」 막대 차트(낮을수록 좋음), 표의 ⚡ 마커는 최저 P99 latency - **해석 팁**: 핸드셰이크 비용 비교(근사) - TCP + TLS 1.3 ≈ 1.5 × RTT (TCP 1-RTT + TLS 1-RTT 압축) - QUIC 1-RTT ≈ 0.5 × RTT (TLS·전송 통합) - QUIC 0-RTT (재연결) ≈ 0 ms 추가 (세션 캐시 hit) - 격리된 컨테이너 간 빈번한 호출에서는 이 차이가 누적되어 시스템 응답성을 결정 ### 7.5. 성공률 - **무엇**: 정상 응답 / 총 시도 요청 - **왜**: 패킷 손실·지연 환경에서의 안정성 측정. 같은 손실률이라도 프로토콜의 재전송·복구 메커니즘 차이로 최종 성공률이 달라짐 - **단위**: % - **UI 표시**: 결과 표의 「성공률」 컬럼, 진행 화면의 `성공=… 실패=…` 카운터 - **해석 팁**: QUIC은 HoL Blocking 해소로 같은 손실률에서 더 높은 처리 성공률을 보일 것으로 가정. 단순 손실률(tc 설정값)과 응용 레벨 성공률은 다르다는 점에 주의 ### 7.6. 0-RTT Resumption *(Phase 2 — 추가 예정)* - **무엇**: 같은 클라이언트가 재연결할 때 첫 요청의 latency. QUIC 전용 - **왜**: 격리 에이전트 재시작·세션 재수립 시나리오에서의 효과 검증. AI Agent 시나리오의 핵심 KPI - **단위**: ms - **측정 방법**: 한 번 핸드셰이크 완료 후 세션 캐시를 활용한 재연결에서 첫 요청 latency. 이를 일반 1-RTT 핸드셰이크와 비교 - **UI 표시**: 현재 미구현 — Phase 2에서 결과 화면에 별도 행으로 추가 예정 ### 7.7. HoL Blocking 내성 *(Phase 2 — 추가 예정)* - **무엇**: 병렬 스트림 4개 동시 전송 중 1개에 강제 패킷 손실을 가했을 때, 나머지 3개의 latency 영향 - **왜**: HTTP/2 vs HTTP/3의 핵심 차별 검증. TCP 위의 HTTP/2는 모든 스트림이 동시에 영향받지만, QUIC은 스트림 단위 격리로 영향 최소화 - **단위**: ms (영향받지 않은 스트림의 P99) - **UI 표시**: 현재 미구현 — Phase 2에서 별도 검증 화면으로 추가 예정 ### 7.8. 시나리오별 지표 가중치 요약 | 시나리오 | 주요 KPI | 보조 KPI | |---------|---------|---------| | **AI Agent RPC** (1–8 KB, Unary, burst) | Connection Overhead, 0-RTT, P50/P95 Latency, RPS | HoL Blocking 내성 | | **IoT 데이터 전송** (64 KB ~ 2 MB, Streaming) | Throughput, P95/P99 Latency, Payload Size, HoL Blocking 내성 | Connection Overhead | > AI Agent 시나리오에서 Payload Size를 단독으로 보고 결론짓지 말 것 — 수 KB 영역에서는 직렬화 차이가 RTT 대비 무시할 수준이다. 같은 이유로, IoT 시나리오에서 Connection Overhead 단독 비교는 큰 의미가 없다. --- ## 8. mock 시뮬레이터의 가정 `internal/ui/simulator.go`는 실제 측정 없이 파라미터에 반응하여 그럴듯한 추세를 만든다. 시뮬레이션이 가정한 추세는 다음과 같다. | 가정 | 코드 위치 | |------|----------| | HTTP/3 (QUIC)은 패킷 손실 환경에서 HoL Blocking 해소로 처리량/latency 안정성 우위 | `simSpeed`, `mockLatency` | | gRPC (Protobuf)는 REST (JSON) 대비 페이로드 ~30% 절감 | `step` 함수의 bytes 계산 | | QUIC 연결 수립은 0/1-RTT (≈0.5×RTT), TCP+TLS는 ≈1.5×RTT | `mockConnectionTime` | | Large-Few 시나리오는 대역폭 영향 지배적 | `mockLatency`의 bandwidth 항 | | 디바이스 수 증가 시 병렬성으로 처리량 비례 증가 | `simSpeed`의 `parFactor` | > ⚠ **이 수치는 모두 시뮬레이션이다.** 실제 gRPC/QUIC 구현이 같은 추세를 보일지는 Phase 1 이후의 실측으로 검증한다. 시뮬레이터 가중치는 발표·논의를 위한 예시이며, 실측을 대신하지 않는다. --- ## 9. 다음 단계 ### 9.1. UI 측면 - 결과 export (JSON / CSV) 기능 추가 - 시나리오 저장/불러오기 (프리셋) - 비교 결과를 동시에 여러 개 누적 보기 (네트워크 조건 매트릭스 sweep) - §7.6 / §7.7 KPI 화면 추가 (0-RTT Resumption, HoL Blocking 내성) ### 9.2. 백엔드 연결 (Phase 1+) 1. `proto/aiot/inference/inference.proto` 정의 및 `make proto`로 코드 생성 2. `cmd/server`에 gRPC InferenceService 구현 (HTTP/2) 3. `cmd/rest-server`에 동일 시나리오의 REST 엔드포인트 구현 4. `cmd/benchmark-runner`에서 두 서버 호출하는 부하 생성기 구현 5. `internal/ui/simulator.go`의 `step()` 함수를 실측 데이터 수집기로 교체 6. `scripts/tc-setup.sh`를 UI에서 자동 호출하도록 통합 자세한 구현 패턴은 [`../IMPLEMENTATION.md`](../IMPLEMENTATION.md) 4절(코드 패턴)과 7절(자주 수행하는 작업 시나리오)을 참고한다. --- ## 10. 트러블슈팅 | 증상 | 원인 / 해결 | |------|-----------| | 한글이 깨져 보임 | 터미널 로케일을 UTF-8로 설정 (`export LANG=ko_KR.UTF-8`) | | 색상이 단조로움 | `TERM` 환경변수가 256색을 지원하는지 확인 (`echo $TERM` → `xterm-256color` 등) | | `go: module ... not found` | `cd src && go mod tidy` 재실행 | | sparkline/막대가 깨짐 | 터미널 폰트가 Block Element(`▓░█▁▂▃▄▅▆▇`)를 지원하는지 확인 (Nerd Font 권장) | | 화면이 잘림 | 최소 터미널 크기 약 100×40 권장 |