본문 바로가기
Dart/Dart Server

[고급] Dart 서버 마이크로서비스 아키텍처 / gRPC와 같은 서비스 간 이벤트 전달 및 메시지 큐 활용 (RabbitMQ, Kafka 등)

by Maccrey Coding 2024. 9. 14.
728x90
반응형

 

마이크로서비스 아키텍처에서는 서비스 간의 통신을 효율적으로 처리하기 위해 다양한 기술을 사용할 수 있습니다.

gRPC는 서비스 간의 직접적인 호출을 지원하며, 메시지 큐(예: RabbitMQ, Kafka)는 비동기적인 이벤트 전달을 지원합니다.

이 블로그에서는 gRPC메시지 큐를 함께 활용하여 서비스 간의 이벤트를 전달하는 방법을 초보자도 쉽게 이해할 수 있도록 설명하겠습니다.

1. gRPC와 메시지 큐의 차이점

gRPC메시지 큐는 각각 서비스 간 통신을 처리하는 방법이지만, 사용하는 상황에 따라 적합한 기술이 다릅니다.

  • gRPC
    • 용도: 서비스 간의 직접적인 호출 및 응답
    • 장점: 실시간 통신, 요청-응답 패턴, 스트리밍 지원
    • 단점: 동기적인 통신, 서버와 클라이언트 간의 직접적인 연결 필요
  • 메시지 큐
    • 용도: 비동기적인 이벤트 전달, 서비스 간의 느슨한 결합
    • 장점: 비동기 통신, 높은 확장성, 서비스 간의 결합도 감소
    • 단점: 메시지 큐 시스템의 복잡성, 지연 발생 가능성

2. Dart에서 gRPC와 메시지 큐 사용하기

이번 섹션에서는 Dart에서 gRPCRabbitMQ를 활용하여 서비스 간의 이벤트를 전달하는 방법을 설명합니다.

RabbitMQ는 오픈 소스 메시지 브로커로, 신뢰성 있는 메시지 전달을 제공합니다.

2.1 RabbitMQ 설치 및 설정

1. RabbitMQ 설치

RabbitMQ는 여러 플랫폼에서 설치할 수 있으며, RabbitMQ 공식 문서에서 설치 방법을 확인할 수 있습니다.

2. RabbitMQ 서버 시작

설치 후, RabbitMQ 서버를 시작합니다. 일반적으로 RabbitMQ는 기본적으로 localhost:5672에서 실행됩니다.

2.2 Dart에서 RabbitMQ 사용하기

1. pubspec.yaml 설정

RabbitMQ와 통신하기 위해 amqp_client 패키지를 추가합니다.

dependencies:
  grpc: ^3.0.0
  protobuf: ^2.0.0
  amqp_client: ^1.0.0

 

2. 메시지 발행 및 구독 코드 작성

발행 코드 (lib/publisher.dart)

import 'package:amqp_client/amqp_client.dart';

Future<void> main() async {
  // RabbitMQ 서버에 연결
  final connection = await AMQPConnection.connect('amqp://guest:guest@localhost:5672');
  final channel = await connection.channel();

  // 큐 생성
  final queue = await channel.queue('my_queue');

  // 메시지 발행
  final message = '안녕하세요, RabbitMQ!';
  await queue.publish(message);
  print('메시지가 큐에 발행되었습니다: $message');

  // 연결 종료
  await connection.close();
}

구독 코드 (lib/consumer.dart)

import 'package:amqp_client/amqp_client.dart';

Future<void> main() async {
  // RabbitMQ 서버에 연결
  final connection = await AMQPConnection.connect('amqp://guest:guest@localhost:5672');
  final channel = await connection.channel();

  // 큐 생성
  final queue = await channel.queue('my_queue');

  // 메시지 수신 및 처리
  await for (final message in queue.consume()) {
    print('큐에서 받은 메시지: ${message.payloadAsString}');
    message.ack();  // 메시지 처리 완료
  }
}

 

  • 발행 코드 (lib/publisher.dart)
    • AMQPConnection.connect('amqp://guest:guest@localhost:5672'): RabbitMQ 서버에 연결합니다.
    • channel.queue('my_queue'): 큐를 생성하거나 가져옵니다.
    • queue.publish(message): 큐에 메시지를 발행합니다.
    • await connection.close(): 연결을 종료합니다.
  • 구독 코드 (lib/consumer.dart)
    • AMQPConnection.connect('amqp://guest:guest@localhost:5672'): RabbitMQ 서버에 연결합니다.
    • channel.queue('my_queue'): 큐를 생성하거나 가져옵니다.
    • await for (final message in queue.consume()): 큐에서 메시지를 수신합니다.
    • message.ack(): 메시지 처리가 완료되었음을 RabbitMQ에 알립니다.

3. gRPC와 메시지 큐를 결합한 예제

서비스 A는 gRPC를 통해 클라이언트의 요청을 받고, 서비스 B는 RabbitMQ를 통해 비동기적으로 작업을 처리한다고 가정해 봅시다.

3.1 서비스 A (gRPC 서버)

lib/service_a.dart

import 'package:grpc/grpc.dart';
import 'generated/helloworld.pbgrpc.dart';
import 'package:amqp_client/amqp_client.dart';

class GreeterService extends GreeterServiceBase {
  @override
  Future<HelloReply> sayHello(ServiceCall call, HelloRequest request) async {
    // RabbitMQ 서버에 연결
    final connection = await AMQPConnection.connect('amqp://guest:guest@localhost:5672');
    final channel = await connection.channel();
    final queue = await channel.queue('my_queue');

    // 메시지 발행
    final message = '클라이언트 요청: ${request.name}';
    await queue.publish(message);
    print('메시지가 큐에 발행되었습니다: $message');

    // 응답 생성
    final reply = HelloReply()..message = '안녕하세요, ${request.name}!';
    await connection.close();
    return reply;
  }
}

Future<void> main() async {
  final server = Server([GreeterService()]);
  await server.serve(port: 50051);
  print('gRPC 서버가 실행 중입니다. 포트: ${server.port}');
}

3.2 서비스 B (메시지 큐 구독)

lib/service_b.dart

import 'package:amqp_client/amqp_client.dart';

Future<void> main() async {
  // RabbitMQ 서버에 연결
  final connection = await AMQPConnection.connect('amqp://guest:guest@localhost:5672');
  final channel = await connection.channel();
  final queue = await channel.queue('my_queue');

  // 메시지 수신 및 처리
  await for (final message in queue.consume()) {
    print('큐에서 받은 메시지: ${message.payloadAsString}');
    message.ack();  // 메시지 처리 완료
  }
}

 

  • 서비스 A (lib/service_a.dart)
    • gRPC 서버가 클라이언트의 요청을 받고, RabbitMQ에 메시지를 발행합니다. 이 메시지는 비동기적으로 처리되어 서비스 B에서 수신됩니다.

    • 클라이언트 요청에 대한 응답을 생성하고, RabbitMQ 연결을 종료합니다.
  • 서비스 B (lib/service_b.dart)
    • RabbitMQ에서 메시지를 수신하고 처리합니다. 이 메시지는 서비스 A가 발행한 것입니다.

gRPC메시지 큐(예: RabbitMQ)를 결합하면, 마이크로서비스 아키텍처에서의 통신을 보다 유연하고 효율적으로 처리할 수 있습니다.

gRPC는 실시간 통신을 지원하며, RabbitMQ는 비동기적으로 이벤트를 전달할 수 있게 합니다. 이러한 기술들은 각각의 장점을 살리며, 복잡한 시스템을 구성하는 데 도움을 줍니다.

 

이 블로그에서 소개한 gRPC와 메시지 큐를 활용한 서비스 간 이벤트 전달 방법을 통해, Dart로 효과적인 마이크로서비스 아키텍처를 구축해 보세요.

 

구독!! 공감과 댓글은 저에게 큰 힘이 됩니다.

Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

 

 

728x90
반응형