홈으로 돌아가기

Kafka와 Flink를 사용한 스트리밍 데이터 처리: 아키텍처

Apache Kafka, Flink, S3를 사용한 스트리밍 데이터 처리 시스템 구축에 대한 기사. 통합 단계, 구성 예제 및 프로덕션 환경을 위한 모범 사례를 상세히 다룹니다.

LEGO 조립기처럼 스트리밍 시스템 구축: 실전 가이드
Advertisement 728x90

스트림 처리: 레고 블록 같은 아키텍처

현대 데이터 처리 시스템은 유연성과 확장성을 요구합니다. 이 글에서는 Kafka, Flink, S3 등의 컴포넌트를 모듈러 아키텍처 원칙을 활용해 통합 스트리밍 플랫폼으로 결합하는 방법을 자세히 살펴보겠습니다. 데이터 생성부터 실시간 분석까지의 통합 단계를 상세히 다루겠습니다.

시스템 기반: 스트리밍 플랫폼

스트림 처리를 구축하기 위해 검증된 기술 스택을 사용합니다. 중심 컴포넌트는 Apache Kafka로, 신뢰할 수 있는 메시지 전달을 보장하는 분산 스트리밍 플랫폼입니다. 함께 사용하는 것은:

  • 외부 시스템 통합을 위한 Kafka Connect
  • 데이터 스키마 관리를 위한 Schema Registry
  • 시각적 관리 인터페이스로 Kafka UI

핵심 아이디어는 컴포넌트를 레고 블록처럼 취급하는 것입니다. 각 컴포넌트는 특정 기능을 담당하고 잘 정의된 인터페이스를 통해 서로 연결됩니다. 최소 설정을 시작하려면 Docker Compose와 Git LFS만 있으면 됩니다. 시스템은 멀티스테이지 빌드를 통해 조립되어 재현 가능한 환경을 보장합니다.

Google AdInline article slot

기본 docker-compose.yml 구성 예시:

services:
  kafka:
    image: confluentinc/cp-kafka:8.1.0
    environment:
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092

  schema-registry:
    image: confluentinc/cp-schema-registry:8.1.0
    environment:
      SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: kafka:9092

전통 데이터베이스와 스트리밍 시스템의 차이를 이해하는 것이 중요합니다. 관계형 DBMS에서는 상태(테이블, 레코드)에 초점이 맞춰져 있지만, 스트림 처리에서는 이벤트에 초점이 맞춰집니다. Kafka의 각 메시지는 로그 끝에 추가되는 불변 이벤트입니다. 이 접근법은 전달 보장과 상태 복구를 가진 시스템을 가능하게 합니다.

데이터 통합 단계

시스템 구축 과정을 네 개의 논리적 단계로 나눕니다:

Google AdInline article slot
  • Ingest — 외부 소스에서 데이터 수신
  • Storage — 영속 저장
  • Transform — 변환 및 강화
  • Serve — 결과 제공

Ingest: 데이터 생성 및 수집

Ingest 단계에서 Kafka Connect를 통해 데이터 소스를 구성합니다. 데모를 위해 온도 센서 판독값 생성기를 구현하겠습니다. Java 커넥터는 시간대와 적도 상대 위치를 고려해 지리적 좌표와 온도를 포함한 합성 데이터를 생성합니다.

커넥터 구성:

{
  "connector.class": "dev.miron.connect.temp.TempSourceConnector",
  "tasks.max": "1",
  "topic": "earth-temp",
  "sensors": "5",
  "messages.per.sensor.per.second": "1"
}

Avro를 사용한 직렬화를 주목하세요. 메시지는 바이너리 형식으로 저장되어 트래픽 양을 줄이고 처리 속도를 높입니다. Schema Registry는 스키마 버전 관리와 호환성 검사(BACKWARD 모드)를 처리합니다. 데이터 구조가 변경되면 시스템이 자동으로 유효하지 않은 업데이트를 거부합니다.

Google AdInline article slot

Storage: 장기 저장

영속 저장을 위해 S3와 Apache Iceberg의 조합을 사용합니다. S3는 객체 저장으로 사용되며, Iceberg은 ACID 트랜잭션과 시간 여행을 가능하게 하는 메타데이터 레이어를 추가합니다. 이 접근법은 대규모 데이터셋을 효율적으로 처리하며 전통 파일 시스템의 문제를 피합니다.

싱크 커넥터 구성:

{
  "connector.class": "io.confluent.connect.s3.S3SinkConnector",
  "topics": "earth-temp",
  "s3.bucket.name": "data-lake",
  "storage.class": "io.confluent.connect.s3.storage.S3Storage",
  "format.class": "io.confluent.connect.s3.format.avro.AvroFormat"
}

데이터 쿼리를 위해 Trino를 사용합니다. 여러 소스의 데이터를 연합할 수 있는 분산 SQL 엔진입니다. 이를 통해 데이터를 이동하지 않고 복잡한 분석 쿼리를 수행할 수 있습니다.

데이터 변환

Transform 단계를 Apache Flink로 구현합니다. 윈도우와 상태ful 연산을 지원하는 스트림 처리 엔진입니다. 예제 작업: 화씨를 섭씨로 변환하고 이상 값을 필터링합니다.

DataStream<TempEvent> processed = source
  .map(event -> {
    event.setCelsius((event.getFahrenheit() - 32) * 5/9);
    return event;
  })
  .filter(event -> event.getCelsius() > -50 && event.getCelsius() < 60);

Flink는 네이티브 커넥터를 통해 Kafka와 통합됩니다. exactly-once 처리 보장을 위해 체크포인팅을 적절히 구성하는 것이 중요합니다. 주요 파라미터:

  • execution.checkpointing.interval: 60000
  • state.backend: rocksdb
  • state.checkpoints.dir: file:///checkpoints

모니터링을 위해 Flink의 내장 웹 인터페이스를 사용해 처리 지연(lag)과 연산자 상태를 추적합니다.

서비스 레이어

마지막 단계에서 데이터가 소비자에게 제공됩니다. 두 가지 옵션을 구현합니다:

  • 운영 쿼리를 위한 JDBC 커넥터를 통한 PostgreSQL
  • 핫 데이터 캐싱을 위한 Redis

PostgreSQL 싱크 구성:

{
  "connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector",
  "connection.url": "jdbc:postgresql://postgres:5432/analytics",
  "topics": "processed-temp",
  "auto.create": "true",
  "insert.mode": "upsert",
  "pk.fields": "sensorId,timestamp"
}

Redis의 경우, 각 센서의 최신 판독값을 해시 테이블에 저장하는 커스텀 커넥터를 사용합니다. 이를 통해 현재 데이터 쿼리에 밀리초 지연을 제공합니다.

주요 요점

  • 데이터 스키마는 BACKWARD 호환성을 가진 Schema Registry를 통해 관리해야 합니다
  • Flink의 상태ful 처리는 체크포인팅 설정과 상태 백엔드 선택이 필요합니다
  • Ingest/Storage/Transform/Serve 단계로의 시스템 분해는 디버깅을 단순화합니다
  • 바이너리 직렬화(Avro/Protobuf)는 스트리밍 시스템 성능에 중요합니다
  • Docker Compose를 통한 설정 테스트는 빠른 반복을 가능하게 합니다

— Editorial Team

Advertisement 728x90

다음 읽기