diff --git a/README.md b/README.md index bbdaa9f..df50486 100644 --- a/README.md +++ b/README.md @@ -89,3 +89,8 @@ ## 라이선스 / 안내 본 프로젝트는 연구 목적의 프로토타입입니다. 프로덕션 환경의 안정성·보안·가용성을 보장하지 않습니다. + +# AI Agents + +- claude --resume 0e21c68a-0e16-47a3-b70b-61187ec8b91f +- hermes --resume 20260507_001250_f9b5f8 \ No newline at end of file diff --git a/TO-DO.md b/TO-DO.md new file mode 100644 index 0000000..b034a5b --- /dev/null +++ b/TO-DO.md @@ -0,0 +1,157 @@ +# TO-DO.md — 추후 개발 항목 + +> 본 파일은 ARCHITECTURE.md와 CLAUDE.md 등에 정의되었으나 **아직 구현되지 않은** 항목들을 추적한다. +> Phase 0 (데모 UI)는 완료되었으며, Phase 1부터 순차적으로 진행 예정이다. + +--- + +## 1. 서버·전송 계층 구현 (Phase 1) + +### 1.1. Proto 정의 및 코드 생성 +- `proto/aiot/inference/inference.proto` — AI 추론 요청/응답 +- `proto/aiot/device/device.proto` — 디바이스 등록·상태 보고 +- `proto/aiot/gateway/gateway.proto` — 게이트웨이 데이터 전달 서비스 +- `make proto` — protoc + protoc-gen-go + protoc-gen-go-grpc 설치 및 자동화 + +### 1.2. 전송 계층 (`internal/transport/`) +- `transport.go` — Listener/Dialer 인터페이스 정의 +- `h2_listener.go` — HTTP/2 (TCP) 리스너 +- `quic_listener.go` — QUIC 리스너 (quic-go 래핑) +- `quic_dialer.go` — QUIC 클라이언트 다이얼러 +- **리스크**: quic-go `quic.Stream`과 `net.Conn` 인터페이스 호환성 검증 필요 + +### 1.3. 서버 구현 (`internal/server/`, `cmd/server/`) +- `internal/server/inference_server.go` — InferenceService 구현 +- `internal/server/device_server.go` — DeviceRegistry 구현 +- `internal/server/gateway_server.go` — GatewayService 구현 +- `cmd/server/main.go` — `--transport=quic|h2` 플래그 기반 진입점 + +### 1.4. 클라이언트 구현 (`internal/client/`) +- `internal/client/inference_client.go` — gRPC 클라이언트 (재시도·타임아웃) +- `internal/client/rest_client.go` — REST 비교군 클라이언트 + +### 1.5. 미들웨어 (`internal/middleware/`) +- `logging.go` — 요청/응답 로깅 인터셉터 +- `metrics.go` — latency 측정 인터셉터 + +--- + +## 2. REST 비교군 구현 (Phase 1) + +### 2.1. REST 서버 +- `cmd/rest-server/main.go` — HTTP/1.1 + JSON REST API 서버 +- `--edge` 플래그 지원 (REST-Edge, 엣지 ROI 1차 처리) + +### 2.2. REST 클라이언트 +- `rest_client.go` — gRPC 클라이언트와 동일 시나리오 보장 + +--- + +## 3. 게이트웨이 구현 (Phase 2~3) + +### 3.1. 게이트웨이 코어 (`internal/gateway/`) +- `gateway.go` — 라우팅·변환 엔진 +- `protocol_adapter.go` — IoT 프로토콜 어댑터 인터페이스 +- `mqtt_adapter.go` — MQTT → Protobuf 변환 +- `coap_adapter.go` — CoAP → Protobuf 변환 (P1) +- `route_table.go` — 서비스 디스커버리·라우팅 테이블 (YAML 기반) + +### 3.2. 라우터 (`internal/router/`) +- `task_router.go` — 엣지 라우팅 로직 (ROI 결과 기반) + +### 3.3. 게이트웨이 서버 +- `cmd/gateway/main.go` — 게이트웨이 진입점 +- HTTP/2 fallback 모드 지원 (quic-go 리스크 대비) + +--- + +## 4. 스크립트·빌드 인프라 + +### 4.1. Shell 스크립트 (`scripts/`) +- `proto-gen.sh` — protoc 컴파일 자동화 +- `tc-setup.sh` — `--delay --loss --rate --interface` 옵션 지원 +- `tc-reset.sh` — tc 설정 초기화 + +### 4.2. Docker (`docker/`) +- `Dockerfile.server` — gRPC 서버 컨테이너 +- `Dockerfile.rest-server` — REST 서버 컨테이너 +- `docker-compose.yml` — 전체 실험 환경 구성 + +### 4.3. Makefile (루트) +- `make proto`, `make build`, `make run-server`, `make test` +- `make benchmark`, `make lint`, `make docker-up/down`, `make clean` + +### 4.4. Lint 설정 +- `.golangci-lint.yaml` — errcheck, govet, staticcheck 등 + +### 4.5. `go.mod` / `go.sum` (루트) +- 루트 Go 모듈 초기화 (`src/`와 별도) + +--- + +## 5. 벤치마크 (Phase 2~3) + +### 5.1. 벤치마크 러너 CLI +- `cmd/benchmark-runner/main.go` — `--mode=once|matrix --scenario --transport` +- 분산 환경 end-to-end 측정 (P50/P95/P99, RPS) +- 2모드: 단일 측정(`once`) / 전체 매트릭스 sweep(`matrix`) + +### 5.2. Go testing.B 벤치마크 (`benchmarks/scenarios/`) +- `unary_test.go` — Unary RPC 마이크로벤치마크 +- `streaming_test.go` — Streaming RPC 벤치마크 +- `rest_compare_test.go` — REST vs gRPC 비교 +- 역할: 단일 프로세스 내 직렬화 시간·처리량 측정 (benchmark-runner와 분리) + +### 5.3. 실험 결과 저장소 +- `benchmarks/results/YYYY-MM-DD/*.json` — raw latency + 메타데이터 +- 사후 분석: percentile + CI95 + Tukey outlier + Mann-Whitney U + +--- + +## 6. 문서·설계 결정 + +### 6.1. ADR (Architecture Decision Records) +`docs/decisions/` 디렉터리에 다음 ADR 작성 필요: +- `001-go-grpc-baseline.md` — Go + gRPC 기술 스택 선정 배경 +- `002-quic-grpc-compatibility-poc.md` — quic-go 호환성 검증 결과 +- `003-gateway-architecture.md` — 게이트웨이 아키텍처 및 novelty 정의 +- `004-protocol-adapter-design.md` — MQTT/CoAP 변환 전략 +- `005-routing-data-model.md` — 라우팅 데이터 모델 및 설정 형식 +- `006-experiment-design.md` — 실험 매트릭스·워크로드 파라미터 고정 + +### 6.2. 위험 관리 (`docs/risks.md`) +- quic-go 호환성 (R-01) +- Docker tc 미작동 (R-02) +- MQTT/CoAP 범위 과다 (R-03) +- Go 버전업 호환성 (R-04) +- 합성 부하의 한계 (R-05) + +--- + +## 7. Phase 0 UI — 사소한 개선 + +### 7.1. `types.go` — 6개 시스템 확장 (낮은 우선순위) +- REST-Cloud / REST-Edge / gRPC-H3-Stream / gRPC-H3-GW 추가 +- **메인 비교 대상은 REST-H2 / gRPC-H2 / gRPC-H3 3개**이므로 시급하지 않음 + +### 7.2. `Result.Latencies` RingBuffer 전환 (선택) +- 타입 레벨에서 cap을 명시하거나 RingBuffer로 변경 +- 현재는 simulator.go에서 500개로 제한 중 + +### 7.3. `padVisible()` 개선 (선택) +- `runewidth.StringWidth()` 사용하여 한글 정렬 보정 +- (`mattn/go-runewidth`는 이미 간접 의존성에 존재) + +--- + +## Phase별 요약 + +| Phase | 주요 작업 | 의존성 | +|-------|---------|--------| +| **1** | Proto 정의 + 전송 계층 + gRPC 서버/클라이언트 + REST 비교군 | — | +| **2** | 게이트웨이 + MQTT 어댑터 + 라우팅 | Phase 1 완료 | +| **3** | tc 스크립트 + Docker + 벤치마크 러너 | Phase 1 완료 | +| **4** | Mininet 토폴로지 + 다중 컨테이너 부하 | Phase 3 완료 | +| **5** | simulator 실측 교체 + 0-RTT/HoL 측정 | Phase 3~4 완료 | + +> 상세 우선순위는 `TASK_LIST.md`를, 의존 순서는 `IMPLEMENTATION.md` §6.2를 참조한다. diff --git a/src/ARCHITECTURE.md b/src/ARCHITECTURE.md new file mode 100644 index 0000000..f3836dd --- /dev/null +++ b/src/ARCHITECTURE.md @@ -0,0 +1,419 @@ +# ARCHITECTURE.md — 성능 검증 테스트베드 아키텍처 + +> 본 문서는 AIoT gRPC 고성능 통신 모듈 연구의 **성능 검증 테스트베드**의 정적·동적 아키텍처를 정의한다. +> 연구 목적·KPI는 [`CLAUDE.md`](CLAUDE.md), 디렉터리·코드 패턴은 [`IMPLEMENTATION.md`](IMPLEMENTATION.md), 데모 UI 가이드는 [`src/README.md`](src/README.md)를 참조한다. + +--- + +## 0. 본 문서의 목적 + +성능 검증 테스트베드가 다음을 만족함을 보이기 위함이다. + +1. **공정성 (Fairness)** — 6개 비교 시스템이 동일 워크로드·동일 네트워크 조건에서 측정된다. +2. **재현성 (Reproducibility)** — 동일 ADR 파라미터로 다른 시점·다른 호스트에서 같은 결과 분포가 재현 가능하다. +3. **점진성 (Phased)** — Phase 1(`tc`)에서 시작해 Phase 2(Mininet)로 토폴로지 복잡도를 단계적으로 확장 가능하다. +4. **관측 가능성 (Observability)** — 모든 KPI가 정의된 위치에서 정의된 방식으로 수집된다. +5. **위험 격리 (Risk Isolation)** — `R-01`(quic-go 호환성) 등 핵심 위험이 발생해도 일부 비교군 측정이 가능하도록 모듈이 분리된다. + +--- + +## 1. 전체 아키텍처 개요 + +``` +┌──────────────────────────── Control Plane ─────────────────────────────┐ +│ │ +│ benchmark-runner tc-setup.sh / mininet result-collector│ +│ (load generator) (network emulator) (metrics agg.) │ +│ │ │ │ │ +│ └──────── 실험 매트릭스 sweep + 결과 동기화 ─────────────┘ │ +│ │ +└────────────────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────── Data Plane (SUT) ────────────────────────────┐ +│ │ +│ Load Gen Node ──[ tc netem / mininet ]── Edge Node ─── Cloud Node │ +│ │ │ │ │ +│ │ ┌────┴─────┐ │ │ +│ │ │ Gateway │ │ │ +│ │ │ (선택적) │ │ │ +│ │ └────┬─────┘ │ │ +│ └──────────────── 6개 비교 시스템 중 하나 선택 ────────┘ │ +│ │ +└──────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + benchmarks/results/YYYY-MM-DD/*.json + │ + ▼ + src/cmd/benchcli (시각화·시연 UI) +``` + +**구성 원칙**: +- **Control Plane**과 **Data Plane**의 분리 — 측정·제어 트래픽이 측정 대상 트래픽에 영향을 주지 않도록 별도 인터페이스/네임스페이스 사용 +- **선언적 실험 정의** — 실험 매트릭스(시스템 × 네트워크 조건 × 시나리오 × 반복 횟수)는 ADR로 고정된 설정 파일로부터 생성 +- **수집 후 분석** — 측정 중에는 raw 데이터만 기록하고, 통계 처리·이상치 탐지·신뢰구간 계산은 사후 분석 단계에서 수행 + +--- + +## 2. 구성 요소 (Components) + +### 2.1. 부하 발생기 (Load Generator) — `cmd/benchmark-runner` + +- **역할**: 시나리오 정의에 따라 RPC/HTTP 호출을 발생시키고, 각 호출의 latency·바이트 수·성공 여부를 raw로 기록 +- **두 모드**: + - `--mode=once` — 단일 (시스템·조건·시나리오) 1회 측정 + - `--mode=matrix` — ADR이 정의한 실험 매트릭스 전체 sweep +- **타임스탬프 정밀도**: `time.Now()` (Go 모노토닉 클럭, 마이크로초) +- **Warm-up**: 본 측정 전 200회 호출로 JIT/연결 초기화 안정화 +- **출력**: `benchmarks/results/YYYY-MM-DD/{system}_{scenario}_{condition}.json` (raw latency 샘플 + 메타데이터) + +### 2.2. 시스템 분기 (Systems Under Test, SUT) + +| ID | 서버 진입점 | 핵심 모듈 | +|----|-----------|----------| +| REST-Cloud | `cmd/rest-server` | HTTP/1.1, JSON, no edge processing | +| REST-Edge | `cmd/rest-server` (`--edge` 플래그) | HTTP/2, JSON, edge ROI 1차 처리 | +| gRPC-H2 | `cmd/server --transport=h2` | HTTP/2 + `internal/transport/h2_listener.go` | +| gRPC-H3 | `cmd/server --transport=quic` | QUIC + `internal/transport/quic_listener.go` | +| gRPC-H3-Stream | `cmd/server --transport=quic --stream` | gRPC bidirectional streaming | +| gRPC-H3-GW | `cmd/gateway` + `cmd/server` | Gateway 경유, MQTT/CoAP 어댑터 통합 | + +> **Phase 1+ 목표** — 현재 Phase 0 UI(`types.go`)는 **REST-H2 / gRPC-H2 / gRPC-H3** 3개 시스템만 지원한다. 6개 시스템 확장(Edge/Stream/GW)은 추후 Phase별로 순차 추가 예정이다 (`TO-DO.md` 참조). + +각 시스템은 동일한 비즈니스 로직(이미지 ROI 탐지·센서 집계)을 호출하며, 차이는 **전송·직렬화·라우팅 계층**에만 있다. + +### 2.3. 네트워크 에뮬레이터 (Network Emulator) + +#### Phase 1 — Linux `tc netem` (현재) + +- 대상 NIC에 `netem` qdisc를 추가하여 지연·손실·대역폭을 제어 +- 적용 대상: Edge Node의 outbound NIC + (필요시) Cloud Node의 inbound NIC +- 적용 단위: 호스트 또는 Linux network namespace +- 명령 예시: + ```bash + tc qdisc add dev eth0 root netem delay 50ms loss 3% + tc qdisc change dev eth0 root netem rate 100mbit + ``` +- 자동화: `scripts/tc-setup.sh --delay 50ms --loss 3% --rate 100mbit --interface eth0` + +#### Phase 2 — Mininet (예정) + +- SDN 스위치 + Linux container 기반 다중 홉 토폴로지 +- 토폴로지 예: Load Gen ↔ Edge Switch ↔ Edge Node ↔ Backbone Switch ↔ Cloud Node +- 각 link에 독립적으로 `tc netem` 적용 가능 → 비대칭 경로 시뮬레이션 가능 +- AI Agent N=수백 시나리오를 위해 Load Gen을 다중 컨테이너로 분산 + +### 2.4. 측정 수집기 (Measurement Collector) + +세 가지 측정 채널이 병렬로 수집되며, 사후에 timestamp 기준으로 정렬·병합된다. + +| 채널 | 주체 | 측정 대상 KPI | +|------|------|--------------| +| **클라이언트 측 인터셉터** | benchmark-runner | latency 분포, RPS, 성공률, payload bytes | +| **호스트 자원 모니터** | `pidstat -p 1` 백그라운드 | CPU·Memory (서버 + 게이트웨이 별도) | +| **패킷 캡처** (선택) | `tcpdump -w *.pcap` | wire 페이로드 크기, 핸드셰이크 RTT | + +> **Observer effect 보정** (FEEDBACK §2.6): 인터셉터의 `time.Now()` 호출 자체가 마이크로초 bias를 추가하므로, 동일 인터셉터가 모든 시스템에 적용된다(상대 비교 유효). 절대값은 인터셉터 비활성화한 별도 측정으로 추정 보정값을 산출. + +### 2.5. 결과 저장소 (Results Store) + +``` +benchmarks/results/2026-05-07/ +├── matrix.json # 본 회차의 실험 매트릭스 (ADR 참조) +├── grpc-h3_small-many_lossy3.json # raw latency 샘플 + meta +├── grpc-h2_small-many_lossy3.json +├── rest-h2_small-many_lossy3.json +├── ... +├── pidstat/ +│ └── grpc-h3_small-many_lossy3.csv +├── pcap/ +│ └── grpc-h3_small-many_lossy3.pcap # (선택) +└── summary.md # 사후 분석 결과 +``` + +raw JSON 스키마 (CLAUDE §7.1): +```json +{ + "system": "grpc-h3", + "scenario": "small-many", + "condition": "lossy3", + "iter": 23, + "started_at": "2026-05-07T01:23:45.678Z", + "host": "edge-host-01", + "kernel": "Linux 7.0.0-15-generic", + "tc_command": "delay 50ms loss 3%", + "warmup_calls": 200, + "samples": [...], // ms 단위 latency + "bytes_sent": 12345678, + "success": 9970, + "fail": 30, + "outliers_tukey": 12, + "ci95_p99": [142.3, 158.7] +} +``` + +### 2.6. 시각화·시연 UI — `src/cmd/benchcli` + +- **현재 (Phase 0)**: 데모 모드 — `internal/ui/simulator.go`가 파라미터에 반응하여 mock 추세 생성 +- **Phase 5 이후**: simulator를 실측 결과 reader로 교체. 같은 UI에서 실측·시뮬레이션 모드를 전환 가능 +- 시연용·발표용 화면 제공 (CLAUDE의 비목표인 "프로덕션 대시보드"와 구분) + +--- + +## 3. 비교 대상 시스템의 구성 + +### 3.1. 시스템별 데이터 경로 + +``` +REST-Cloud: Load Gen ──[ HTTP/1.1 + JSON ]──> Cloud Node + (raw 데이터 직송, 베이스라인) + +REST-Edge: Load Gen ──[ HTTP/2 + JSON ]──> Edge Node ──[ HTTP/2 + JSON ]──> Cloud Node + (ROI 1차 처리) + +gRPC-H2: Load Gen ──[ HTTP/2 + Protobuf ]──> Edge Node ──[ HTTP/2 + Protobuf ]──> Cloud Node + +gRPC-H3: Load Gen ──[ HTTP/3 (QUIC) + Protobuf ]──> Edge Node ──[ HTTP/3 + Protobuf ]──> Cloud Node + ★ 본 연구 통신 모듈 + +gRPC-H3-Stream: 위와 같지만 Bidirectional Streaming 활용 + +gRPC-H3-GW: Load Gen ──[ MQTT/CoAP ]──> Gateway ──[ HTTP/3 + Protobuf ]──> Edge/Cloud + ★ 본 연구 게이트웨이 아키텍처 + (Gateway가 프로토콜 변환 + 정적 라우팅 수행) +``` + +### 3.2. 시스템 간 공통 비즈니스 로직 + +모든 시스템이 호출하는 *application-level 처리*는 동일하다. + +- **IoT 시나리오**: 1차 ROI 탐지 → (필요시) 정밀 분석 호출 +- **AI Agent 시나리오**: 합성 부하 — 입력 토큰 수 기반 RAG 조회 + 도구 호출 시뮬레이션 + +차이는 *전송·직렬화·라우팅 계층*에만 있다는 것이 공정 비교의 전제다. + +--- + +## 4. 노드 토폴로지 + +### 4.1. Phase 1 — 단일 호스트, 다중 namespace + +``` +┌────────────────────────── 단일 Linux 호스트 ────────────────────────────┐ +│ │ +│ ┌─ ns:loadgen ─┐ veth ┌─ ns:edge ─┐ veth ┌─ ns:gw ─┐ veth ┌─ ns:cloud ─┐ +│ │ │ ◀──▶ │ │ ◀────▶ │ │ ◀──▶│ │ +│ │ benchmark- │ │ gRPC/REST │ │ gateway │ │ backend │ +│ │ runner │ │ server │ │ │ │ server │ +│ └──────────────┘ └────────────┘ └─────────┘ └────────────┘ +│ ▲ ▲ ▲ ▲ │ +│ │ pidstat / pcap │ │ │ │ +│ └──────────────────────┴───────────────────┴─────────────────┘ │ +│ │ +│ tc netem 적용: veth(loadgen↔edge) 또는 veth(edge↔cloud) 또는 둘 다 │ +└────────────────────────────────────────────────────────────────────────────┘ +``` + +- **장점**: 빠른 실행, 외부 인프라 불필요, 재현성 높음 +- **한계**: 모든 namespace가 같은 커널·CPU 자원 공유. CPU 측정의 노이즈 가능성 + +### 4.2. Phase 2 — Mininet (예정) + +``` +┌────────────────────────────── Mininet 토폴로지 ────────────────────────────┐ +│ │ +│ [LoadGen×N] ──┐ │ +│ │ │ +│ [LoadGen×N] ──┤ │ +│ ├──> [SW1] ──┬──> [Edge Node] │ +│ [LoadGen×N] ──┤ │ │ +│ │ └──> [Gateway] ──> [SW2] ──> [Cloud Node] │ +│ [LoadGen×N] ──┘ │ +│ │ +│ 각 link에 독립적인 tc netem qdisc 적용 가능 │ +│ AI Agent N=100~수백 시나리오를 위해 Load Gen 다중화 │ +└──────────────────────────────────────────────────────────────────────────────┘ +``` + +- **장점**: 복잡한 토폴로지, 비대칭 경로, 다중 디바이스 시뮬레이션 +- **활용 시나리오**: 0-RTT 재연결을 위한 클라이언트 마이그레이션, 다중 게이트웨이 부하 분산 등 + +--- + +## 5. 데이터 흐름 + +### 5.1. 실험 한 사이클의 라이프사이클 + +``` +1. 매트릭스 로드 ─ ADR에서 정의된 실험 매트릭스 파싱 + (시스템 × 네트워크 조건 × 시나리오 × 반복) + +2. 환경 설정 ─ tc-setup.sh로 네트워크 조건 적용 + SUT 컨테이너 기동 (필요시) + +3. 자원 모니터 시작 ─ pidstat 백그라운드 시작 + (선택) tcpdump 시작 + +4. Warm-up ─ 200회 호출로 JIT/캐시 안정화 + +5. 본 측정 ─ 정의된 반복 횟수만큼 호출 + 각 호출의 (timestamp, latency, bytes, status) raw 기록 + +6. 자원 모니터 종료 ─ pidstat / tcpdump 종료 + 각 결과 파일 디스크에 flush + +7. 환경 복구 ─ tc-reset.sh로 네트워크 조건 원복 + +8. 다음 조합 반복 ─ 매트릭스 끝까지 + +9. 사후 분석 ─ raw 데이터에서 통계량 산출 + (P50/P95/P99, CI95, outlier 비율, Mann-Whitney U) + summary.md 생성 +``` + +### 5.2. 측정 데이터 파이프라인 + +``` +[클라이언트 인터셉터] ──┐ + │ +[pidstat 1초 샘플링] ──┼──▶ raw JSON / CSV 파일 + │ (per-system × per-condition × per-scenario) +[(선택) tcpdump pcap] ──┘ + │ + ▼ + [사후 분석 스크립트] + - percentile bootstrap (95% CI) + - Tukey fence outlier 식별 + - Mann-Whitney U (시스템 쌍 비교) + │ + ▼ + summary.md + 시각화 데이터 + │ + ▼ + src/cmd/benchcli (Phase 5+) +``` + +--- + +## 6. 워크로드 발생 모델 + +| 시나리오 | 페이로드 | 호출 패턴 | 동시성 | 부하 generator 동작 | +|---------|---------|----------|--------|-------------------| +| **AI Agent RPC** | 1–8 KB Unary | burst-pause-burst (poisson 또는 ON-OFF) | 격리 N=10/50/100 | 컨테이너당 1 goroutine, burst size·간격은 ADR 고정 | +| **IoT 데이터 전송** | 64KB ~ 2MB | Unary 또는 Streaming | 디바이스 N=10/50 | 디바이스당 1 connection, 정해진 간격으로 메시지 emit | + +> **합성 부하의 한계** (위험 R-05): AI Agent 시나리오는 실제 LLM 호출의 burst 패턴을 모방하지만, 실제 사용자 입력 분포는 반영하지 않는다. 결론에서 이 점을 명시하고, ADR에 burst 파라미터(평균 휴지·burst 크기·burst 간격)를 고정하여 재현성을 확보한다. + +--- + +## 7. 네트워크 조건 적용 메커니즘 + +`tc netem` qdisc 한 줄로 다음을 동시 제어: + +```bash +tc qdisc add dev root netem \ + delay <편도지연>ms \ + loss <손실률>% \ + rate <대역폭>mbit +``` + +### 7.1. 매트릭스 (CLAUDE §5.3) + +| 조건 | delay | loss | rate | 의도 | +|------|-------|------|------|------| +| Ideal | 0 ms | 0 % | 1 Gbps | 베이스라인 | +| LAN | 1 ms | 0 % | 1 Gbps | 로컬 엣지 | +| WAN-Low | 50 ms | 0 % | 100 Mbps | 일반 클라우드 | +| WAN-High | 200 ms | 0 % | 50 Mbps | 원거리 클라우드 | +| Lossy-1 | 50 ms | 1 % | 100 Mbps | 약한 손실 | +| Lossy-3 | 50 ms | 3 % | 100 Mbps | 중간 손실 (HoL Blocking 본격화) | +| Lossy-5 | 100 ms | 5 % | 50 Mbps | 강한 손실 (모바일 무선) | + +### 7.2. 적용 시 주의 + +- **양방향 적용**: tc netem은 outbound만 영향을 주므로, 양방향 시뮬레이션이 필요한 경우 양 끝 NIC에 모두 적용 +- **버퍼링 효과**: 큰 페이로드 + 낮은 대역폭 조합에서는 송신 큐가 가득 차서 latency가 의도와 다르게 측정될 수 있음 — `tbf` qdisc 추가 검토 필요 +- **kernel 버전 의존성**: netem의 동작이 kernel 버전에 따라 미세 차이 — 모든 측정에서 동일 호스트·동일 kernel 사용 (raw JSON에 기록) + +--- + +## 8. 게이트웨이 아키텍처 통합 (제안 ②) + +### 8.1. 게이트웨이의 위치와 책임 + +``` + ┌──────────────────────────┐ + [Load Gen as IoT]──▶│ Gateway │──▶ [Edge Backend] + MQTT/CoAP │ │ gRPC-H3 + │ ┌────────────────────┐ │ + │ │ Protocol Adapter │ │ + │ │ - mqtt_adapter.go │ │ + │ │ - coap_adapter.go │ │ + │ └─────────┬──────────┘ │ + │ │ │ + │ ┌─────────▼──────────┐ │ + │ │ Static Route Table │ │ + │ │ (rule-based) │ │ + │ └─────────┬──────────┘ │ + │ │ │ + │ ▼ │ + │ gRPC-QUIC client │ + │ (internal/transport/quic_dialer.go) + └──────────────────────────┘──▶ [Cloud Backend] + gRPC-H3 +``` + +### 8.2. 게이트웨이를 거치는 경우의 측정 + +- **추가 hop의 latency** — 같은 네트워크 조건에서 gRPC-H3 vs gRPC-H3-GW의 latency 차이로 측정 +- **자원 사용** — 게이트웨이와 백엔드를 *각각* 그리고 *합계*로 측정 (FEEDBACK §2.5 권고 — 단일 서버와의 공정 비교) +- **변환 비용** — MQTT → Protobuf 직렬화·역직렬화 cost (게이트웨이 내부 구간 측정) + +### 8.3. 핵심 위험과 대응 + +- **R-01 (quic-go 호환성)**: 게이트웨이의 백엔드 통신이 gRPC-QUIC이므로, 통신 모듈이 좌초하면 게이트웨이 검증도 영향받음 → 대비책으로 **HTTP/2 백엔드 통신 모드**도 게이트웨이가 지원하도록 설계 (CLI 플래그로 전환) +- **R-03 (어댑터 범위 과다)**: MQTT 어댑터 우선 검증, CoAP은 P1으로 격하 + +--- + +## 9. 재현성·검증성 보장 + +| 요구사항 | 메커니즘 | +|---------|---------| +| 동일 워크로드 재현 | ADR로 고정된 워크로드 파라미터 (이미지 해상도, RPS 목표, burst 간격) | +| 동일 네트워크 조건 재현 | `tc-setup.sh` 명령을 raw JSON에 기록 | +| 환경 정보 보존 | host/kernel/CPU/NIC 모델·드라이버 버전을 raw JSON 메타데이터에 기록 | +| 의존성 고정 | `go.mod`의 quic-go 버전 고정 (R-04 대응) | +| 통계적 유의성 | 최소 30회 반복 (Lossy-3/5는 50회), 95 % CI, Tukey outlier, Mann-Whitney U | +| 측정 도구 영향 | observer effect 보정값 별도 보고 (FEEDBACK §2.6) | + +--- + +## 10. Phase별 변경점 + +| Phase | 토폴로지 | 부하 generator | SUT | 시각화 | +|------|---------|--------------|-----|-------| +| **0 (현재)** | — (UI만) | — | — (mock) | `src/cmd/benchcli` (시뮬레이션) | +| **1** | 단일 호스트 + namespace | `cmd/benchmark-runner` (Go) | gRPC-H2 + REST 비교군 | benchcli (수동 결과 import) | +| **2** | + tc netem 단일 NIC | + AI Agent burst 모드 | + gRPC-H3 (제안 ①) | benchcli 자동 갱신 | +| **3** | + 게이트웨이 namespace | + MQTT 부하 mode | + gRPC-H3-GW (제안 ②) | + 게이트웨이 자원 별도 표시 | +| **4** | Mininet 다중 노드 | 다중 컨테이너 부하 | + gRPC-H3-Stream | + 다중 노드 토폴로지 뷰 | +| **5** | Mininet + 마이그레이션 | + 클라이언트 IP 변경 시나리오 | + 0-RTT 측정, HoL Blocking 측정 | + Phase 2 KPI 화면 | + +--- + +## 11. 본 아키텍처가 답하는 질문 + +| 질문 | 어떤 구성 요소가 답하는가 | +|------|------------------------| +| gRPC-H3가 gRPC-H2 대비 얼마나 빠른가? | §2.4 인터셉터 + §5 사후 분석 | +| 패킷 손실이 늘어날수록 어떤 시스템이 가장 강건한가? | §7 매트릭스 sweep + Lossy-1/3/5 | +| 게이트웨이 추가 hop의 latency 비용은? | §8.2 gRPC-H3 vs gRPC-H3-GW 비교 | +| 0-RTT 재연결 효과는 실제로 의미가 있는가? | Phase 5 측정 (R-01 후 도입) | +| 결론이 통계적으로 유의한가? | §9 신뢰 구간 + Mann-Whitney U | +| 합성 부하의 결론이 실제 시나리오로 일반화되는가? | R-05의 한계로 명시, ADR로 burst 파라미터 고정 | + +--- + +> 본 아키텍처 문서는 살아있는 문서다. 실험 진행 중 발견되는 제약·한계는 ADR로 등록하고, 본 문서를 갱신한다. diff --git a/src/README.md b/src/README.md index c9a7f54..4b5e080 100644 --- a/src/README.md +++ b/src/README.md @@ -138,7 +138,83 @@ github.com/charmbracelet/lipgloss v1.0.0 # 스타일링 --- -## 7. mock 시뮬레이터의 가정 +## 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`는 실제 측정 없이 파라미터에 반응하여 그럴듯한 추세를 만든다. 시뮬레이션이 가정한 추세는 다음과 같다. @@ -154,14 +230,15 @@ github.com/charmbracelet/lipgloss v1.0.0 # 스타일링 --- -## 8. 다음 단계 +## 9. 다음 단계 -### 8.1. UI 측면 +### 9.1. UI 측면 - 결과 export (JSON / CSV) 기능 추가 - 시나리오 저장/불러오기 (프리셋) - 비교 결과를 동시에 여러 개 누적 보기 (네트워크 조건 매트릭스 sweep) +- §7.6 / §7.7 KPI 화면 추가 (0-RTT Resumption, HoL Blocking 내성) -### 8.2. 백엔드 연결 (Phase 1+) +### 9.2. 백엔드 연결 (Phase 1+) 1. `proto/aiot/inference/inference.proto` 정의 및 `make proto`로 코드 생성 2. `cmd/server`에 gRPC InferenceService 구현 (HTTP/2) 3. `cmd/rest-server`에 동일 시나리오의 REST 엔드포인트 구현 @@ -173,7 +250,7 @@ github.com/charmbracelet/lipgloss v1.0.0 # 스타일링 --- -## 9. 트러블슈팅 +## 10. 트러블슈팅 | 증상 | 원인 / 해결 | |------|-----------|