Skip to content

Latest commit

Β 

History

History
442 lines (350 loc) Β· 16.2 KB

File metadata and controls

442 lines (350 loc) Β· 16.2 KB

Saga Pattern Example with Temporal & Eureka

이 ν”„λ‘œμ νŠΈλŠ” Temporal을 Saga Orchestrator둜, Spring Cloud Netflix Eurekaλ₯Ό μ„œλΉ„μŠ€ λ””μŠ€μ»€λ²„λ¦¬λ‘œ μ‚¬μš©ν•˜μ—¬ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€ κ°„ λΆ„μ‚° νŠΈλžœμž­μ…˜μ„ κ΄€λ¦¬ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€.

πŸ“‹ λͺ©μ°¨


πŸ— μ•„ν‚€ν…μ²˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           ν΄λΌμ΄μ–ΈνŠΈ                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                                β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    order-service (8080)                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  POST /api/orders                                            β”‚   β”‚
β”‚  β”‚  1. 재고 확인 (Feign β†’ inventory-service) [동기]            β”‚   β”‚
β”‚  β”‚  2. μ£Όλ¬Έ μ €μž₯ (PENDING)                                      β”‚   β”‚
β”‚  β”‚  3. Workflow μ‹œμž‘ (Temporal)                                 β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                               β”‚
        β”‚ Feign (동기)                   β”‚ Workflow μ‹œμž‘
        β–Ό                               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ inventory-service β”‚     β”‚              Temporal Server             β”‚
β”‚     (8083)        β”‚     β”‚                (7233)                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
                                        β”‚ Task Queue 폴링
                                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               saga-orchestrator (8082) ⭐ Orchestrator               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Temporal Worker                                             β”‚   β”‚
β”‚  β”‚  β”œβ”€ OrderWorkflow (Saga 둜직)                                β”‚   β”‚
β”‚  β”‚  β”‚   β”œβ”€ Step 1: reserveStock (inventory-service)            β”‚   β”‚
β”‚  β”‚  β”‚   β”œβ”€ Step 2: processPayment (payment-service)            β”‚   β”‚
β”‚  β”‚  β”‚   └─ Step 3: completeOrder (order-service)               β”‚   β”‚
β”‚  β”‚  └─ 보상 νŠΈλžœμž­μ…˜                                            β”‚   β”‚
β”‚  β”‚      β”œβ”€ releaseStock (재고 ν•΄μ œ)                             β”‚   β”‚
β”‚  β”‚      └─ refundPayment (결제 ν™˜λΆˆ)                            β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                       β”‚                       β”‚
        β–Ό                       β–Ό                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ inventory     β”‚     β”‚ payment       β”‚     β”‚ order         β”‚
β”‚ -service      β”‚     β”‚ -service      β”‚     β”‚ -service      β”‚
β”‚ (Activity)    β”‚     β”‚ (Activity)    β”‚     β”‚ (Activity)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Eureka Server     β”‚
                    β”‚      (8761)         β”‚
                    β”‚  μ„œλΉ„μŠ€ λ””μŠ€μ»€λ²„λ¦¬    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β–²
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                     β”‚                     β”‚
   order-service      inventory-service     payment-service
   saga-orchestrator

πŸ›  기술 μŠ€νƒ

ꡬ뢄 기술
Language Java 21
Framework Spring Boot 3.3.x
Build Tool Gradle 8.x
Service Discovery Spring Cloud Netflix Eureka
동기 호좜 OpenFeign
Saga Orchestration Temporal
Database H2 (in-memory), PostgreSQL (Temporal)
Container Docker, Docker Compose

πŸ“ ν”„λ‘œμ νŠΈ ꡬ쑰

saga-example/
β”œβ”€β”€ eureka-server/                    # πŸ†• Eureka Server (μ„œλΉ„μŠ€ λ””μŠ€μ»€λ²„λ¦¬)
β”‚   └── src/main/java/com/example/eureka/
β”‚       └── EurekaServerApplication.java
β”‚
β”œβ”€β”€ saga-common/                      # 곡유 λͺ¨λ“ˆ (μΈν„°νŽ˜μ΄μŠ€, μƒμˆ˜)
β”‚   └── src/main/java/com/example/saga/common/
β”‚       β”œβ”€β”€ workflow/
β”‚       β”‚   β”œβ”€β”€ OrderWorkflow.java
β”‚       β”‚   β”œβ”€β”€ OrderServiceActivities.java
β”‚       β”‚   β”œβ”€β”€ PaymentServiceActivities.java
β”‚       β”‚   └── InventoryServiceActivities.java  # πŸ†•
β”‚       └── constants/
β”‚           └── SagaConstants.java
β”‚
β”œβ”€β”€ inventory-service/                # πŸ†• 재고 μ„œλΉ„μŠ€ (도메인)
β”‚   └── src/main/java/com/example/inventory/
β”‚       β”œβ”€β”€ InventoryServiceApplication.java
β”‚       β”œβ”€β”€ domain/
β”‚       β”‚   β”œβ”€β”€ Inventory.java
β”‚       β”‚   └── StockReservation.java
β”‚       β”œβ”€β”€ repository/
β”‚       β”œβ”€β”€ service/
β”‚       β”‚   β”œβ”€β”€ InventoryService.java
β”‚       β”‚   └── InventoryServiceActivitiesImpl.java
β”‚       β”œβ”€β”€ controller/
β”‚       β”‚   └── InventoryController.java
β”‚       └── config/
β”‚
β”œβ”€β”€ order-service/                    # μ£Όλ¬Έ μ„œλΉ„μŠ€ (+ Feign Client)
β”‚   └── src/main/java/com/example/order/
β”‚       β”œβ”€β”€ OrderServiceApplication.java
β”‚       β”œβ”€β”€ client/                   # πŸ†•
β”‚       β”‚   β”œβ”€β”€ InventoryClient.java  # Feign Client
β”‚       β”‚   └── InventoryClientFallback.java
β”‚       β”œβ”€β”€ domain/
β”‚       β”œβ”€β”€ service/
β”‚       β”‚   β”œβ”€β”€ OrderService.java     # 재고 확인 둜직 μΆ”κ°€
β”‚       β”‚   └── OrderServiceActivitiesImpl.java
β”‚       └── ...
β”‚
β”œβ”€β”€ payment-service/                  # 결제 μ„œλΉ„μŠ€
β”‚   └── src/main/java/com/example/payment/
β”‚       └── ...
β”‚
β”œβ”€β”€ saga-orchestrator/                # Saga Orchestrator
β”‚   └── src/main/java/com/example/orchestrator/
β”‚       └── workflow/
β”‚           └── OrderWorkflowImpl.java  # 재고 Saga μΆ”κ°€
β”‚
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ build.gradle
β”œβ”€β”€ settings.gradle
└── README.md

λͺ¨λ“ˆ μ˜μ‘΄μ„±

           saga-common (곡유 라이브러리)
                    ↑
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚               β”‚               β”‚               β”‚
order-service  inventory-service  payment-service  saga-orchestrator
(Workflow μ‹œμž‘)   (Activity κ΅¬ν˜„)  (Activity κ΅¬ν˜„)  (Workflow κ΅¬ν˜„)
    β”‚
    └──→ InventoryClient (Feign - 동기 호좜)
              β”‚
              β–Ό
         inventory-service

                    ↑ Eureka 등둝 ↑
              eureka-server (8761)

πŸ”„ Saga 흐름

성곡 μΌ€μ΄μŠ€ (amount ≀ 100 & 재고 μΆ©λΆ„)

sequenceDiagram
    participant Client
    participant OrderService
    participant InventoryService
    participant Temporal
    participant Orchestrator
    participant PaymentService

    Client->>OrderService: POST /api/orders<br/>{productId, quantity, amount: 50}
    OrderService->>InventoryService: [Feign] 재고 확인
    InventoryService-->>OrderService: {available: true}
    OrderService->>OrderService: μ£Όλ¬Έ μ €μž₯ (PENDING)
    OrderService->>Temporal: Start OrderWorkflow
    OrderService-->>Client: 201 Created<br/>{id, status: PENDING}

    Temporal->>Orchestrator: Task Queue 폴링
    
    Note over Orchestrator: [Step 1] 재고 μ˜ˆμ•½
    Orchestrator->>InventoryService: reserveStock()
    InventoryService-->>Orchestrator: true (μ˜ˆμ•½ 성곡)
    
    Note over Orchestrator: [Step 2] 결제 처리
    Orchestrator->>PaymentService: processPayment()
    PaymentService-->>Orchestrator: true (결제 성곡)
    
    Note over Orchestrator: [Step 3] μ£Όλ¬Έ μ™„λ£Œ
    Orchestrator->>OrderService: completeOrder()
    Orchestrator->>InventoryService: confirmStock()
    
    Note over Orchestrator: Saga μ™„λ£Œ (성곡)
Loading

μ‹€νŒ¨ μΌ€μ΄μŠ€ (결제 μ‹€νŒ¨ β†’ 재고 볡ꡬ)

sequenceDiagram
    participant Client
    participant OrderService
    participant InventoryService
    participant Temporal
    participant Orchestrator
    participant PaymentService

    Client->>OrderService: POST /api/orders<br/>{productId, quantity, amount: 200}
    OrderService->>InventoryService: [Feign] 재고 확인
    InventoryService-->>OrderService: {available: true}
    OrderService->>OrderService: μ£Όλ¬Έ μ €μž₯ (PENDING)
    OrderService->>Temporal: Start OrderWorkflow
    OrderService-->>Client: 201 Created

    Temporal->>Orchestrator: Task Queue 폴링
    
    Note over Orchestrator: [Step 1] 재고 μ˜ˆμ•½
    Orchestrator->>InventoryService: reserveStock()
    InventoryService-->>Orchestrator: true
    
    Note over Orchestrator: [Step 2] 결제 처리
    Orchestrator->>PaymentService: processPayment()
    PaymentService-->>Orchestrator: false (μž”μ•‘ λΆ€μ‘±)
    
    Note over Orchestrator: 보상 νŠΈλžœμž­μ…˜ μ‹€ν–‰
    Orchestrator->>InventoryService: releaseStock() (보상)
    Orchestrator->>OrderService: cancelOrder()
    
    Note over Orchestrator: Saga μ™„λ£Œ (결제 μ‹€νŒ¨ β†’ μ·¨μ†Œ)
Loading

πŸš€ μ‹€ν–‰ 방법

1. 사전 μš”κ΅¬μ‚¬ν•­

  • Java 21
  • Docker & Docker Compose
  • Gradle 8.x (λ˜λŠ” Gradle Wrapper μ‚¬μš©)

2. ν”„λ‘œμ νŠΈ λΉŒλ“œ

./gradlew clean build -x test

3. 인프라 μ‹€ν–‰ (Temporal)

docker-compose up -d

4. μ„œλΉ„μŠ€ μ‹€ν–‰ (μˆœμ„œλŒ€λ‘œ)

# 터미널 1: Eureka Server (λ¨Όμ € μ‹€ν–‰!)
./gradlew :eureka-server:bootRun

# 터미널 2: Inventory Service
./gradlew :inventory-service:bootRun

# 터미널 3: Payment Service
./gradlew :payment-service:bootRun

# 터미널 4: Order Service
./gradlew :order-service:bootRun

# 터미널 5: Saga Orchestrator
./gradlew :saga-orchestrator:bootRun

5. μ„œλΉ„μŠ€ 접속 정보

μ„œλΉ„μŠ€ 포트 μ„€λͺ…
eureka-server 8761 μ„œλΉ„μŠ€ λ””μŠ€μ»€λ²„λ¦¬ Dashboard
order-service 8080 μ£Όλ¬Έ API
payment-service 8081 결제 API
saga-orchestrator 8082 Saga Orchestrator (Temporal Worker)
inventory-service 8083 재고 API
Temporal Web UI 8088 Workflow λͺ¨λ‹ˆν„°λ§
Temporal Server 7233 Temporal gRPC

6. μ’…λ£Œ

docker-compose down -v

πŸ§ͺ API ν…ŒμŠ€νŠΈ

재고 쑰회

curl http://localhost:8083/api/inventory

μ£Όλ¬Έ 생성 (성곡 μΌ€μ΄μŠ€: amount ≀ 100)

curl -X POST http://localhost:8080/api/orders \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user-1",
    "productId": "PROD-001",
    "quantity": 2,
    "amount": 50
  }'

응닡:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "userId": "user-1",
  "productId": "PROD-001",
  "quantity": 2,
  "amount": 50,
  "status": "PENDING"
}

μ£Όλ¬Έ 쑰회 (μž μ‹œ ν›„ COMPLETED둜 변경됨)

curl http://localhost:8080/api/orders/{orderId}

μ£Όλ¬Έ 생성 (μ‹€νŒ¨ μΌ€μ΄μŠ€: amount > 100)

curl -X POST http://localhost:8080/api/orders \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user-2",
    "productId": "PROD-001",
    "quantity": 1,
    "amount": 200
  }'

μž μ‹œ ν›„ μ‘°νšŒν•˜λ©΄ CANCELED μƒνƒœ:

{
  "id": "...",
  "status": "CANCELED"
}

πŸ–₯ Eureka Dashboard

http://localhost:8761 μ—μ„œ Eureka Dashboard에 μ ‘μ†ν•˜μ—¬:

  1. λ“±λ‘λœ μ„œλΉ„μŠ€ λͺ©λ‘ 확인
  2. 각 μ„œλΉ„μŠ€μ˜ μΈμŠ€ν„΄μŠ€ μƒνƒœ 확인
  3. μ„œλΉ„μŠ€ ν—¬μŠ€ 체크

λ“±λ‘λ˜λŠ” μ„œλΉ„μŠ€ λͺ©λ‘

  • ORDER-SERVICE
  • PAYMENT-SERVICE
  • INVENTORY-SERVICE
  • SAGA-ORCHESTRATOR

πŸ–₯ Temporal Web UI

http://localhost:8088 μ—μ„œ Temporal Web UI에 μ ‘μ†ν•˜μ—¬:

  1. Workflow λͺ©λ‘ 확인: μ‹€ν–‰ 쀑인/μ™„λ£Œλœ Workflow λͺ©λ‘
  2. Workflow 상세 보기: 각 Activity μ‹€ν–‰ 이λ ₯, μž…λ ₯/좜λ ₯ κ°’
  3. Timeline 보기: Saga 각 λ‹¨κ³„μ˜ μ‹œκ°„ 흐름

Workflow ID ν˜•μ‹

  • order-{orderId} ν˜•νƒœλ‘œ 생성됨

🎯 μ£Όμš” νŠΉμ§•

Eureka 기반 μ„œλΉ„μŠ€ λ””μŠ€μ»€λ²„λ¦¬

  • μ„œλΉ„μŠ€ μžλ™ 등둝/ν•΄μ œ
  • λ‘œλ“œ λ°ΈλŸ°μ‹± 지원
  • μ„œλΉ„μŠ€ ν—¬μŠ€ 체크

OpenFeign 동기 호좜

  • μ£Όλ¬Έ 생성 μ „ 재고 확인 (동기)
  • 선언적 REST ν΄λΌμ΄μ–ΈνŠΈ
  • Fallback 처리 지원

Temporal Saga νŒ¨ν„΄

  • 3단계 Saga: 재고 μ˜ˆμ•½ β†’ 결제 β†’ μ£Όλ¬Έ μ™„λ£Œ
  • μžλ™ 보상 νŠΈλžœμž­μ…˜
  • μƒνƒœ μ˜μ†μ„± 및 μž¬μ‹œλ„ 처리

πŸ“ ν”„λ‘œλ•μ…˜ 고렀사항

  1. λ©±λ“±μ„±: 재고 μ˜ˆμ•½, 결제 μš”μ²­μ˜ 쀑볡 처리 λ°©μ§€
  2. νƒ€μž„μ•„μ›ƒ: Activity별 μ μ ˆν•œ νƒ€μž„μ•„μ›ƒ μ„€μ •
  3. μž¬μ‹œλ„ μ •μ±…: μ„œλΉ„μŠ€λ³„ μž¬μ‹œλ„ μ „λž΅
  4. λͺ¨λ‹ˆν„°λ§: Prometheus, Grafana 연동
  5. λ³΄μ•ˆ: mTLS, 인증/인가
  6. λ‘œκΉ…: λΆ„μ‚° 좔적 (Jaeger, Zipkin)

πŸ“š μ°Έκ³  자료