📖
Aaron's TECH BOOK
  • Intro
    • About me
  • Lecture
    • Kubernetes
      • Begin Kubernetes
    • Kafka
      • Begin Kafka
    • Kotlin
      • TDD, Clean Code Preview
      • woowa Kotlin
    • Java
      • Multithread Concurrency
      • The Java
    • Toby
      • Toby Spring 6
      • Toby Spring Boot
    • MSA
      • 01.Micro Service
      • 02.DDD 설계
      • 03.DDD 구현
      • 04.EDA 구현
    • Spring Boot
    • Spring Batch
    • Spring Core Advanced
    • Spring DB Part II
    • Spring DB Part I
    • JPA API and Performance Optimization
    • JPA Web Application
    • JPA Programming Basic
    • Spring MVC Part 2
      • 01.Thymeleaf
      • 02.ETC
      • 03.Validation
      • 04.Login
      • 05.Exception
    • Spring MVC Part 1
      • 01.Servlet
      • 02.MVC
    • Http
      • 01.Basic
      • 02.Method
      • 03.Header
    • Spring Core
    • Study
      • Concurrency issues
      • First Come First Served
      • Performance Test
      • TDD
      • IntelliJ
  • Book
    • Kafka Streams in Action
      • 01.카프카 스트림즈
      • 02.카프카 스트림즈 개발
      • 03.카프카 스트림즈 관리
    • Effective Kotlin
      • 01.좋은 코드
      • 02.코드 설계
      • 03.효율성
    • 이벤트 소싱과 MSA
      • 01.도메인 주도 설계
      • 02.객체지향 설계 원칙
      • 03-04.이벤트 소싱
      • 05.마이크로서비스 협업
      • 06.결과적 일관성
      • 07.CQRS
      • 08.UI
      • 09.클라우드 환경
    • 몽고DB 완벽 가이드
      • I. 몽고DB 시작
      • II. 몽고DB 개발
    • Kotlin Cookbook
      • 코틀린 기초
      • 코틀린 기능
      • ETC
    • Kotlin in Action
      • 함수/클래스/객체/인터페이스
      • 람다와 타입
      • 오버로딩과 고차 함수
      • 제네릭스, 애노테이션, 리플렉션
    • Kent Beck Tidy First?
    • 대규모 시스템 설계 기초
      • 01.사용자 수에 따른 규모 확장성
      • 02.개략적인 규모 추정
      • 03.시스템 설계 공략법
      • 04.처리율 제한 장치 설계
      • 05.안정 해시 설계
      • 06.키-값 저장소 설계
      • 07.유일 ID 생성기 설계
      • 08.URL 단축기 설계
      • 09.웹 크롤러 설계
      • 10.알림 시스템 설계
      • 11.뉴스 피드 시스템 설계
      • 12.채팅 시스템 설계
      • 13.검색어 자동완성 시스템
      • 14.유튜브 설계
      • 15.구글 드라이브 설계
      • 16.배움은 계속된다
    • 실용주의 프로그래머📖
    • GoF Design Patterns
    • 도메인 주도 개발 시작하기
      • 01.도메인 모델 시작하기
      • 02.아키텍처 개요
      • 03.애그리거트
      • 04.리포지터리와 모델 구현
      • 05.Spring Data JPA를 이용한 조회 기능
      • 06.응용 서비스와 표현 영역
      • 07.도메인 서비스
      • 08.애그리거트 트랜잭션 관리
      • 09.도메인 모델과 바운디드 컨텍스트
      • 10.이벤트
      • 11.CQRS
    • Effective Java 3/E
      • 객체, 공통 메서드
      • 클래스, 인터페이스, 제네릭
    • 소프트웨어 장인
    • 함께 자라기
    • Modern Java In Action
      • 01.기초
      • 02.함수형 데이터 처리
      • 03.스트림과 람다를 이용한 효과적 프로그래밍
      • 04.매일 자바와 함께
    • Refactoring
      • 01.리펙터링 첫 번째 예시
      • 02.리펙터링 원칙
      • 03.코드에서 나는 악취
      • 06.기본적인 리펙터링
      • 07.캡슐화
      • 08.기능 이동
      • 09.데이터 조직화
      • 10.조건부 로직 간소화
      • 11.API 리팩터링
      • 12.상속 다루기
    • 객체지향의 사실과 오해
      • 01.협력하는 객체들의 공동체
      • 02.이상한 나라의 객체
      • 03.타입과 추상화
      • 04.역할, 책임, 협력
      • 05.책임과 메시지
      • 06.객체 지도
      • 07.함께 모으기
      • 부록.추상화 기법
    • Clean Code
    • 자바 ORM 표준 JPA 프로그래밍
Powered by GitBook
On this page
  • EDA
  • 도메인 헥사곤 구현
  • 카프카 토픽 설계
  • Integration Test
  • 비동기 문제
  1. Lecture
  2. MSA

04.EDA 구현

Last updated 1 year ago

EDA

이벤트 기반 통신

  • 데이터 생산/소유와 데이터 접근 행위가 철저히 분리

  • 이벤트 스트림은

이벤트 브로커 vs 메시지 브로커

  • 이벤트 브로커는 모든 컨슈머가 전체 사본 획득 가능

  • 메시지 브로커는 큐로 가져가면 사라짐

이벤트 브로커 주요 특징

  • 확장성: 여러 노드로 클러스터 단위 구성

  • 보존성 : 노드 간 데이터 복제

  • 고가용성: 장애 분산

  • 고성능: 여러 노드 생산/소비 분담

이벤트 보관 및 처리

  • 파티셔닝(portioning) : 이벤트 스트림을 여러 하위 이벤트 스트림으로 파티셔닝

  • 순서보장: 스트림 파티션 내에서 데이터 순서 보장

  • 불변성 : 한번 발행되면 수정 불가

  • 인덱싱: 이벤트 스트림에 기록되는 시점에 인덱스(오프셋, offset) 할당

    • 컨슈머는 다음에 읽기 시작 할 위치를 이 오프셋으로 특정하여 데이터 소비

  • 무기한 보존: 이벤트 스트림은 이벤트를 무기한 보존

  • 재연성: 필요한 데이터를 골라서 읽을 수 있도록 재연 가능

도메인 헥사곤 구현

도메인 이벤트

  • 도메인의 상태를 변화시킨 시점의 사건 이력

  • 결과적 일관성을 만족시키기 위해 생산/소비

  • 어떤 시점의 엔티티 속성 및 상태

  • 헥사고날의 내부영역, 도메인 모델에 위치

이벤트 흐름 설계

  • 이벤트 설계

    • 스트림당 이벤트는 하나만 정의

    • 이벤트는 하나의 목적만 보유(대여, 반납 ..)

    • 이벤트 크기는 최소화하기

  • 이벤트 흐름 설계

    • 대여(도서대여됨 Event) -> 도서, 회원, 베스트도서

    • 대여(도서반납됨 Event) -> 도서, 회원

    • 대여(대여정지해제됨 Event) -> 회원

카프카 토픽 설계

  • 클러스터: 여러 가지 노드를 묶은 상태

  • 토픽: 하나의 이벤트 스트림

  • 메시지: 이벤트 스트림으로 흘러가는 도메인 이벤트

  • 오프셋: 컨슈머가 어디까지 읽었는지 표시

  • 커넥트 소스: 카프카에서 데이터를 보내는 쪽

  • 커넥트 싱크: 어답터?

  • 파티션: 컨슈머에 따라 토픽들이 파티셔닝

  • 컨슈머 그룹:

  • 주키퍼: 노드 관리, 각 토픽마다 컨슈머가 몇번의 오프셋을 처리했는지 기억, 특정 노드가 죽으면 어디로 가야 하는지 안내

Integration Test

docker-compose-infra_only.yml

version: '3'
services:
  # MongoDB
  mongodb:
    image: mongo:latest
    container_name: mongodb
    ports:
      - "27017:27017"
  # Zookeeper
  zookeeper-1:
    image: confluentinc/cp-zookeeper:latest
    ports:
      - '32181:32181'

    environment:
      ZOOKEEPER_CLIENT_PORT: 32181
      ZOOKEEPER_TICK_TIME: 2000

  # kafka
  kafka-1:
    image: confluentinc/cp-kafka:latest
    container_name: kafka-msa
    ports:
      - '9092:9092'

    depends_on:
      - zookeeper-1
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper-1:32181'
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka-1:29092,EXTERNAL://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      # KAFKA_DEFAULT_REPLICATION_FACTOR: 3
      KAFKA_NUM_PARTITIONS: 4

  kafka-ui:
    image: provectuslabs/kafka-ui
    container_name: kafka-ui
    ports:
      - "8989:8080"
    restart: always
    environment:
      - KAFKA_CLUSTERS_0_NAME=local
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka-1:29092
      - KAFKA_CLUSTERS_0_ZOOKEEPER=zookeeper-1:32181

비동기 문제

Saga Pattern 적용

마이크로서비스들끼리 이벤트를 주고 받아 특정 마이크로서비스에서의 작업이 실패하면 이전까지의 작업이 완료된 마이크서비스들에게 보상(complemetary) 이벤트를 소싱함으로써 분산 환경에서 원자성(atomicity)을 보장하는 패턴

kafka rent event producer

@Value(value = "${producers.topic1.name}")
private String TOPIC_RENT;

private final KafkaTemplate<String, ItemRented> kafkaTemplate;

// ...

kafkaTemplate.send(TOPIC_RENT, itemRented)
{
	"idName": {
		"id": "jenny",
		"name": "제니"
	},
	"item": {
		"no": 1,
		"title": "누구를 위하여 종을 울리나?"
	},
	"point": 10
}

kafka rent event consumer

private final ObjectMapper objectMapper = new ObjectMapper();

@KafkaListener(topics = "${consumer.topic1.name}", groupId = "${consumer.groupid.name}")
public void consumeRental(ConsumerRecord<String, String> record) throws Exception {
    EventResult eventResult = objectMapper.readValue(record.value(), EventResult.class);

// ...
{
	"eventType": "RENT",
	"idName": {
		"id": "jenny",
		"name": "제니"
	},
	"item": {
		"no": 1,
		"title": "누구를 위하여 종을 울리나?"
	},
	"point": 10,
	"success": true
}

단일 진실 공급원(SSOT; Single Source Of Truth)
Docker Desktop
MongoDB Compass