반응형

MSA에서 서비스 통신 방법: 동기, 비동기, 그리고 그 너머

안녕하세요! 오늘은 마이크로서비스 아키텍처(MSA)에서 서비스 간 통신을 구현하는 다양한 방법을 살펴보고, 각각의 장단점을 정리해보려고 합니다. MSA에서는 서비스가 독립적으로 동작하기 때문에 통신 방식이 성능, 유연성, 유지보수성에 큰 영향을 미치죠. 이번 글에서는 동기 방식(HTTP/OpenFeign), 비동기 방식(메시지큐/Kafka), 그리고 제로 페이로드, GraphQL, gRPC까지 다뤄보겠습니다. 그럼 시작해볼까요?

1. 동기 통신: HTTP (OpenFeign)

설명:
HTTP는 MSA에서 가장 널리 사용되는 동기 통신 방식입니다. RESTful API를 통해 서비스 간 요청과 응답을 주고받죠. Spring Boot에서는 OpenFeign 같은 선언적 HTTP 클라이언트를 사용하면 코드가 간결해지고 외부 API 호출이 쉬워집니다. 예를 들어, 주문 서비스가 상품 서비스에 "재고 확인" 요청을 보내고 즉시 응답을 받는 식이에요.

장점:

  • 직관적: 요청과 응답이 바로 이어져 로직이 단순하고 이해하기 쉬움.
  • 즉시성: 결과를 실시간으로 받아야 하는 경우 적합 (예: 결제 처리).
  • 생태계: REST API는 표준화되어 있어 도구와 라이브러리가 풍부함.

단점:

  • 강한 결합: 호출하는 서비스가 응답을 기다려야 하므로 의존성이 강해질 수 있음.
  • 지연: 응답이 느리거나 호출받는 서비스가 다운되면 전체 흐름이 멈춤.
  • 확장성 한계: 트래픽이 많아지면 동기 호출이 병목현상을 일으킬 가능성 있음.

2. 비동기 통신: 메시지큐 (Kafka)

설명:
비동기 통신은 메시지큐를 통해 서비스 간 데이터를 전달합니다. Apache Kafka는 대표적인 메시지 브로커로, 프로듀서가 토픽에 메시지를 보내고 컨슈머가 이를 비동기적으로 처리하죠. 예를 들어, 주문 서비스가 "주문 생성" 이벤트를 Kafka에 보내고, 배송 서비스가 나중에 이를 받아 처리하는 방식입니다.

장점:

  • 느슨한 결합: 서비스가 서로 직접 호출하지 않아 독립성이 높아짐.
  • 확장성: 높은 처리량과 대규모 이벤트 처리가 가능 (Kafka의 강점!).
  • 장애 내성: 한 서비스가 실패해도 메시지가 큐에 남아 있어 복구 후 처리 가능.

단점:

  • 복잡성: 메시지 브로커 설정, 토픽 관리 등 추가 인프라가 필요.
  • 지연 가능성: 실시간 응답이 필요한 경우 부적합.
  • 추적 어려움: 메시지 흐름이 분산되어 디버깅이 까다로울 수 있음.

3. 제로 페이로드 (Zero Payload)

설명:
제로 페이로드는 데이터 자체를 주고받지 않고, 참조(예: ID나 URL)만 전달하는 방식입니다. 수신 서비스가 필요한 데이터를 직접 조회하죠. 예를 들어, 주문 서비스가 "상품 ID"만 보내고, 재고 서비스가 DB에서 해당 데이터를 가져오는 식이에요.

장점:

  • 경량화: 네트워크 부하가 줄어 빠른 통신 가능.
  • 유연성: 수신 측에서 필요한 데이터만 조회해 처리 가능.
  • 단순성: 페이로드 구조를 신경 쓸 필요 없음.

단점:

  • 추가 요청: 데이터를 조회하려면 별도 호출이 필요해 지연 발생 가능.
  • 의존성: 수신 서비스가 데이터 소스에 접근할 수 있어야 함.
  • 일관성 문제: 참조 데이터가 변경되면 불일치 위험이 있음.

4. GraphQL

설명:
GraphQL은 클라이언트가 필요한 데이터만 요청할 수 있는 쿼리 언어 기반 API입니다. MSA에서는 여러 서비스의 데이터를 하나의 GraphQL 엔드포인트로 통합해 제공하거나, 서비스 간 통신에 사용할 수 있어요. 예를 들어, 주문 서비스가 상품과 사용자 데이터를 한 번에 요청할 수 있죠.

장점:

  • 효율성: 필요한 데이터만 받아 과다/과소 페칭 문제를 해결.
  • 유연성: 클라이언트가 요청 형식을 자유롭게 정의 가능.
  • 단일 엔드포인트: 여러 서비스 호출을 하나로 통합 가능.

단점:

  • 복잡성: 서버 측에서 스키마 정의와 리졸버 구현이 필요.
  • 캐싱 어려움: HTTP GET 기반 REST에 비해 캐싱이 까다로움.
  • 오버헤드: 쿼리 파싱과 실행에 추가 리소스 소요.

5. gRPC

설명:
gRPC는 Google에서 개발한 고성능 RPC(Remote Procedure Call) 프레임워크로, HTTP/2와 Protocol Buffers(Protobuf)를 사용합니다. MSA에서 서비스 간 빠르고 효율적인 통신을 위해 사용되죠. 예를 들어, 주문 서비스가 재고 서비스의 함수를 직접 호출하듯 사용할 수 있습니다.

장점:

  • 고성능: 이진 데이터(Protobuf)와 HTTP/2로 속도가 빠름.
  • 타입 안정성: Protobuf로 인터페이스 정의 시 컴파일 타임에 오류 체크 가능.
  • 스트리밍 지원: 양방향 스트리밍으로 실시간 통신 가능.

단점:

  • 학습 곡선: Protobuf와 gRPC 설정이 처음에는 낯설 수 있음.
  • 호환성: REST에 비해 브라우저 지원이 제한적.
  • 복잡성: 설정과 디버깅이 HTTP보다 까다로울 수 있음.

어떤 방식을 선택할까?

  • 실시간 응답 필요: HTTP(OpenFeign) 또는 gRPC.
  • 대규모 이벤트 처리: Kafka.
  • 최소 데이터 전송: 제로 페이로드.
  • 클라이언트 유연성: GraphQL.
  • 최고 성능: gRPC.

각 방법은 사용 사례와 요구사항에 따라 빛을 발합니다. 예를 들어, 결제처럼 즉시 응답이 필요한 경우는 OpenFeign, 주문 이벤트 전파처럼 비동기 처리가 적합한 경우는 Kafka를 선택하면 좋겠죠. 여러 방식을 조합해 사용하는 것도 좋은 전략이에요!

마무리

MSA에서 서비스 통신은 시스템의 성공을 좌우하는 핵심 요소입니다. 이번 글에서 다룬 다섯 가지 방법의 장단점을 이해하고, 프로젝트에 맞는 방식을 골라보세요.

반응형
반응형

Kafka와 Spring Boot로 메시지 보내고 받기

안녕하세요! 오늘은 분산 메시징 시스템인 Apache Kafka를 Spring Boot와 함께 사용해 메시지를 보내고 받는 방법을 알아보려고 합니다. Kafka는 대규모 데이터 처리나 실시간 스트리밍에 강력한 도구인데요, Spring Boot와 통합하면 설정도 간단하고 코드도 깔끔해집니다. 바로 시작해볼까요?

Kafka란?

Kafka는 LinkedIn에서 개발된 오픈소스 메시징 시스템으로, 높은 처리량과 확장성을 자랑합니다. **프로듀서(Producer)**가 메시지를 보내고, **컨슈머(Consumer)**가 이를 받아 처리하는 방식으로 동작하죠. 메시지는 **토픽(Topic)**이라는 카테고리에 저장되며, 필요에 따라 여러 컨슈머가 동일한 토픽을 구독할 수 있습니다.

이제 Spring Boot에서 Kafka를 활용하는 방법을 단계별로 살펴보겠습니다.

Spring Boot에서 Kafka 사용하기

Kafka를 사용하려면 먼저 Kafka 브로커가 실행 중이어야 합니다. 로컬에서 테스트하려면 Kafka 공식 사이트에서 다운로드해 실행하거나, Docker를 사용하는 것도 추천드려요. 여기서는 기본 설정을 기준으로 진행하겠습니다.

<카프카 실행 실습>

1. 의존성 추가

pom.xml에 Spring Kafka 의존성을 추가합니다.

 
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

 

Spring Boot 버전에 따라 자동으로 적합한 Kafka 클라이언트가 포함되니, 별도로 버전을 명시하지 않아도 됩니다.

2. Kafka 설정 (application.yml)

Kafka 브로커와 연결 설정을 application.yml에 추가합니다.

spring:
  kafka:
    bootstrap-servers: localhost:9092  # Kafka 브로커 주소
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    consumer:
      group-id: my-group  # 컨슈머 그룹 ID
      auto-offset-reset: earliest  # 처음부터 메시지 읽기
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
  • bootstrap-servers: Kafka 브로커가 실행 중인 주소.
  • serializers/deserializers: 메시지의 키와 값을 문자열로 직렬화/역직렬화.
3. 메시지 보내기 (Producer)

Spring Kafka는 KafkaTemplate을 제공해 메시지 전송을 쉽게 처리할 수 있습니다. 토픽에 메시지를 보내는 서비스를 만들어보죠.

import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@Service
public class KafkaProducerService {

    private static final String TOPIC = "my-topic";
    private final KafkaTemplate<String, String> kafkaTemplate;

    public KafkaProducerService(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void sendMessage(String message) {
        kafkaTemplate.send(TOPIC, message);
        System.out.println("Message sent: " + message);
    }
}
  • KafkaTemplate: Spring이 자동으로 주입해주는 템플릿.
  • send: 토픽 이름과 메시지를 인자로 전달해 전송.
4. 컨트롤러에서 Producer 호출

간단한 REST 엔드포인트를 만들어 메시지를 보내보겠습니다.

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class KafkaController {

    private final KafkaProducerService producerService;

    public KafkaController(KafkaProducerService producerService) {
        this.producerService = producerService;
    }

    @PostMapping("/send")
    public String sendMessage(@RequestParam String message) {
        producerService.sendMessage(message);
        return "Message sent to Kafka: " + message;
    }
}

 

5. 메시지 받기 (Consumer)

이제 토픽에서 메시지를 받아오는 컨슈머를 작성합니다. @KafkaListener 어노테이션을 사용하면 매우 간단하죠.

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class KafkaConsumerService {

    @KafkaListener(topics = "my-topic", groupId = "my-group")
    public void listen(String message) {
        System.out.println("Received message: " + message);
    }
}
  • @KafkaListener: 지정한 토픽의 메시지를 감지해 메서드를 실행.
  • groupId: 컨슈머 그룹을 식별. 같은 그룹 내 컨슈머는 메시지를 나누어 처리.
6. 실행 및 테스트
  1. Kafka 브로커를 실행합니다 (예: bin/kafka-server-start.sh config/server.properties).
  2. Spring Boot 애플리케이션을 실행합니다.
  3. Postman이나 curlPOST http://localhost:8080/send?message=Hello Kafka! 요청을 보냅니다.

그러면 콘솔에서:

  • Producer: "Message sent: Hello Kafka!"
  • Consumer: "Received message: Hello Kafka!"

이렇게 출력되는 걸 확인할 수 있습니다!

추가 팁: JSON 메시지 처리

문자열 대신 JSON 객체를 주고받고 싶다면, JsonSerializerJsonDeserializer를 사용하세요. 의존성에 jackson-databind를 추가하고 설정을 변경하면 됩니다.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

 

application.yml 수정:

spring:
  kafka:
    producer:
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
    consumer:
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring.json.trusted.packages: "*"  # 역직렬화 시 신뢰할 패키지

 

그리고 DTO 클래스를 만들어 사용하면 됩니다 (예: Message 클래스).

마무리

Spring Boot와 Kafka를 함께 사용하면 메시지 기반 시스템을 정말 쉽게 구축할 수 있습니다. 이번 예제는 기본적인 Producer와 Consumer 설정을 다뤘는데요, 토픽 파티션 관리나 에러 처리 등 더 깊은 주제도 탐구해보시면 좋을 거예요. Kafka의 세계에 입문해보고 싶었다면, 지금이 시작할 완벽한 타이밍입니다!

반응형
반응형

1. 리눅스 서버 3대 준비

- 메시지를 보낼 서버

- kafka, zookeepr 서버

- 메시지를 받을 서버

2. 세개 서버에 모두 kafka 다운로드 및 압축 풀기

- apache kafka download 검색 후 다운로드 주소 복사

- 서버에서 다운로드 및 압축 해제

wget https://dlcdn.apache.org/kafka/3.9.0/kafka_2.13-3.9.0.tgz
tar zxvf kafka_2.13-3.9.0.tgz

 

3. kafka는 java 기반 프레임 워크로 모든 서버에 java 다운로드

apt update
apt install openjdk-17-jdk

 

4. kafka 서버에 zookeeper & kafka 실행

- bin 폴더로 이동하여 zookeeper 실행

./zookeeper-server-start.sh ../config/zookeeper.properties

- config 폴더 이동하여 kafka 설정 변경

주석 처리된 listerners, advertised 주석 해제 및 advertised의 ip주소 kafka 서버로 변경

 

- bin 폴더 이동하여 kafka 실행

./kafka-server-start.sh ../config/server.properties

 

5. 메시지를 보낼 서버에서 producer 실행

- bin 폴더 이동하여 실행

./kafka-console-producer.sh --broker-list [kafka server ip]:9092 --topic abc

 

6. 메시지를 받을 서버에서 consumer 실행

- bin 폴더 이동하여 실행

./kafka-console-consumer.sh --bootstrap-server [kafka server ip]:9092 --topic abc

 

7. 메시지를 보낼 서버에서 메시지 입력 후 메시지를 받는 서버에서 메시지가 오는지 확인

메시지 전송
메시지 받기

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Log] Log 중앙화  (0) 2025.02.21
[Trace] 핀포인트(Pinpoint)  (0) 2025.02.21
[Spring] 환경 변수 설정  (0) 2025.02.15
[Spring] @Component와 @Bean의 차이점  (0) 2025.02.15
[Spring] Stream  (0) 2025.02.15

+ Recent posts