- types.go: ScenarioSmallMedium 상수 추가, switch 문으로 모든 시나리오 함수 확장 - screen_config.go: 시나리오 2-way 토글 → 3-way 순환, 숫자키 1/2/3 지원 - screen_about.go: About 화면에 Small-Medium 시나리오 설명 추가 - README.md: 파라미터 표 업데이트
src/ — 구현 코드
본 디렉터리는 AIoT gRPC 고성능 통신 모듈 프로젝트의 구현 코드 루트다.
프로젝트 전체 개요·연구 목적·비교 대상은 상위 디렉터리의 README.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명령
go version # 1.22 이상 확인
3. 빌드 및 실행
3.1. Terminal UI 데모
# 본 src/ 디렉터리에서
go mod tidy # 최초 1회 의존성 다운로드
go run ./cmd/benchcli # 즉시 실행
# 또는 바이너리 빌드
go build -o ../bin/benchcli ./cmd/benchcli
../bin/benchcli
3.2. 검증
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 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 §5.2에 정의된 KPI 집합이다. 본 절은 각 지표가 무엇을 의미하고, UI에서 어떻게 표시되며, 어떻게 해석해야 하는지를 실용적 관점에서 정리한다.
Phase 0(현재)에서는 모든 수치가 시뮬레이션 값이며, Phase 5 이후 실측으로 대체된다. 측정 방법·warm-up·반복 횟수·신뢰 구간 등 실험 설계의 세부 사항은
../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+)
proto/aiot/inference/inference.proto정의 및make proto로 코드 생성cmd/server에 gRPC InferenceService 구현 (HTTP/2)cmd/rest-server에 동일 시나리오의 REST 엔드포인트 구현cmd/benchmark-runner에서 두 서버 호출하는 부하 생성기 구현internal/ui/simulator.go의step()함수를 실측 데이터 수집기로 교체scripts/tc-setup.sh를 UI에서 자동 호출하도록 통합
자세한 구현 패턴은 ../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 권장 |