diff --git a/300_architecture/360_로빙_컨테이너_경량화_전략.md b/300_architecture/360_로빙_컨테이너_경량화_전략.md new file mode 100644 index 0000000..cb8e1ec --- /dev/null +++ b/300_architecture/360_로빙_컨테이너_경량화_전략.md @@ -0,0 +1,328 @@ +# 360. 로빙 컨테이너 경량화 전략 + +## 개요 + +현재 rb10508은 31개 파일, 82개 함수가 거미줄처럼 얽혀있는 monolithic 구조로, 메모리 사용량이 2GB를 넘어가고 있습니다. 이를 512MB 이하의 경량 컨테이너로 전환하여 100개 이상의 로빙을 동시에 운영할 수 있는 구조로 개선하고자 합니다. + +> "컨테이너는 몸, 기억은 영혼 - 100개 로빙이 하나의 스킬 서비스를 공유한다" + +## 현재 상황 분석 + +### 문제점 +1. **모든 기능이 한 컨테이너에 집중** + - LLM 호출, ChromaDB, PostgreSQL 접근 + - 메모리 관리, 스킬 처리, Slack 통신 + - 파일 간 강한 결합도 + +2. **리소스 과다 사용** + - 메모리: 2GB 이상 + - CPU: 지속적인 높은 사용률 + - 확장 시 비용 급증 + +3. **상태 의존성 (Stateful)** + - ChromaDB가 컨테이너 내부에 위치 + - 재시작 시 상태 복구 필요 + - 스케일링 어려움 + +## 목표 아키텍처 + +### Stateless Router + Microservices + +``` +현재 구조: 목표 구조: +┌─────────────────┐ ┌──────────────────┐ +│ rb10508 │ │ rb10508-lite │ +│ (2GB+) │ ──→ │ (512MB) │ +│ - 모든 기능 포함 │ │ - 라우팅만 담당 │ +└─────────────────┘ └────────┬─────────┘ + │ + ┌──────────┴──────────┐ + │ │ + ┌──────▼──────┐ ┌──────▼──────┐ + │State Service│ │ LLM Service │ + │ (공용 DB) │ │(Gemini/GPT) │ + └─────────────┘ └─────────────┘ + + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │Skill-Email │ │ Skill-News │ │ Skill-Slack │ + │ (HTTP API) │ │ (HTTP API) │ │ (HTTP API) │ + └─────────────┘ └─────────────┘ └─────────────┘ +``` + +### 핵심 설계 원칙 + +1. **경량화**: 로빙 컨테이너는 최소한의 리소스로 운영 +2. **무상태 (Stateless)**: 언제든 재시작 가능, 상태는 외부 관리 +3. **확장성**: 스킬 서버는 독립적으로 스케일링 +4. **비용 효율성**: LLM API는 공용 서버에서만 호출 +5. **독립성**: 각 컴포넌트별 독립 배포/업데이트 + +## 실행 로드맵 + +### Phase 1: 분석 및 설계 + +#### 주요 작업 +1. **의존성 맵 작성** + - file-graph-visualizer 결과 분석 + - 실행 경로 기준 우선순위 설정 + - 가장 빈번한 경로부터 분리 (예: Slack → 의도 분석 → LLM) + +2. **API 인터페이스 정의** + - RESTful API + WebSocket (실시간 업데이트) + - 내부 서비스용 gRPC 검토 + - 인증/인가 체계 설계 + +#### 용어 설명 +- **의존성 맵**: 코드 파일들 간의 import/호출 관계를 시각화한 다이어그램 +- **gRPC**: Google이 개발한 고성능 RPC 프레임워크, HTTP/2 기반으로 빠른 통신 지원 +- **WebSocket**: 실시간 양방향 통신을 위한 프로토콜 + +### Phase 2: 공용 서비스 구축 + +#### State Service (상태 관리 서비스) +```python +# 주요 기능 +- 사용자 상태 관리 (레벨, 스탯, 경험치) +- 메모리 저장/검색 (ChromaDB 통합) +- 회사별 설정 관리 +- 실시간 상태 동기화 +``` + +**구현 포인트**: +- PostgreSQL + ChromaDB 외부화 +- 세션 데이터와 장기 기억 논리적 분리 +- pgvector + materialized view로 검색 최적화 +- 버전 필드로 점진적 마이그레이션 지원 + +#### LLM Service (언어모델 관리 서비스) +```python +# 주요 기능 +- Gemini/OpenAI 통합 관리 +- 지능형 캐싱 (프롬프트 해시 기반) +- Rate limiting 및 API 키 풀 관리 +- 비용 최적화 (스탯 기반 모델 선택) +``` + +**구현 포인트**: +- 프롬프트 길이 ≥ n일 때만 캐싱 적용 +- API 키를 3개 그룹으로 분류 (고속/보통/저비용) +- 연산 스탯에 따라 적절한 그룹 선택 + +#### 용어 설명 +- **pgvector**: PostgreSQL의 벡터 검색 확장 기능 +- **materialized view**: 쿼리 결과를 물리적으로 저장하는 뷰, 성능 향상 +- **Rate limiting**: API 호출 횟수를 제한하여 과부하 방지 +- **API 키 풀**: 여러 API 키를 순환 사용하여 한도 분산 + +### Phase 3: 로빙 코어 경량화 + +#### 남길 기능 (최소한의 핵심) +1. **Slack 이벤트 수신 및 ACK** +2. **간단한 키워드 기반 라우팅** +3. **외부 서비스 호출 클라이언트** +4. **헬스체크 및 모니터링** + +#### 로빙 브레인의 새로운 역할 +```python +class RobingBrain: + """경량화된 로빙 브레인 - 라우터 역할만 수행""" + + def __init__(self): + self.skill_endpoints = { + "email": "http://skill-email:8501", + "news": "http://skill-news:8505", + "slack": "http://skill-slack:8503", + "pdf": "http://skill-pdf:8502" + } + + async def route_to_skill(self, message: str, user_id: str): + # 1. 간단한 키워드 매칭 (LLM 없이) + if "이메일" in message or "메일" in message: + skill_url = self.skill_endpoints["email"] + elif "뉴스" in message or "news" in message: + skill_url = self.skill_endpoints["news"] + elif "요약" in message or "스레드" in message: + skill_url = self.skill_endpoints["slack"] + + # 2. 외부 스킬 서비스 호출 + response = await self.http_client.post( + skill_url, + json={"message": message, "user_id": user_id} + ) + + # 3. 결과만 반환 (처리는 스킬 서버에서) + return response.json() +``` + +**현재**: 로빙이 직접 스킬 로직 실행 +**개선**: 로빙은 라우팅만, 실제 처리는 독립된 스킬 서버에서 + +#### 제거할 기능 (외부 서비스로 이동) +1. **gemini_service.py** → LLM Service +2. **chroma_service.py** → State Service +3. **복잡한 의도 분석 로직** → LLM Service +4. **메모리 관리 로직** → State Service + +#### 최적화 방법 +- FastAPI → Starlette 다운사이징 +- Uvicorn workers = 1로 제한 +- 불필요한 의존성 제거 +- Policy Object로 라우팅 결과 직렬화 + +#### 용어 설명 +- **ACK (Acknowledgment)**: 메시지 수신 확인 응답 +- **Starlette**: FastAPI의 기반이 되는 경량 웹 프레임워크 +- **Uvicorn**: Python 비동기 웹 서버 +- **Policy Object**: 의사결정 규칙을 객체로 표현한 패턴 + +## 즉시 실행 가능한 개선사항 + +### 1. 하드코딩 제거 +```python +# 현재 (gemini_service.py:190-192) +좋은 답변: "김종태님, 아드님은 초등학교 2학년이시고..." + +# 개선 +# 모델 컨피그 테이블에서 동적으로 로드 +``` + +### 2. 메모리 제한 설정 +```yaml +# docker-compose.yml에 추가 +deploy: + resources: + limits: + memory: 512m + cpus: '0.5' + reservations: + memory: 256m +``` + +### 3. 문서 이동 및 정리 +- `/DOCS/_archive/docs/architecture/로빙_아키텍쳐_설계_경량.md` +- → `/DOCS/300_architecture/360_로빙_컨테이너_경량화_전략.md` +- ADR(Architecture Decision Record)로 등록 + +## 위험 요소 및 대응 방안 + +### 1. 네트워크 지연 증가 +- **문제**: 서비스 분리로 1-2 RTT 추가 +- **대응**: + - 내부 로드밸런서(Envoy) 사용 + - Keep-alive 연결 유지 + - 중요 경로 캐싱 강화 + +### 2. 운영 복잡도 증가 +- **문제**: 서비스 수 증가로 관리 어려움 +- **대응**: + - 공통 미들웨어 프레임워크 + - 중앙집중식 로깅/모니터링 + - 자동화된 헬스체크 + +### 3. 배포 파편화 +- **문제**: 여러 서비스의 일관된 배포 어려움 +- **대응**: + - GitOps (Argo CD) 도입 + - Blue-Green 배포 + - 단계별 트래픽 미러링 + +#### 용어 설명 +- **RTT (Round Trip Time)**: 요청-응답 왕복 시간 +- **Envoy**: 고성능 프록시 및 로드밸런서 +- **GitOps**: Git을 통한 인프라 관리 방법론 +- **Blue-Green 배포**: 두 환경을 번갈아 사용하는 무중단 배포 + +## 기대 효과 + +### 리소스 절감 +- 메모리: 2GB+ → 512MB (75% 감소) +- CPU: 1 core → 0.5 core (50% 감소) +- 비용: 서버당 약 70% 절감 + +### 확장성 향상 +- 현재: 서버당 5-10개 로빙 +- 목표: 서버당 100+ 로빙 +- 수평 확장 용이 + +### 운영 효율성 +- 컴포넌트별 독립 배포 +- 장애 격리 및 빠른 복구 +- 중앙집중식 모니터링 + +## 추가 고려사항 + +### 로그 관리 전략 +```yaml +# 현재: SSD에 로그 저장 (문제) +volumes: + - ./logs:/code/logs + +# 개선: HDD로 심링크 설정 +# 호스트에서: ln -s /mnt/hdd/logs/rb10508 ./logs +volumes: + - ./logs:/code/logs:rw +``` + +**로그 경량화**: +- 로그 레벨 동적 조정 (DEBUG → INFO) +- 구조화된 로그 (JSON 형식) +- 외부 로그 수집기로 전송 (Fluentd/Logstash) + +### 환경변수 관리 +```python +# State Service에서 중앙 관리 +class ConfigService: + async def get_robing_config(self, robing_id: str): + return { + "log_level": "INFO", + "memory_limit": "512m", + "skill_endpoints": {...}, + "feature_flags": {...} + } +``` + +### 함수형 프로그래밍 접근 +```python +# 순수 함수로 스킬 처리 +def route_message(message: str, skill_map: dict) -> str: + """부작용 없는 라우팅 함수""" + for keyword, skill in skill_map.items(): + if keyword in message: + return skill + return "default" + +# 불변성 유지 +RouteResult = namedtuple('RouteResult', ['skill', 'confidence']) +``` + +### 메트릭 수집 +```python +# Prometheus 메트릭 +robing_request_count = Counter('robing_requests_total', 'Total requests') +robing_memory_usage = Gauge('robing_memory_bytes', 'Memory usage') +robing_response_time = Histogram('robing_response_seconds', 'Response time') +``` + +### 보안 강화 +- **네트워크 격리**: 스킬 서버는 내부망에서만 접근 +- **인증 토큰 순환**: JWT 토큰 주기적 갱신 +- **Rate Limiting**: 로빙별 요청 제한 +- **감사 로그**: 모든 API 호출 기록 + +## 다음 단계 + +1. **아키텍처 결정** + - State Service와 LLM Service 간 통신 방식 + - 이벤트 버스(Kafka/NATS) vs HTTP + 캐시 + +2. **파일럿 프로젝트** + - rb10508_lite 프로토타입 개발 + - 성능 벤치마크 및 검증 + +3. **점진적 마이그레이션** + - 기능별 단계적 분리 + - 트래픽 미러링으로 안정성 확보 + +--- + +*"로빙을 가볍게, 그러나 더 강하게 - 진정한 디지털 동료로의 진화"* \ No newline at end of file diff --git a/README.md b/README.md index f8c3c72..73a2970 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ - [330. 백엔드: PostgreSQL + ChromaDB Vector Memory](./300_architecture/330_백엔드_PostgreSQL_ChromaDB_Vector_Memory.md) - [340. GUI 공유 아키텍처: 레벨 기반 권한](./300_architecture/340_GUI_공유_아키텍처_레벨기반_권한.md) - [350. DID 기반 정체성과 다중 에이전트](./300_architecture/350_DID_기반_정체성과_다중에이전트.md) +- [360. 로빙 컨테이너 경량화 전략](./300_architecture/360_로빙_컨테이너_경량화_전략.md) #### Part 4: 성장과 진화 (400_growth) - [410. 레벨업 알고리즘과 사용자 피드백](./400_growth/410_레벨업_알고리즘과_사용자_피드백.md)