Hseong

[KT AIVLE SCHOOL 7기] - Cloud Native Application (2) 본문

KT AIVLE SCHOOL 7기

[KT AIVLE SCHOOL 7기] - Cloud Native Application (2)

__hseong__ 2025. 6. 10. 17:05
728x90
반응형

 


✅ Gitpod 환경 세팅

# Gitpod 진입 (예시)
https://gitpod.io/#https://github.com/kyusooK/lab-shop-pub-sub-2024

# Docker 기반 Kafka 실행
cd infra
docker-compose up

🧱 MSA 마이크로서비스 핵심 설계

📌 DDD 구성 요소

  • Entity: 핵심 도메인 객체 (DB 저장 대상)
  • Aggregate: 일관성을 유지하는 객체 집합 단위
  • Command: 사용자 요청 (예: CreateOrder)
  • Event: 도메인에서 발생한 불변 사실 (예: OrderPlaced)
  • ReadModel: 조회 전용 모델 (CQRS용)

⚙ 서비스 간 비동기 연동 흐름

Client → Command → Aggregate 처리 → Event 발행 → Kafka → 다른 서비스 Event 처리

📂 Java 프로젝트 기본 구조 예시

📁 order
├── OrderApplication.java
├── domain
│   └── Order.java
├── event
│   └── OrderPlaced.java
├── command
│   └── CreateOrderCommand.java
├── policy
│   └── PolicyHandler.java
├── repository
│   └── OrderRepository.java
└── api
    └── OrderController.java

📦 주요 클래스 예시

1. Order.java

@Entity
public class Order {
    @Id @GeneratedValue
    private Long id;
    private String itemId;
    private Integer qty;
    private String customerId;
    private String address;
    private String status;

    @PostPersist
    public void onPostPersist() {
        OrderPlaced event = new OrderPlaced(this);
        event.publishAfterCommit();
    }

    @PreRemove
    public void onPreRemove() {
        OrderCancelled event = new OrderCancelled(this);
        event.publishAfterCommit();
    }
}

2. OrderPlaced.java

public class OrderPlaced extends AbstractEvent {
    private Long id;
    private String itemId;
    private Integer qty;
    // 생성자, getter, setter
}

3. PolicyHandler.java

@Service
public class PolicyHandler {
    @StreamListener(KafkaProcessor.INPUT)
    public void handle(@Payload OrderPlaced event) {
        if (!event.validate()) return;
        // 재고 차감 로직
    }
}

📡 Kafka 토픽 및 송수신

✅ Kafka 토픽 생성

kafka-topics.sh --create --bootstrap-server localhost:9092 \
--replication-factor 1 --partitions 1 --topic order-topic

✅ 메시지 송수신 테스트

# Producer
kafka-console-producer.sh --broker-list localhost:9092 --topic order-topic
> Hello Kafka!

# Consumer
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic order-topic --from-beginning

🔁 Kafka 보상 트랜잭션 예시

@StreamListener(KafkaProcessor.INPUT)
public void wheneverOrderCancelled_IncreaseStock(@Payload OrderCancelled event) {
    repository().findByProductId(event.getItemId())
        .ifPresent(inventory -> {
            inventory.setStock(inventory.getStock() + event.getQty());
            repository().save(inventory);
        });
}

🔄 동기 호출: FeignClient 예시

@FeignClient(name = "inventory", url = "${api.url.inventory}")
public interface InventoryService {
    @PostMapping("/inventory/{itemId}/decrease")
    void decreaseStock(@PathVariable String itemId, @RequestBody DecreaseStockCommand cmd);
}

🔐 장애 대응: Fallback 처리 예시

@FeignClient(name = "inventory", fallback = InventoryServiceFallback.class)
public interface InventoryService {
    Inventory getInventory(Long id);
}

@Service
public class InventoryServiceFallback implements InventoryService {
    public Inventory getInventory(Long id) {
        Inventory fallback = new Inventory();
        fallback.setStock(100L);
        return fallback;
    }
}

🧠 @ 어노테이션 용어 정리

📘 Spring

어노테이션 설명

@Service 비즈니스 로직 클래스
@Repository DB 처리 클래스, 예외 변환 포함
@RestController REST API 제공
@RequestMapping URL 매핑 지정
@PostMapping, @GetMapping HTTP 메소드 매핑
@Autowired 의존성 주입

📗 JPA

어노테이션 설명

@Entity DB 테이블 매핑 객체
@Id, @GeneratedValue PK 설정 및 자동 생성
@PostPersist, @PreRemove 저장/삭제 시점 콜백

📒 Kafka

어노테이션 설명

@StreamListener Kafka 메시지 수신 메서드
@Payload Kafka 메시지 본문 매핑
@EnableBinding KafkaProcessor 인터페이스 바인딩

📕 Feign

어노테이션 설명

@FeignClient 외부 API 호출 클라이언트
@RequestBody, @PathVariable 파라미터 설정
@Fallback 장애 시 대체 로직 연결

✅ 전체 흐름 시각화 (Mermaid)

graph TD
  A[사용자 Command 입력] --> B[Order 서비스 Aggregate 처리]
  B --> C[Kafka에 OrderPlaced Event 발행]
  C --> D[Inventory 서비스 Consumer 수신]
  D --> E[재고 차감 처리]
  F[OrderCancelled Event] --> G[Kafka] --> H[재고 복구 처리]

 

728x90
반응형