[Project] kafka+SSE 알림 기능 구현- 1 : kafka setting

Updated:

Categories:

Tags: ,

📌 개인적인 공간으로 공부를 기록하고 복습하기 위해 사용하는 블로그입니다.
정확하지 않은 정보가 있을 수 있으니 참고바랍니다 :😸
[틀린 내용은 댓글로 남겨주시면 복받으실거에요]

kafka+SSE 알림 기능 구현- 1

msa구조라서 알림기능을 각각의 프로젝트로 들어가서 구현할 지

아니면 알림을 따로 빼야하는지가 고민이었는데 일단 동일 코드를 여러번 치는 것 보다는

kafka를 통해서 느슨한 결합으로 알림을 구현하고자 kafka를 사용하기로 했다.

카프카란?

실시간으로 기록 스트림을 게시, 구독, 저장 및 처리할 수 있는 분산형 데이터 스트리밍 플랫폼이다.

즉, API로 데이터를 바로 요청을 하는 것이 아닌 미들웨어인 카프카를 둬서 프로듀서가 메시지를 생산해서 토픽으로 메시지를 보내고, 컨슈머는 토픽의 메시지를 가져와 사용하는 애플리케이션 부분이다.

따라서 연결되어 있는 토픽에 메시지(큐)가 들어오면 컨슈머는 그 메시지를 받을 수 있는 것이다.

장점)

  1. 대량의 데이터를 처리 가능하고, 시스템 부하에 따라 확장이 가능하다.

  2. 카프카는 실시간 데이터 처리를 위해 설계되었다. 데이터가 전송되는 즉시 프로듀서와 컨슈머가 데이터를 처리할 수 있고, 데이터의 지연 시간이 최소화되기 때문에 실시간 데이터 스트리밍이 가능하다.

  3. 카프카는 메시지를 영속적으로 저장하기 때문에 나중에 다시 데이터를 재처리할 수 있다.

윈도우 환경을 쓰면 그냥 실행했을 때 오류가 발생한다는 글을 참고하여 도커를 사용하기로 결정했다.

환경설정

Kafka와 Zookeeper 설정 : kafka-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: '3'
services:
  zookeeper:
    image: wurstmeister/zookeeper:latest
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka:
    image: wurstmeister/kafka:latest
    ports:
      - "9092:9092"
    expose:
      - "9093"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
  • yaml이 있는 directory 가서 터미널 열기

    1
    2
    3
    
      PS C:\Project\alarm\alarm-api\src\main\resources> 
        
      docker-compose -f kafka-compose.yml up -d
    
  • 그럼 docker container에 kafka와 zookeeper 가 올라간다.

  • docker desktop에서 확인

  • 혹은 터미널에서 확인하고 싶을 때는 docker ps 라고 명령어 치면 아래와 같이 확인할 수 있다.

    1
    
      docker ps
    

application.yml에서 kafka설정

1
2
3
4
5
6
7
8
9
10
11
spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: my-group
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer

build.gradle

1
2
3
4
	// Kafka
	implementation 'org.apache.kafka:kafka-streams'
	implementation 'org.springframework.kafka:spring-kafka'
	testImplementation 'org.springframework.kafka:spring-kafka-test'

Spring 에서 적용

MSA 구조라서 어떻게 구현할까에 대해서 고민을 많이했다.

만약에 하나의 프로젝트에서 운영된다면 고민을 안 했을텐데 독립된 서비스라서 의존을 끊어낸 다음 각각 구현할지 아니면 의존관계를 가질지에 대해서 생각했다.

첫 번째는 알림 서비스를 따로 구현한 다음 각각 서비스에서 producer를 생성할지.

두 번째는 각각의 서비스에서 producer와 consumer를 사용할 것인지

그리고 세 번째로는 chat과 mail처럼 알림이 중요한 곳에서만 producer와 consumer 를 설정하고

그 외의 calendar와 전자 결재, 그리고 자원 예약, 공지사항에 대한 알림만 통합해서 관리할 지에 대해서 생각해봤는데…. 일단 전자결재/게시판/일정/예약이 먼저 구현될 것 같아서 그것들에 대해선 통합해서 관리하기로 했다.

동작원리

  1. Producer가 메시지 발행
    • 전자 결재 서비스 같은 각 독립된 서비스는 특정 이벤트가 발생할 때마다 Kafka의 특정 토픽에 메시지를 보낸다.
    • 이 메시지는 알림의 내용과 관련된 데이터가 담겨있어.
  2. Kafka가 메시지 저장 및 관리
    • Kafka는 발행된 메시지를 지정된 토픽에 저장하고 관리한다.
    • 각 토픽은 여러 파티션으로 나뉘어 있어 메시지의 효율적인 저장과 처리가 가능하다.
  3. Consumer가 메시지 구독
    • 알림 서비스는 Kafka의 특정 토픽을 구독하고 있는 Consumer 그룹에 속해 있다
    • 새로운 메시지가 토픽에 추가되면, 알림 서비스의 Consumer가 이를 받아 처리하게 된다.
  4. 알림 처리 및 전송
    • Consumer는 받은 메시지를 기반으로 실제 알림을 생성하고, 이를 사용자에게 전송한다.
    • 예를 들어, 이메일이나 푸시 알림을 통해 사용자가 실시간으로 알림을 받을 수 있게 된다.

이러한 흐름 덕분에 각 서비스는 서로 직접적으로 연결되지 않고, Kafka를 통해 느슨하게 결합되어 있어 시스템의 확장성과 유지보수가 용이해진다.

메세지 전달은 어떻게 할 것인지 : SSE(Server Send Event)

SSE는 클라이언트와 서버 간의 단방향 통신을 하게 해주는 기술인데 알림을 실시간으로 사용자에게 전달하기에 적합하다.

예전에 솔로프로젝트로 게시판 만들 때 알림기능은 어떻게 구현할 수 있지? 하고 찾아서 정리했었는데 : https://quokkavely.github.io/project/SSE/

그때도 SSE로 하면 되겠네 하고 정리만 해뒀었는데… 마지막 프로젝트까지 와서야 구현하게 되었다.

SSE

  1. 장점
    • 단순한 구현 SSE는 단방향 통신이기 때문에 간단한 편에 속하고 서버에서 클라이언트로 데이터를 보내는 데 특화되어 있어서 설정과 관리가 쉽다.
    • 자동 재연결 클라이언트가 서버와의 연결이 끊어지면, SSE는 자동으로 재연결을 시도하고 별도의 재연결 로직을 구현할 필요가 없어 안정적인 실시간 통신을 제공
    • HTTP 기반 SSE는 HTTP/1.1을 기반으로 작동하기 때문에 기존의 HTTP 인프라(프록시, 로드 밸런서 등)와 호환성이 좋아. 별도의 프로토콜을 사용하지 않아서 설정이 간편하다.
    • 브라우저 호환성 대부분의 최신 웹 브라우저에서 SSE를 지원한다. 특히 Chrome, Firefox, Safari 등에서 잘 동작하며, 특정 구형 브라우저를 제외하면 호환성 문제가 크게 없다.
    • 효율적인 리소스 사용 서버에서 클라이언트로 데이터를 푸시할 때, 필요한 데이터만 전송하기 때문에 네트워크 사용량이 적고, 클라이언트의 리소스를 효율적으로 사용할 수 있다.
  2. 단점
    • 단방향 통신 SSE는 서버에서 클라이언트로만 데이터를 보내는 단방향 통신 방식이기 때문에 클라이언트에서 서버로 데이터를 보내려면 별도의 요청을 사용해야 한다.
    • 브라우저 지원 제한 일부 구형 브라우저나 특정 모바일 브라우저에서는 SSE를 완벽하게 지원하지 않을 수 있다. 특히 Internet Explorer에서는 SSE 지원이 제한적이야.
    • 스케일링의 한계 대규모 트래픽을 처리할 때, 지속적인 HTTP 연결을 유지해야 하기 때문에 서버의 리소스가 많이 소모될 수 있다.
    • 보안 이슈 SSE는 기본적으로 인증과 암호화를 지원하지 않기 때문에, HTTPS를 사용하지 않으면 데이터가 노출될 위험이 있다.
    • 프로토콜 제한: SSE는 HTTP/2와 완벽하게 호환되지 않을 수 있다. HTTP/2에서는 다중화 기능을 제공하지만, SSE는 이 기능을 충분히 활용하지 못할 수 있다.

SSE vs WebSocket

그릅웨어 기능 중에 메신저 기능은 웹소켓을 사용했는데 알림도 웹소켓을 사용할 수 있을 것 같아서 찾아보고 차이점 정리해봤다.

  • SSE:
    • 단방향 통신: 서버 -> 클라이언트
    • 간단한 구현: 설정이 쉬움
    • HTTP 기반: 기존 인프라와 호환성 좋음
    • 자동 재연결: 내장된 재연결 기능 제공
  • WebSocket:
    • 양방향 통신: 서버 <-> 클라이언트
    • 복잡한 구현: 설정과 관리가 다소 복잡함
    • 전용 프로토콜: 기존 HTTP 인프라와 일부 호환성 문제 발생 가능
    • 유연성: 다양한 실시간 애플리케이션에 적합

주로 SSE는 실시간 알림/ 뉴스업데이트 / 라이브 피드 같은 곳에서 사용되고 WebSocket은 실시간 채팅, 게임 등에서 사용된다고 한답…

일단 setting 까지하고 내일은 consumer랑 producer 구현할 예정이다.🦾🦾

참고자료







Project 카테고리 내 다른 글 보러가기

Leave a comment