docs: 연구 방향(CLAUDE.md)과 구현 가이드(IMPLEMENTATION.md) 분리

연구 방향·정책과 구현 세부사항을 두 문서로 명확히 분리한다.

CLAUDE.md (연구 방향·정책 전용):
- 연구 배경 요약 (BACKGROUND.md 참조)
- 제안 기법 ① gRPC over QUIC 통신 모듈 (AIoT 도메인 실증)
- 제안 기법 ② AI Agent + IoT 통합 엣지 게이트웨이
- 우선순위별 목표(P0/P1/P2)와 의존성·리스크
- 위험 관리(Risk Register) — quic-go 호환성, tc 작동, 어댑터 범위 등
- 평가 시나리오·KPI·네트워크 조건·통계적 유의성 확보 계획
- 코드 작성 정책(계층 분리, 컨텍스트 전파, 에러 처리, 측정 가능성)

IMPLEMENTATION.md (구현 세부사항 전용):
- 프로젝트 디렉터리 구조 (proto/, gen/, internal/, cmd/, benchmarks/)
- 네이밍 규칙 (Proto·Go)
- 개발 워크플로우 (proto 컴파일, 서버 실행, tc 시뮬레이션, 테스트)
- 코드 패턴 (Transport 인터페이스, 컨텍스트, gRPC 에러, 인터셉터)
- Makefile 타겟 목록
- 멀티 에이전트 작업 분담 가이드
- 자주 수행하는 작업 시나리오

원칙: 디렉터리 경로·명령어·코드 샘플 등 구현 세부사항은 모두
IMPLEMENTATION.md에 두고, CLAUDE.md는 연구 방향과 정책에만 집중한다.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 01:31:31 +00:00
parent 5f35254d03
commit d2c63e7c19
2 changed files with 719 additions and 0 deletions
+374
View File
@@ -0,0 +1,374 @@
# AIoT gRPC 고성능 통신 모듈 — 연구 프로젝트
> **언어**: Go | **프로토콜**: gRPC over HTTP/3 (QUIC) + Protocol Buffers v3
> **목적**: AI Agent 및 AIoT 환경에서 고성능·경량 서비스 간 통신을 위한 **gRPC-QUIC 통신 모듈**과 이를 활용하는 **엣지 게이트웨이** 설계·구현·실증
> **연구의 성격**: 새로운 프로토콜의 발명이 아니라, **AIoT 도메인 워크로드(AI Agent RPC + IoT 데이터 전송)에 gRPC over QUIC을 적용한 domain-specific empirical study**. AIoT 워크로드 특성에 따른 효과 측정이 부재한 격차(gap)를 메우는 것이 목적이다.
---
## 0. 문서 지침 (먼저 읽을 것)
본 저장소의 문서는 **역할별로 분리**되어 있다. 작업을 시작하기 전에 자신의 작업 종류에 맞는 문서를 함께 참조한다.
| 문서 | 역할 | 언제 참조하는가 |
|------|------|----------------|
| **`CLAUDE.md`** (본 파일) | 연구 방향·동기·목표·평가 지표·코드 정책·위험 관리 | 모든 작업 시작 시 |
| **`IMPLEMENTATION.md`** | 디렉터리 구조, 네이밍, 워크플로우, 코드 패턴, Makefile, 멀티 에이전트 작업 분담 | 코드를 작성·수정·실행할 때 |
| `BACKGROUND.md` | 연구 시작의 구조적 배경 (AI Agent 시대의 통신 인프라 변화) — 발표 자료 추출 가능 형태 | 연구 동기를 깊이 이해하거나 슬라이드로 추출할 때 |
| `참고/SGS/README.md` | 선행 연구 (스마트팜 해충 탐지, gRPC vs REST/HTTP-2) | 연구 차별성·시나리오 설계 시 |
| `FEEDBACK.md` | 외부 리뷰어의 비평 (긍정 평가 생략, 개선 지점만) | 큰 설계 변경 전 또는 보강 항목을 찾을 때 |
| `docs/decisions/` | 설계 결정 기록 (ADR) | 중요한 설계 변경 전후 |
| `docs/open-questions.md` | 미해결 탐색 주제 | 새 실험을 기획할 때 |
> **원칙**: `CLAUDE.md`는 *연구 방향과 정책*만 다룬다. 디렉터리 경로, 명령어, 코드 샘플, 파일 단위 작업 분담 등 **구현 세부 사항은 모두 `IMPLEMENTATION.md`에** 둔다. 연구 배경의 자세한 서술은 모두 `BACKGROUND.md`에 두고, 본 문서는 *요약·정책·평가 계획*에 집중한다.
---
## 1. 연구 배경 및 동기 (요약)
> 본 절은 핵심 요약만 다룬다. 추세·기술 한계·QUIC 개요의 자세한 서술은 [`BACKGROUND.md`](BACKGROUND.md)를 참조한다. (FEEDBACK §4.5에 따라 중복을 제거했다.)
### 1.1. 세 가지 구조적 추세 (한 줄 요약)
| 추세 | 핵심 함의 |
|------|---------|
| **보안 격리** | 컨테이너/VM 격리로 같은 노드 내 통신도 네트워크 스택 경유 → 통신 건수 폭증 |
| **서브에이전트 + RAG** | 컨텍스트 한계 극복을 위한 외부 서비스 통신 빈도 증가 → 통신 속도가 응답성을 좌우 |
| **24/7 가동** | 사람이 쉬는 시간에도 동작하는 Agent로 동시간 트래픽 누적 → 동시성 폭증 |
→ 자세한 분석은 [`BACKGROUND.md`](BACKGROUND.md) §1, §2.
### 1.2. 기존 통신 기술의 한계 (한 줄 요약)
- gRPC(HTTP/2) > REST는 선행 연구로 검증됨 ([`참고/SGS`](참고/SGS/README.md))
- 그러나 HTTP/2 기반 gRPC는 **TCP의 근본적 한계**(연결 수립 비용, HoL Blocking, 연결 고정)를 그대로 상속
- QUIC(HTTP/3)은 위 세 한계를 모두 해결하는 차세대 전송 계층
→ 자세한 분석은 [`BACKGROUND.md`](BACKGROUND.md) §3.
### 1.3. 선행 연구의 향후 과제 중 본 연구의 위치 — 왜 HTTP/3을 선택했는가
[`참고/SGS`](참고/SGS/README.md)는 향후 연구로 다음 세 가지를 제시했다.
1. **HTTP/3(QUIC) 기반 gRPC 도입** ← 본 연구의 주제
2. 다양한 스트리밍 패턴 비교 (Unary / Server / Client / Bidi)
3. LLM 기반 동적 작업 라우팅
본 연구가 (1)을 우선 선택한 근거(FEEDBACK §2.1 반영):
- **(2) 스트리밍 패턴**은 응용 계층의 표현 변화로, **전송 계층의 병목(연결 수립 비용·HoL Blocking)을 해결하지 못한다**. 같은 TCP 위에서 호출 모양만 바꾸는 셈이다.
- **(3) LLM 라우팅**은 라우팅 의사결정의 지능화에 관한 것으로, **통신 채널의 효율 자체를 개선하지 않는다**. 라우팅이 똑똑해져도 채널이 느리면 응답성에 한계가 있다.
- **(1) HTTP/3 도입**은 §1.1의 세 추세(보안 격리·빈번한 RPC·동시성)가 모두 만나는 **전송 계층을 직접 개선**하는 가장 영향력 있는 단일 변경이며, AIoT 도메인에서 실증이 부재하다.
따라서 (1)을 우선 다루고, (2) 스트리밍 패턴은 본 연구의 P2 항목으로 부분 포함하며, (3) LLM 라우팅은 명시적 비목표(§3.2)로 제외한다.
### 1.4. 본 연구가 다루는 트래픽 두 종류
| 종류 | 특성 | 페이로드 | 대표 예시 |
|------|------|---------|----------|
| **AI Agent ↔ 외부 서비스/Agent** | 짧고 빈번한 RPC, 컨테이너 격리 환경 | 18 KB, Unary 위주 | 서브에이전트 호출, RAG 조회, 도구 호출 |
| **IoT Device ↔ Edge ↔ Cloud** | 다양한 응용 프로토콜(MQTT/CoAP), 엣지 단계적 처리 | 64 KB ~ 2 MB, 스트리밍 가능 | 해충 탐지 ROI 전달, 센서 데이터 적재 |
**두 시나리오를 동일한 gRPC-QUIC 스택으로 다루는 근거** (FEEDBACK §4.1 반영):
| QUIC 특성 | AI Agent 시나리오에서의 효용 | IoT 시나리오에서의 효용 |
|-----------|---------------------------|----------------------|
| 0-RTT 연결 수립 | 격리 에이전트 간 빈번한 단발성 RPC 가속 | 디바이스 reconnect 시 latency 감소 |
| 스트림 독립성 (HoL Blocking 해소) | 다중 동시 RPC의 안정성 | 무선/모바일 IoT 패킷 손실 환경 강건 |
| 연결 마이그레이션 | 컨테이너 재배치 시 일부 시나리오에서 유효 | 모바일 IoT, NAT rebinding |
| Protobuf 표현 (gRPC 공통) | 호출 인터페이스 IDL 일관성 | 페이로드 절감 (특히 큰 메시지) |
두 시나리오는 페이로드 크기와 패턴은 다르지만 **연결 빈도가 높고 패킷 손실에 노출되며 다양한 네트워크 조건에서 동작해야 한다**는 공통점을 가지며, QUIC의 핵심 이점이 두 시나리오 모두에 작용한다. 단, **각 시나리오에서 지배적인 KPI는 다르므로**(§5.4 참조) 단일 KPI로 두 시나리오를 평가하지 않는다.
---
## 2. 제안 기법
본 연구의 기여는 **AIoT 도메인에서의 실증(domain-specific empirical study)**이다. gRPC over QUIC의 발명은 본 연구의 기여가 아니다 — 이미 quic-go 커뮤니티의 PoC, MsQuic 등에서 시도되고 있다(FEEDBACK §4.2 반영).
### 2.1. 제안 ① — AIoT 환경에서의 gRPC-QUIC 실증
**기여의 성격**: 새로운 프로토콜의 발명이 아니라, **AIoT 도메인의 실제 워크로드에 gRPC over QUIC을 적용하고, 통제된 네트워크 조건에서 정량 비교**를 수행하는 empirical study다.
**왜 이 실증이 필요한가:**
- 기존 QUIC/HTTP-3 벤치마크는 **웹 트래픽**(브라우저-서버) 중심이며, AI Agent의 burst RPC 패턴이나 IoT 단계적 처리에 그대로 적용되지 않는다.
- gRPC core team의 gRPC-over-QUIC도 stable에 도달하지 않았으며, **AIoT 워크로드 특성에 따른 효과 측정**이 부재하다.
- 본 연구는 *"gRPC over QUIC이 AIoT 환경에서 얼마만큼의 개선을 가져오며, 어느 조건에서 가장 큰가?"*에 대한 정량 답을 제공한다.
QUIC의 어떤 특성이 어떻게 작용하는지(0-RTT, HoL Blocking, 연결 마이그레이션)는 §1.4 표 참조.
> 본 연구는 **0-RTT 측정에 필요한 TLS 1.3 설정 자체는 실험 범위에 포함**하며(self-signed 인증서 사용), 인증서 관리·인증/인가 등 프로덕션 수준의 보안 시스템은 비목표로 둔다 (§3.2).
### 2.2. 제안 ② — AI Agent + IoT 통합 엣지 게이트웨이
**기여의 성격**(FEEDBACK §2.2 반영): 프로토콜 변환과 정적 라우팅 자체는 이미 존재하는 개념이다. 본 게이트웨이의 기여는 다음 두 가지에 있다.
1. **AI Agent와 IoT를 단일 스택으로 통합** — 기존 IoT 게이트웨이는 MQTT↔HTTP 변환에 머무르고, AI Agent gateway는 별도 계열(LangGraph, MCP 등). 본 연구는 두 트래픽을 **하나의 게이트웨이가 처리하는 아키텍처**를 정의·구현·측정한다.
2. **gRPC-QUIC 백본과의 통합 검증** — 게이트웨이가 백엔드와 gRPC-QUIC으로 통신할 때의 성능 영향(추가 hop의 latency, 자원 사용)을 정량 측정한다. 기존 게이트웨이 연구는 HTTP/2 위에서만 평가되었다.
게이트웨이의 두 책임:
1. **프로토콜 변환** — 외부 IoT 응용 프로토콜(MQTT, CoAP)에서 들어오는 메시지를 gRPC/Protobuf로 변환. AI Agent 측 트래픽은 이미 gRPC이므로 변환 없이 라우팅 단계로 진입.
2. **서비스 라우팅** — 정적 룰 기반(룰 테이블) IoT 데이터의 단계적 처리 분배 및 AI Agent 호출의 백엔드 서비스 디스커버리.
> **선행 연구의 LLM 기반 라우팅**은 본 연구의 범위 밖이다 (§3.2). 본 연구의 라우팅은 정적 룰 기반으로 한정한다.
### 2.3. 선행 연구(SGS) 대비 차별성
| 비교 항목 | 선행 연구 (SGS) | 본 연구 |
|-----------|---------------|---------|
| 전송 계층 | HTTP/2 (TCP) | **HTTP/3 (QUIC) 추가 및 비교** |
| 시나리오 | 스마트팜 단일 시나리오 | IoT 시나리오 + **AI Agent RPC 패턴** 이중 |
| 게이트웨이 | 센서/엣지 인터페이스 변환기 (개념적 제시) | **AI Agent + IoT 통합 게이트웨이의 실증** |
| 평가 지표 | 응답 시간, 데이터 전송량 | + **0-RTT 효과**, **HoL Blocking 내성**, **연결 마이그레이션**, 통계적 유의성 |
| 비교 시스템 수 | 3개 | 6개 (4-way 전송 비교 + 스트리밍 + 게이트웨이) |
---
## 3. 프로젝트 목표 및 범위
### 3.1. 우선순위별 목표 (의존성 및 리스크 명시)
FEEDBACK §2.3에 따라 각 P0 목표의 의존성과 주된 리스크를 함께 표기한다.
| 우선순위 | 목표 | 주된 의존 / 리스크 |
|----------|------|------------------|
| P0 | **gRPC over QUIC 통신 모듈 구현** — Go 기반 서버/클라이언트 | quic-go ↔ gRPC transport interface 호환성 (§3.3 R-01) |
| P0 | **gRPC 엣지 게이트웨이 설계·구현** — 프로토콜 변환 + 정적 룰 라우팅 | 통신 모듈(P0-1) 의존, MQTT/CoAP 어댑터 범위 통제 필요 (§3.3 R-03) |
| P0 | gRPC/HTTP3 vs gRPC/HTTP2 vs REST/HTTP2 vs REST/HTTP1.1 4-way 정량 성능 비교 | P0-1 지연 시 HTTP/2까지 우선 측정, QUIC은 후속 추가 (§3.3 R-01 fallback) |
| P1 | **IoT 시나리오 벤치마크** — 이미지/센서 데이터 (해충 탐지 ROI 단계적 처리) | gRPC 서버/클라이언트 완성 후 |
| P1 | **AI Agent 통신 시나리오 벤치마크** — 짧고 빈번한 RPC, 다수 동시 에이전트 환경 | 동일 |
| P2 | gRPC 스트리밍 패턴 비교 (Unary / Server-side / Client-side / Bidirectional) | Unary 측정 후 |
| P2 | QUIC 0-RTT 재연결 성능 측정 및 연결 마이그레이션 시나리오 검증 | P0-1 완료 후 |
> P0-1(통신 모듈)이 본 프로젝트의 핵심 병목이므로, §3.3의 위험 관리가 본 프로젝트 운영의 가장 중요한 과제다.
### 3.2. 비목표 (명시적 제외)
- **프로덕션 수준 인증/인가 시스템 및 인증서 관리** *(0-RTT 측정에 필요한 TLS 1.3 설정 자체는 실험 범위에 포함, self-signed 인증서 사용)*
- **LLM 기반 동적 작업 라우팅** *(선행 연구의 향후 과제로 제시되었으나, 본 연구는 정적 룰 기반 라우팅에 한정)*
- 특정 하드웨어 최적화 (Raspberry Pi 등 임베디드 전용 튜닝)
- Kubernetes 오케스트레이션 자동화
- 프로덕션 UI/대시보드 *(데모 목적의 Terminal UI는 별도 산출물로 제공 — `src/README.md`)*
### 3.3. 위험 관리 (Risk Register)
FEEDBACK §4.4 권고에 따라 도입했다. 각 위험은 발생 시 ADR로 정식 등록하고, 변경이 발생하면 본 표를 갱신한다.
| ID | 위험 | 영향 | 가능성 | 대비책 |
|----|------|------|--------|--------|
| **R-01** | quic-go의 `Stream`과 gRPC transport(`net.Conn`) 인터페이스 의미 차이 — `SetDeadline`/`Close`(half-close)/`LocalAddr` 등 | 프로젝트 핵심 모듈 좌초 → P0 전체 지연 | 중간 | (a) PoC를 본 구현 전에 분리 제작하여 호환성 검증 (b) 실패 시 HTTP/2 기반 게이트웨이로 P0-2,3 우선 진행, QUIC은 별도 실험으로 분리 |
| **R-02** | Docker 환경에서 `tc(netem)` 미작동 또는 컨테이너 격리로 인한 효과 미반영 | 네트워크 시뮬레이션 신뢰도 저하 | 낮음~중간 | 호스트 레벨 tc 적용, 또는 Linux network namespace로 노드 분리 후 적용. Phase 2(Mininet)에서는 자동 적용 |
| **R-03** | MQTT/CoAP 어댑터 구현 범위 과다 | P0-2 일정 지연 | 중간 | MQTT만 우선 구현, CoAP은 P1으로 격하 |
| **R-04** | Go/quic-go 버전업에 따른 API 변경 | 빌드 실패, 재작업 | 낮음 | `go.mod`에 quic-go 버전 고정, ADR로 변경 사유 기록 |
| **R-05** | AI Agent 시나리오의 부하 발생기는 합성 부하 — 실제 LLM 호출 패턴과 차이 가능 | 결론의 일반화 약함 | 중간 | 부하 generator의 burst 파라미터(휴지·burst 크기·burst 간격)를 명시하고, 합성 부하임을 결론에 명기 |
---
## 4. 기술 스택
| 영역 | 기술 | 비고 |
|------|------|------|
| **언어** | Go 1.22+ | `go.mod` 기준 |
| **IDL** | Protocol Buffers v3 | `.proto` → Go 스텁 자동 생성 |
| **gRPC** | `google.golang.org/grpc` | 공식 Go gRPC 라이브러리 |
| **QUIC / HTTP/3** | `github.com/quic-go/quic-go` | Go 순수 구현 QUIC 라이브러리 (버전 고정 — R-04) |
| **gRPC-QUIC 바인딩** | 커스텀 transport 패키지 | quic-go 위에 gRPC 전송 계층 구현 (R-01) |
| **Protobuf 코드젠** | `protoc` + `protoc-gen-go` + `protoc-gen-go-grpc` | Makefile로 자동화 |
| **HTTP 비교군** | Go 표준 `net/http` + `encoding/json` | REST API (HTTP/1.1, HTTP/2) |
| **벤치마크** | Go 내장 `testing.B` + 커스텀 러너(`cmd/benchmark-runner`) | 측정 도구 (역할 분담은 IMPLEMENTATION.md) |
| **자원 사용 측정** | `pidstat` (1초 샘플링), `pprof`(핫스팟 분석 한정) | §5.2 측정 방법 참조 |
| **컨테이너** | Docker + Docker Compose | 실험 환경 재현성 확보 |
| **네트워크 제어** | Linux `tc` (Phase 1), Mininet (Phase 2) | 지연/손실/대역폭 시뮬레이션 |
> 구체적인 빌드/실행 명령은 [`IMPLEMENTATION.md`](IMPLEMENTATION.md) §3(개발 워크플로우)을 따른다.
---
## 5. 평가 시나리오 및 지표
### 5.1. 비교 대상 시스템
각 시스템은 **두 시나리오 (① AI Agent RPC, ② IoT 데이터 전송)** 모두에서 동일하게 측정한다. "처리 위치"는 **데이터의 1차 처리(ROI 탐지·집계 등)가 어디서 수행되는가**를 의미한다(FEEDBACK §2.4 반영하여 정의 일관화).
| 시스템 | 전송 프로토콜 | 직렬화 | 처리 위치 | 비고 |
|--------|-------------|--------|-----------|------|
| **REST-Cloud** | HTTP/1.1 (TCP) | JSON | 클라우드 (원시 데이터 직송) | 베이스라인 |
| **REST-Edge** | HTTP/2 (TCP) | JSON | 엣지 1차 처리 → 클라우드 | 기존 방식 |
| **gRPC-H2** | HTTP/2 (TCP) | Protobuf | 엣지 1차 처리 → 클라우드 | 선행 연구 재확인 |
| **gRPC-H3 (제안 ①)** | HTTP/3 (QUIC) | Protobuf | 엣지 1차 처리 → 클라우드 | **본 연구 통신 모듈** |
| **gRPC-H3-Stream** | HTTP/3 (QUIC) | Protobuf | 엣지, 스트리밍 | 스트리밍 확장 (P2) |
| **gRPC-H3-GW (제안 ②)** | HTTP/3 (QUIC) | Protobuf | 게이트웨이 경유 → 백엔드 | **본 연구 게이트웨이 아키텍처** |
### 5.2. 핵심 성능 지표 (KPI) 및 측정 방법
FEEDBACK §2.5 권고에 따라 측정 방법·조건·게이트웨이의 자원 측정 단위를 명시한다.
| 지표 | 설명 | 측정 방법 |
|------|------|-----------|
| **P50 / P95 / P99 Latency** | 응답 시간 분포 | 클라이언트 측 wall-clock 타임스탬프. **warm-up 200회 후 측정 시작**. |
| **Throughput (RPS)** | 초당 처리 요청 수 | 정상 종료된 요청 수 / 측정 구간 길이. 측정 구간은 최소 30초 또는 N≥10000 요청 |
| **Payload Size** | 단일 요청의 직렬화된 페이로드 크기 | tcpdump 캡처에서 application payload만 합산. TLS 오버헤드 포함 여부는 별도 ADR로 결정 |
| **CPU / Memory** | 서버 측 자원 사용률 | `pidstat -p <pid> 1`로 1초 단위 샘플링, 측정 구간 평균과 분산 보고. **게이트웨이 시나리오는 게이트웨이 + 백엔드 합계와 개별값 모두 보고**(공정 비교를 위해). pprof는 핫스팟 분석에만 사용하며 자원 비교 KPI에는 사용하지 않음 |
| **Connection Overhead** | 연결 수립 비용 | 첫 요청 vs. 재사용 요청 latency 차이 (10회 평균) |
| **0-RTT Resumption** | QUIC 0-RTT 재연결 효과 | 세션 캐시 적용 후 첫 요청 latency (QUIC only) |
| **HoL Blocking 내성** | 패킷 손실이 다른 스트림에 미치는 영향 | 병렬 스트림 4개 동시 전송 중 1개 스트림 강제 손실 시 나머지 3개의 latency |
### 5.3. 네트워크 조건 매트릭스
QUIC의 HoL Blocking 해소 효과를 분명히 드러내기 위해 손실 조건을 다양화했다(FEEDBACK §2.7 반영). TCP의 rapid recovery로 가려지는 1% 영역과 본격 효과가 드러나는 3–5% 영역을 모두 포함한다.
| 조건 | 지연 | 패킷 손실 | 용도 |
|------|------|-----------|------|
| Ideal | 0 ms | 0 % | 베이스라인 |
| LAN | 1 ms | 0 % | 로컬 엣지 |
| WAN-Low | 50 ms | 0 % | 일반 클라우드 |
| WAN-High | 200 ms | 0 % | 원거리 클라우드 |
| **Lossy-1** | 50 ms | **1 %** | 약한 손실 (TCP rapid recovery 영역) |
| **Lossy-3** | 50 ms | **3 %** | 중간 손실 (HoL Blocking 효과 본격화) |
| **Lossy-5** | 100 ms | **5 %** | 강한 손실 (모바일/원거리 무선 환경) |
### 5.4. 시나리오 정의 및 시나리오별 KPI 가중치
§1.4에서 분류한 두 트래픽 종류에 대해 다음 워크로드를 사용한다. **시나리오마다 지배적인 KPI가 다르므로**, 결과 해석 시 표의 "주요 KPI"를 우선 기준으로 삼는다(FEEDBACK §2.8 반영).
| 시나리오 | 페이로드 | 호출 패턴 | 동시성 | 주요 KPI | 보조 KPI |
|----------|----------|----------|--------|---------|---------|
| **① AI Agent RPC** | 18 KB 작은 요청/응답 | Unary, 짧은 burst 반복 | 격리 에이전트 N=10/50/100 | **Connection Overhead**, **0-RTT Resumption**, P50/P95 Latency, RPS | HoL Blocking 내성 |
| **② IoT 데이터 전송** | 64 KB ~ 2 MB | Unary + Streaming | 디바이스 N=10/50 | **Throughput**, P95/P99 Latency, **Payload Size**, **HoL Blocking 내성** (Lossy 조건) | Connection Overhead |
> **주의**: AI Agent RPC 시나리오에서 Payload Size는 직렬화 효율(Protobuf vs JSON)이 latency를 거의 좌우하지 않는 영역(수 KB)이다(직렬화 시간이 RTT보다 두세 자릿수 작음). 따라서 보고는 하되 결론의 핵심 근거로 사용하지 않는다. 이 시나리오의 핵심 차별 요인은 **연결 수립 비용**이다.
시나리오별 구체 워크로드 파라미터(이미지 해상도, RPS 목표, burst 크기 등)는 `docs/decisions/`의 ADR로 별도 고정한다.
### 5.5. 통계적 유의성 확보 계획
FEEDBACK §4.3을 반영하여 다음 원칙을 따른다. (단순한 `count=5`는 평균/분산 추정에 부족하다는 지적을 수용.)
| 항목 | 방침 |
|------|------|
| **반복 횟수** | 각 (시스템 × 네트워크 조건 × 시나리오) 조합당 최소 **30회 반복**. Lossy-3, Lossy-5는 분산이 크므로 **50회**로 증가 |
| **Warm-up** | 측정 전 동일 시스템에 200회 호출하여 JIT/캐시/연결 초기화 효과 안정화 |
| **신뢰 구간** | 모든 요약값에 **95% 신뢰 구간** 동반 보고. percentile은 percentile bootstrap, 평균은 Student's *t* |
| **Outlier 처리** | Tukey's fence(Q3 + 1.5×IQR 초과)를 outlier로 표시하되 **제거하지 않음**. 보고에 outlier 비율 포함 |
| **유의성 검정** | 두 시스템 간 차이의 유의성은 **MannWhitney U test**(latency 분포는 정규성 가정 어려움)로 판정, p<0.05 기준 |
| **재현성** | 모든 측정은 ADR로 등록된 워크로드 파라미터를 사용. 측정 환경(호스트, OS, NIC, kernel 버전, tc 명령) 함께 기록 |
---
## 6. 코드 작성 정책
본 절은 *정책*만 정의한다. 디렉터리 구조·네이밍·코드 패턴·예제 코드는 [`IMPLEMENTATION.md`](IMPLEMENTATION.md)를 따른다.
### 6.1. 계층 분리 (필수)
```
Transport (QUIC/TCP) → Protocol (gRPC/HTTP) → Serialization (Protobuf/JSON) → Business Logic
```
- 전송 계층은 **인터페이스로 추상화**하여 QUIC↔TCP를 동일 코드 경로로 교체 가능하게 한다 (벤치마크 공정성 보장)
- 게이트웨이는 *외부 IoT 프로토콜 ↔ gRPC Protobuf 변환*과 *서비스 라우팅*만 담당한다
- gRPC 서버 구현은 비즈니스 로직과 분리되어야 한다
### 6.2. 컨텍스트 전파
모든 RPC 함수는 `context.Context`를 첫 번째 인수로 받는다. **타임아웃은 클라이언트에서 설정**하고 서버는 컨텍스트 취소를 존중한다.
### 6.3. 에러 처리
gRPC 에러는 `google.golang.org/grpc/status` 패키지의 표준 코드를 사용한다.
### 6.4. 측정 가능성 (필수)
**모든 신규 RPC 구현은 latency 측정이 가능해야 한다.** 인터셉터(`internal/middleware/metrics.go`)를 활용하거나, 직접 측정이 필요한 경우 명시적으로 기록한다.
> **측정 도구의 observer effect** (FEEDBACK §2.6 반영): 인터셉터의 `time.Now()` 호출과 metric 기록은 측정값에 마이크로초 단위 bias를 추가한다. 본 연구는 모든 비교군에 *동일한 인터셉터*를 적용하므로 **상대 비교는 유효**하지만, **절대값**은 인터셉터를 비활성화한 별도 측정으로 추정 보정값을 산출하여 함께 보고한다. AI Agent 시나리오처럼 latency 자체가 작은 영역에서는 이 bias가 비례적으로 커질 수 있으므로 절대값 해석에 주의한다.
### 6.5. 금지 사항
- `gen/` 디렉터리 직접 수정 금지 — `.proto` 수정 후 재생성한다
- `panic` 사용 금지 (초기화 코드 제외)
- 전역 변수로 설정 관리 금지 — `config` 구조체를 사용한다
- 미사용 의존성 추가 금지 — `go mod tidy` 후 커밋
---
## 7. 연구 기록 규칙
### 7.1. 실험 결과
`benchmarks/results/YYYY-MM-DD/` 디렉터리에 시나리오별 JSON 결과와 `summary.md`를 함께 저장한다.
```
benchmarks/results/2026-05-07/
├── unary_ideal.json
├── unary_wan_200ms.json
├── streaming_wan_200ms.json
├── lossy3_wan_50ms.json
└── summary.md # 해당 날짜 실험 요약 및 주요 발견사항
```
각 JSON에는 raw latency 샘플 + 95% 신뢰구간 + outlier 비율(§5.5) + 측정 환경(host, kernel, tc 명령)을 함께 기록한다.
### 7.2. 설계 결정 (ADR)
`docs/decisions/NNN-{title}.md` 형식으로 기록한다.
```markdown
# NNN. {제목}
## 상태
Accepted / Deprecated / Superseded by NNN
## 맥락
왜 이 결정이 필요했는가?
## 결정
무엇을 선택했는가?
## 대안
고려했지만 선택하지 않은 것과 그 이유
## 결과
이 결정으로 인해 생기는 트레이드오프
```
§3.3의 주요 위험은 발생 시점 또는 mitigation 결정 시 ADR로 정식 등록한다.
### 7.3. 오픈 질문
`docs/open-questions.md`에 기록한다. 실험으로 답을 얻으면 해당 항목에 결과를 추가하고 닫는다.
### 7.4. 실패한 접근도 기록
무엇을 시도했고, 왜 실패했으며, 무엇을 배웠는지 `docs/decisions/`에 포함한다. 실패 기록은 미래의 시간 낭비를 막는 자산이다.
### 7.5. 외부 피드백 반영
[`FEEDBACK.md`](FEEDBACK.md)의 권고를 본 문서·`BACKGROUND.md`·`IMPLEMENTATION.md`에 반영할 때는, 어떤 항목을 어디에 어떻게 반영했는지 ADR 또는 본 문서의 해당 절에 *명시적으로 표기*한다 (현재 본 문서의 `(FEEDBACK §x.y 반영)` 표기 참조).
---
## 8. 참고 자료
- **본 저장소 내부**
- [`IMPLEMENTATION.md`](IMPLEMENTATION.md) — 구현 세부 사항 (디렉터리·네이밍·워크플로우·코드 패턴·멀티 에이전트 분담)
- [`BACKGROUND.md`](BACKGROUND.md) — 연구 수행 배경 (발표 자료 추출 가능 형태)
- [`참고/SGS/README.md`](참고/SGS/README.md) — 선행 연구
- [`FEEDBACK.md`](FEEDBACK.md) — 외부 리뷰어의 비평 (긍정 평가 생략)
- [`src/README.md`](src/README.md) — 데모 Terminal UI 빌드·실행 가이드
- `docs/decisions/` — 설계 결정 기록 (ADR)
- `docs/open-questions.md` — 미해결 탐색 주제
- **외부 문서**
- [RFC 9000 — QUIC](https://datatracker.ietf.org/doc/html/rfc9000)
- [RFC 9114 — HTTP/3](https://datatracker.ietf.org/doc/html/rfc9114)
- [gRPC 공식 문서](https://grpc.io/docs/)
- [gRPC Go 빠른 시작](https://grpc.io/docs/languages/go/quickstart/)
- [Protocol Buffers v3 언어 가이드](https://protobuf.dev/programming-guides/proto3/)
- [google.golang.org/grpc Go pkg](https://pkg.go.dev/google.golang.org/grpc)
- [quic-go GitHub](https://github.com/quic-go/quic-go)
---
> 본 프로젝트는 연구 목적의 프로토타입입니다. 프로덕션 환경의 안정성·보안·가용성을 보장하지 않습니다.
+345
View File
@@ -0,0 +1,345 @@
# IMPLEMENTATION.md — 구현 가이드
> 본 문서는 `CLAUDE.md`(연구 방향·정책)에서 분리된 **구현 세부 사항**을 다룬다.
> 디렉터리 구조, 네이밍 규칙, 개발 워크플로우, 코드 패턴, 멀티 에이전트 작업 분담 등이 포함된다.
>
> 연구 동기·목표·평가 지표는 `CLAUDE.md`를 참조한다.
---
## 1. 프로젝트 구조
```
.
├── proto/ # IDL 정의
│ └── aiot/
│ ├── inference/inference.proto # AI 추론 요청/응답
│ ├── device/device.proto # 디바이스 등록·상태 보고
│ └── gateway/gateway.proto # 게이트웨이 데이터 전달 서비스
├── gen/ # protoc 자동 생성 파일 (수동 수정 금지)
│ └── aiot/{inference,device,gateway}/
├── internal/ # 프로젝트 내부 패키지 (외부 import 불가)
│ ├── transport/
│ │ ├── transport.go # Listener/Dialer 인터페이스 정의
│ │ ├── quic_listener.go # QUIC 리스너 (quic-go 래핑)
│ │ ├── quic_dialer.go # QUIC 다이얼러 (클라이언트 연결)
│ │ └── h2_listener.go # HTTP/2 리스너 (비교군)
│ ├── gateway/
│ │ ├── gateway.go # 게이트웨이 코어 (라우팅·변환 엔진)
│ │ ├── protocol_adapter.go # IoT 프로토콜 어댑터 인터페이스
│ │ ├── mqtt_adapter.go # MQTT → Protobuf
│ │ ├── coap_adapter.go # CoAP → Protobuf
│ │ └── route_table.go # 서비스 디스커버리·라우팅 테이블
│ ├── server/
│ │ ├── inference_server.go # InferenceService 구현
│ │ ├── device_server.go # DeviceRegistry 구현
│ │ └── gateway_server.go # GatewayService 구현
│ ├── client/
│ │ ├── inference_client.go # gRPC 클라이언트 (재시도·타임아웃 포함)
│ │ └── rest_client.go # REST 비교군 클라이언트
│ ├── middleware/
│ │ ├── logging.go # 요청/응답 로깅 인터셉터
│ │ └── metrics.go # latency 측정 인터셉터
│ └── router/
│ └── task_router.go # 엣지 라우팅 로직 (ROI 결과 기반)
├── cmd/
│ ├── server/main.go # gRPC 서버 진입점 (--transport=quic|h2 플래그)
│ ├── gateway/main.go # gRPC 게이트웨이 진입점
│ ├── rest-server/main.go # REST 비교군 서버 진입점
│ └── benchmark-runner/main.go # 벤치마크 실행 CLI
├── benchmarks/
│ ├── scenarios/
│ │ ├── unary_test.go # Unary RPC 벤치마크
│ │ ├── streaming_test.go # Streaming RPC 벤치마크
│ │ └── rest_compare_test.go # REST vs gRPC 비교 벤치마크
│ └── results/ # 날짜별 결과 (YYYY-MM-DD/)
│ └── .gitkeep
├── docs/
│ ├── decisions/ # ADR (Architecture Decision Records)
│ │ └── 001-go-grpc-baseline.md
│ └── open-questions.md # 미해결 질문 및 탐색 주제
├── tests/
│ ├── unit/ # 단위 테스트
│ └── integration/ # 통합 테스트 (실제 서버 기동)
├── scripts/
│ ├── proto-gen.sh # protoc 컴파일 스크립트
│ ├── tc-setup.sh # tc 네트워크 지연 설정
│ └── tc-reset.sh # tc 설정 초기화
├── docker/
│ ├── Dockerfile.server
│ ├── Dockerfile.rest-server
│ └── docker-compose.yml # 전체 실험 환경 구성
├── CLAUDE.md # 연구 방향·정책
├── IMPLEMENTATION.md # (본 파일) 구현 세부 사항
├── BACKGROUND.md # 연구 수행 배경
├── go.mod
├── go.sum
└── Makefile
```
---
## 2. 네이밍 규칙
### 2.1. Proto 정의
| 대상 | 규칙 | 예시 |
|------|------|------|
| 패키지 | `aiot.{module}` | `aiot.inference` |
| 서비스 | `{명사}{역할}Service` | `InferenceService`, `DeviceRegistry` |
| RPC 메서드 | `{동사}{명사}` | `PredictFrame`, `RegisterDevice`, `StreamSensorData` |
| 메시지 | `{명사}{동사}Request/Response` | `FramePredictRequest`, `DeviceRegisterResponse` |
| 열거형 | `UPPER_SNAKE_CASE` | `PROCESSING_STATUS_PENDING` |
### 2.2. Go 코드
| 대상 | 규칙 |
|------|------|
| 파일 | `snake_case.go` |
| 패키지 | 단수 소문자 (`server`, `client`, `router`) |
| 인터페이스 | `{명사}` 또는 `{명사}er` (`InferenceService`, `Router`) |
| 구조체 | `PascalCase` |
| 함수/메서드 | `camelCase` (내부), `PascalCase` (공개) |
| 에러 변수 | `Err{명사}` (`ErrConnectionTimeout`) |
| 컨텍스트 | 첫 번째 인수, 변수명 `ctx` |
---
## 3. 개발 워크플로우
### 3.1. 초기 셋업
```bash
# Go 버전 확인 (1.22 이상 권장)
go version
# protoc 및 플러그인 설치 (최초 1회)
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 의존성 설치
go mod tidy
```
### 3.2. Proto 컴파일
```bash
make proto
# 또는 직접 실행:
# scripts/proto-gen.sh
```
**`gen/` 디렉터리 파일은 절대 직접 수정하지 않는다.** `.proto` 파일을 수정 후 재생성한다.
### 3.3. 서버/클라이언트 실행
```bash
# gRPC 서버 (전송 계층 선택)
make run-server # 기본
go run ./cmd/server --transport=quic --port=50051
go run ./cmd/server --transport=h2 --port=50052
# REST 비교군 서버
make run-rest-server
# 벤치마크
make benchmark
go run ./cmd/benchmark-runner --scenario unary --requests 10000 --concurrency 10
```
### 3.4. 네트워크 조건 시뮬레이션
```bash
# 지연 50ms
sudo ./scripts/tc-setup.sh --delay 50ms --interface eth0
# 지연 200ms + 패킷 손실 1%
sudo ./scripts/tc-setup.sh --delay 200ms --loss 1% --interface eth0
# 초기화
sudo ./scripts/tc-reset.sh --interface eth0
```
### 3.5. 테스트
```bash
# 단위 테스트
go test ./tests/unit/... -v
# 통합 테스트 (서버 자동 기동)
go test ./tests/integration/... -v -timeout 60s
# 벤치마크 (Go 표준)
go test ./benchmarks/... -bench=. -benchmem -count=5
```
---
## 4. 코드 패턴
### 4.1. Transport 인터페이스 설계
QUIC↔TCP를 동일한 코드 경로에서 교체할 수 있도록, 전송 계층은 인터페이스로 추상화한다.
```go
// internal/transport/transport.go
type Listener interface {
Accept(ctx context.Context) (net.Conn, error)
Addr() net.Addr
Close() error
}
type Dialer interface {
Dial(ctx context.Context, addr string) (net.Conn, error)
Close() error
}
```
- gRPC 서버/클라이언트 생성 시 `Listener`/`Dialer`를 주입받음
- 벤치마크는 동일 코드 경로로 전송 계층만 변경하여 공정 비교
### 4.2. 컨텍스트와 타임아웃
타임아웃은 **클라이언트에서 설정**한다. 서버는 컨텍스트 취소를 존중한다.
```go
func (c *InferenceClient) PredictFrame(ctx context.Context, req *pb.FramePredictRequest) (*pb.FramePredictResponse, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
return c.stub.PredictFrame(ctx, req)
}
```
### 4.3. gRPC 에러 처리
```go
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// 서버 측
return nil, status.Errorf(codes.InvalidArgument, "frame data is empty")
// 클라이언트 측
if st, ok := status.FromError(err); ok {
switch st.Code() {
case codes.DeadlineExceeded:
// 타임아웃 처리
case codes.Unavailable:
// 재연결 처리
}
}
```
### 4.4. Latency 측정 인터셉터
`internal/middleware/metrics.go`의 인터셉터를 RPC 등록 시 함께 등록한다. 직접 측정이 필요한 경우 구간을 명시적으로 기록한다.
```go
// 등록 예시
grpc.NewServer(
grpc.UnaryInterceptor(middleware.MetricsUnaryInterceptor),
grpc.StreamInterceptor(middleware.MetricsStreamInterceptor),
)
```
---
## 5. Makefile 타겟
```makefile
make proto # .proto → gen/ Go 코드 생성
make build # 모든 cmd/ 바이너리 빌드
make run-server # gRPC 서버 실행 (기본 포트 :50051)
make run-rest # REST 서버 실행 (기본 포트 :8080)
make test # 단위 + 통합 테스트
make benchmark # 전체 벤치마크 시나리오 실행
make lint # golangci-lint 실행
make docker-up # docker-compose로 전체 환경 기동
make docker-down # 환경 종료
make clean # 빌드 아티팩트 및 gen/ 삭제
```
---
## 6. 멀티 에이전트 작업 분담 가이드
여러 에이전트가 동시에 작업할 경우 아래 경계를 지킨다.
### 6.1. 독립 작업 도메인
| 도메인 | 담당 파일/디렉터리 | 주의사항 |
|--------|------------------|----------|
| **Proto 설계** | `proto/` | 필드 번호 변경은 전체 팀에 공지 후 진행 |
| **QUIC 전송 계층** | `internal/transport/` | 인터페이스(`Listener`/`Dialer`) 확정 후 구현, quic-go 의존 |
| **gRPC 게이트웨이** | `internal/gateway/`, `cmd/gateway/` | transport 인터페이스 의존, 프로토콜 어댑터는 독립 개발 가능 |
| **gRPC 서버 구현** | `internal/server/`, `cmd/server/` | `gen/` + transport 인터페이스 의존 |
| **REST 비교군** | `internal/client/rest_client.go`, `cmd/rest-server/` | gRPC 서버와 동일한 시나리오 구현 필수 |
| **벤치마크 스크립트** | `benchmarks/`, `cmd/benchmark-runner/` | 서버/클라이언트 인터페이스 확정 후 구현 |
| **라우터 로직** | `internal/router/` | 인터페이스만 맞추면 독립 개발 가능 |
| **문서/분석** | `docs/`, `benchmarks/results/` | 코드 변경 없이 병행 가능 |
### 6.2. 의존 순서
```
Proto 정의 완료
└─→ gen/ 코드 생성
Transport 인터페이스 확정 (internal/transport/transport.go)
├─→ QUIC Listener/Dialer 구현 (internal/transport/quic_*.go)
├─→ H2 Listener/Dialer 구현 (internal/transport/h2_*.go)
├─→ gRPC 서버 구현 (transport 주입)
├─→ gRPC 게이트웨이 구현
│ ├─→ 프로토콜 어댑터 (MQTT, CoAP — 독립 병행 가능)
│ └─→ 라우팅 테이블
├─→ gRPC 클라이언트 구현
├─→ REST 비교군 구현
└─→ 벤치마크 구현
└─→ 실험 실행 → 결과 기록
```
### 6.3. 충돌 방지
- `go.mod` / `go.sum` 변경 시 다른 에이전트에 즉시 알린다
- `proto/` 파일에 새 필드 추가 시 **필드 번호를 기존과 겹치지 않게** 유보 번호를 확인한다
- 실험 결과 파일은 날짜/시나리오명으로 고유하게 명명하여 덮어쓰기를 방지한다
---
## 7. 자주 수행하는 작업 시나리오
### 7.1. 새 RPC 추가
1. `proto/aiot/{module}/{service}.proto`에 메시지·서비스 정의
2. `make proto``gen/` 코드 생성
3. `internal/server/`에 핸들러 구현
4. `internal/middleware/metrics.go` 인터셉터로 측정 자동화
5. `tests/unit/`에 단위 테스트 추가
6. `benchmarks/scenarios/`에 벤치마크 시나리오 추가
### 7.2. 새 전송 계층 추가
1. `internal/transport/transport.go``Listener`/`Dialer` 인터페이스 충족 확인
2. `internal/transport/{name}_listener.go`, `{name}_dialer.go` 구현
3. `cmd/server/main.go``--transport` 플래그 분기에 추가
4. 벤치마크 실행 시 `--transport={name}` 옵션으로 비교군 등록
### 7.3. 새 IoT 프로토콜 어댑터 추가 (게이트웨이)
1. `internal/gateway/protocol_adapter.go`의 어댑터 인터페이스 확인
2. `internal/gateway/{protocol}_adapter.go` 구현
3. 게이트웨이 부트스트랩(`cmd/gateway/main.go`)에서 어댑터 등록
4. `tests/integration/`에 end-to-end 테스트 추가