Nebula AIλ AI κΈ°λ° λΆλ§ν¬ μ μ₯ λ° μ¬μ©μ νλ‘ν κ΄λ¦¬ μμ€ν μΌλ‘, λ§μ΄ν¬λ‘μλΉμ€ μν€ν μ²μ CQRS ν¨ν΄μ κΈ°λ°μΌλ‘ ꡬμΆλ νμ₯ κ°λ₯ν νλ«νΌμ λλ€.
βββββββββββββββββββ HTTP API βββββββββββββββββββ
β Spring Boot β βββββββββββββββΊ β AI Server β
β μλ² β β (FastAPI) β
β β β β
β - μ¬μ©μ μΈμ¦ β β - νλ‘ν λΆμ β
β - μΉ μΈν°νμ΄μ€ β β - μΆμ² μμ§ β
β - λ°μ΄ν° κ΄λ¦¬ β β - λ²‘ν° μ²λ¦¬ β
βββββββββββββββββββ βββββββββββββββββββ
β
β RabbitMQ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β λ©μμ§ ν μμ€ν
β
β β
β βββββββββββββββ βββββββββββββββ β
β β λΆλ§ν¬ β β νλ‘ν β β
β β μ μ₯ ν β β μ
λ°μ΄νΈν β β
β βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββ
β
β Celery
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β λ°±κ·ΈλΌμ΄λ μμ
μ²λ¦¬ β
β β
β βββββββββββββββ βββββββββββββββ β
β β λ²‘ν° μμ± β β μ μ¬λ β β
β β μμ
β β κ³μ° μμ
β β
β βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β λ°μ΄ν° μ μ₯μ β
β β
β βββββββββββββββ βββββββββββββββ β
β β PostgreSQL β β Redis β β
β β (λ©μΈ DB) β β (μΊμ) β β
β βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββ
μ¬μ©μ νλ‘ν μμ€ν μ CQRS ν¨ν΄μ ν΅ν΄ μ½κΈ°μ μ°κΈ°λ₯Ό λΆλ¦¬νμ¬ μ±λ₯κ³Ό νμ₯μ±μ 보μ₯ν©λλ€.
Spring Boot β RabbitMQ β AI Server β λΉλκΈ° μ²λ¦¬ β λ°μ΄ν° μ μ₯
νΉμ§:
- λͺ¨λ μ λ°μ΄νΈ μμ μ λ©μμ§ νλ₯Ό ν΅ν΄ λΉλκΈ° μ²λ¦¬
- μμμ μ°μ°κ³Ό μ΄λ²€νΈ μμ± μ§μ
- λμ μ²λ¦¬λκ³Ό μμ μ± λ³΄μ₯
Spring Boot β FastAPI μ§μ νΈμΆ β μ¦μ μλ΅
νΉμ§:
- μ€μκ° μ‘°ν API μ 곡
- μΊμ κΈ°λ° λΉ λ₯Έ μλ΅
- μ½κΈ° μ μ© μ΅μ νλ λ°μ΄ν° ꡬ쑰
μ¬μ©μ νλ β μ΄λ²€νΈ λ°μ β λ©μμ§ ν β μ΄λ²€νΈ μ²λ¦¬ β μν μ
λ°μ΄νΈ
μ£Όμ μ΄λ²€νΈ:
- λΆλ§ν¬ μ μ₯ μ΄λ²€νΈ
- μ±ν μΈμ μλ£ μ΄λ²€νΈ
- νλ‘ν νμ§ μ²΄ν¬ μ΄λ²€νΈ
- μΆμ² κ°±μ μ΄λ²€νΈ
- μν : μΉ μΈν°νμ΄μ€, μΈμ¦, μΈμ κ΄λ¦¬
- κΈ°μ : Java, Spring Boot, MySQL
- μ± μ: μ¬μ©μ κ²½ν, λ°μ΄ν° 무결μ±
- μν : AI λΆμ, λ²‘ν° μ²λ¦¬, μΆμ² μμ§
- κΈ°μ : Python, FastAPI, PostgreSQL
- μ± μ: λ¨Έμ λ¬λ, μμ°μ΄ μ²λ¦¬, λ²‘ν° μ°μ°
sequenceDiagram
participant U as μ¬μ©μ
participant S as Spring Boot
participant Q as RabbitMQ
participant A as AI μλ²
participant C as Celery
participant D as PostgreSQL
U->>S: λΆλ§ν¬ μ μ₯ μμ²
S->>Q: λ©μμ§ λ°ν
Q->>A: Consumer μμ
A->>C: Task νμ
C->>C: λ²‘ν° μμ±
C->>D: λ°μ΄ν° μ μ₯
C->>Q: μλ£ μλ¦Ό
Q->>S: κ²°κ³Ό μμ
S->>U: μλ£ μλ΅
sequenceDiagram
participant E as μ΄λ²€νΈ
participant L as EventListener
participant P as ProfileProcessor
participant R as Redis
participant A as APIAdapter
participant Q as RabbitMQ
participant D as Database
E->>L: μ¬μ©μ νλ κ°μ§
L->>P: μ΄λ²€νΈ μ²λ¦¬
P->>R: μμ μΊμ
P->>A: API μ΄λν° νΈμΆ
A->>Q: λ©μμ§ λ°ν
Q->>P: λ°±κ·ΈλΌμ΄λ μ²λ¦¬
P->>D: νλ‘ν μ
λ°μ΄νΈ
- νλ μμν¬: FastAPI
- λΉλκΈ° μ²λ¦¬: Celery + Redis
- λ©μμ§ ν: RabbitMQ (aio-pika)
- ML/AI: OpenAI API, NLTK, scikit-learn
- λ²‘ν° DB: Chroma, PostgreSQL + pgvector
- νλ μμν¬: Spring Boot
- λ°μ΄ν°λ² μ΄μ€: MySQL
- μΈμ¦: Spring Security
- API ν΅μ : RestTemplate/WebClient
# μ£Όμ ν ꡬμ±
QUEUES = {
"bookmark.save": "λΆλ§ν¬ μ μ₯ μ²λ¦¬",
"profile.update": "νλ‘ν μ€μκ° μ
λ°μ΄νΈ",
"profile.refresh": "νλ‘ν λ°°μΉ κ°±μ ",
"recommendation.refresh": "μΆμ² μμ€ν
κ°±μ ",
"analytics": "λΆμ μμ
"
}- PostgreSQL: λ©μΈ λ°μ΄ν° μ μ₯μ (λ²‘ν° λ°μ΄ν° ν¬ν¨)
- Redis: μΊμ λ° μΈμ μ μ₯μ
- MySQL: Spring Boot μλ² λ°μ΄ν°
- Chroma: λ²‘ν° μ μ¬λ κ²μ
- Spring Boot: JWT κΈ°λ° μΈμ¦
- AI μλ²: API ν€ κΈ°λ° μ κ·Ό μ μ΄
- λ΄λΆ ν΅μ : λ©μμ§ νλ₯Ό ν΅ν μμ ν ν΅μ
- κ°μΈμ 보 λ§μ€νΉ: μ±ν λ°μ΄ν° μλ λ§μ€νΉ
- μνΈν: μ€μ λ°μ΄ν° μνΈν μ μ₯
- μ κ·Ό μ μ΄: μ¬μ©μλ³ λ°μ΄ν° μ κ·Ό κΆν
# λ€μΈ΅ μΊμ± ꡬ쑰
CACHE_LAYERS = {
"L1": "Redis (λΉ λ₯Έ μ κ·Ό)",
"L2": "PostgreSQL (μꡬ μ μ₯)",
"L3": "λ²‘ν° DB (μ μ¬λ κ²μ)"
}- μ€μκ°: μ€μν μ λ°μ΄νΈ μ¦μ μ²λ¦¬
- λ°°μΉ: λλ λ°μ΄ν° ν¨μ¨μ μ²λ¦¬
- μ€μΌμ€λ§: μμ€ν λΆν λΆμ°
- Celery Worker: λ 립μ μ€μΌμΌλ§
- AI μλ²: Load Balancerλ₯Ό ν΅ν λ€μ€ μΈμ€ν΄μ€
- λ°μ΄ν°λ² μ΄μ€: μ½κΈ° 볡μ λ³Έ νμ©
- RabbitMQ Management: ν μν λͺ¨λν°λ§
- Flower: Celery μμ λͺ¨λν°λ§
- Prometheus + Grafana: μμ€ν λ©νΈλ¦
- λ‘κ·Έ μ§κ³: μ€μνλ λ‘κ·Έ κ΄λ¦¬
- Circuit Breaker: μλΉμ€ μ₯μ 격리
- Retry Logic: μλ μ¬μλ λ©μ»€λμ¦
- Dead Letter Queue: μ€ν¨ν λ©μμ§ μ²λ¦¬
- Health Check: μλΉμ€ μν μλ κ°μ§
{
"user_id": "μ¬μ©μ μλ³μ",
"profile_vector": "768μ°¨μ 벑ν°",
"last_updated": "λ§μ§λ§ μ
λ°μ΄νΈ μκ°",
"quality_score": "νλ‘ν νμ§ μ μ",
"metadata": "μΆκ° λ©νλ°μ΄ν°"
}{
"bookmark_id": "λΆλ§ν¬ μλ³μ",
"user_id": "μμ μ",
"title": "μ λͺ©",
"url": "URL",
"vector_embedding": "μ½ν
μΈ λ²‘ν°",
"keywords": "ν€μλ 리μ€νΈ",
"similarity_score": "μ μ¬λ μ μ"
}# λ‘컬 κ°λ° νκ²½ ꡬμ±
make local # μ 체 μλΉμ€ μμ
make test-all # ν΅ν© ν
μ€νΈ
make dev-setup # κ°λ° νκ²½ μ€μ - κ°λ°: Docker Compose κΈ°λ°
- μ€ν μ΄μ§: Kubernetes ν΄λ¬μ€ν°
- νλ‘λμ : ν΄λΌμ°λ λ€μ΄ν°λΈ λ°°ν¬
- μ½λ μ»€λ° β GitHub
- μλ ν μ€νΈ β pytest, ν΅ν© ν μ€νΈ
- λΉλ β Docker μ΄λ―Έμ§
- λ°°ν¬ β νκ²½λ³ μλ λ°°ν¬
- μΆμ² μμ§ κ³ λν
- μ±λ₯ λ©νΈλ¦ λμ보λ
- A/B ν μ€νΈ νλ μμν¬
- λ¨Έμ λ¬λ νμ΄νλΌμΈ μλν
- λ€μ€ ν λνΈ μ§μ
- κ³ κΈ λΆμ κΈ°λ₯
- AI λͺ¨λΈ μ체 νλ ¨
- μ€μκ° κ°μΈν
- κΈλ‘λ² νμ₯
μ΄ μν€ν μ²λ νμ₯μ±, μμ μ±, μ±λ₯μ λͺ¨λ κ³ λ €νμ¬ μ€κ³λμμΌλ©°, μ§μμ μΈ κ°μ μ ν΅ν΄ λμ± μ κ΅ν μμ€ν μΌλ‘ λ°μ ν μμ μ λλ€.