MicroService Design Pattern ‐ Service Communications Patterns - woojin-playground/Backend-PlayGround GitHub Wiki

MicroService Design Pattern - Service Communications Patterns

동기화 통신 방법

  1. Request/Response Communication
스크린샷 2026-03-27 오후 9 19 58
  • HTTP, REST : 동기식 요청/응답 방식, 마이크로서비스 API
  • Restful API : HTTP Protocol + Method, GET/POST/PUT/DELETE/PATCH
  • gRPC : 내부 마이크로서비스 간 통신이 잦을 때, 고성능 + 낮은 지연 시간
  • GraphQL : 요청 시 사용하는 쿼리에 따라 다른 응답, HTTP 요청 회수 및 응답 사이즈 줄임, 필요한 데이터 구조를 정의할 수 있어 유연성과 효율성을 확보할 수 있다.
  1. Push/Pull Communication
스크린샷 2026-03-27 오후 9 26 45
  • HTTP, WebSocket 기반의 Push + Realtime 통신
    • WebSocket API
    • 채팅 애플리케이션에서 많이 활용
    • 스트리밍 대시보드 - 양방향
    • 클라이언트, 서버 모두 메시지 전송 가능
    • 백엔드 서버는 연결된 모든 사용자에게 데이터 푸시 가능
  • HTTP, AMQP
    • Polling
    • 일정 시간마다 새로고침
    • 불필요한 통신 발생 가능성 높다.
    • 연결을 맺고 끊는데 드는 비용이 크다.
  1. Event-Driven Communication(비동기)
스크린샷 2026-03-27 오후 9 32 09
  • 마이크로서비스 간 호출 대신 이벤트 생성(비동기 방식) - Message Broker System에서 메시지를 소비
  • AMQP(Advanced Message Queueing Protocol) - Publish/Subscribe 패턴
  • 메시지 소비자와 생산자는 서로의 존재를 모르게 설계할 필요가 있다.
  • 서비스의 종속성이 감소하면서 느슨한 결합의 서비스를 구성할 수 있다.
  • 아키텍처의 복잡성 자체가 증가한다.

RESTful API 통신

스크린샷 2026-03-27 오후 9 43 23
  • Restful API : 마이크로서비스를 위한 가장 일반적인 통신 아키텍처
  • Request/Response API - RESTful API

장점

  • 사용 용이(웹 브라우저)
  • HTTP 프로토콜
  • HTTP GET 캐싱 옵션
  • Json 형식

단점

  • 관계형 데이터를 얻기 위한 여러 요청 필요하다.
  • 많은 데이터를 표현할 때 호출이 많아진다.
  • 데이터 크기가 커지게 되면 그에 따라 많은 오버헤드가 발생한다.

GraphQL 통신

  • 클라이언트가 필요한 데이터 구조를 정의 → 동일한 데이터 구조가 서버로부터 반환된다.
    • 모든 가능한 데이터 스키마 생성이 가능하다.
    • 클라이언트에서 쿼리를 요청하면 검증 후에 쿼리를 실행한다.
  • API를 위한 쿼리 및 조작 언어 → 기존 데이터를 가지고 쿼리를 수행할 수 있는 방법을 제공한다.
    • 클라이언트가 필요한 것을 정확하게 요청하고 얻을 수 있다.
  • 단일 요청에서 여러 소스에 접근하여 데이터 가져오기
    • 네트워크 호출 감소
    • 한 리소스의 속성과 리소스 간의 특정 리소스 참조가 가능하다.
    • 애플리케이션에 필요한 데이터만 가져오기가 가능하다.
  • 기존 쿼리에 영향을 주지 않고 새로운 필드와 유형 추가가 가능하다.

GraphQL API : FRESH

  • Fast : 데이터를 얻기 위해 여러 번 호출하지 않고 특정 필드만 선택하여 쿼리를 제공한다,
  • Single Request : 단일 요청으로 애플리케이션에 필요한 모든 데이터를 가져온다.
  • Evolve API : 기존 쿼리에 중단없이 새로운 API 기능 추가가 가능하다.
  • Strongly typed : 쿼리하기 전에 데이터에 대해 설명하여 강력하게 정의된 데이터 유형을 사용한다.
  • Hierarchical Structure : 객체 간 관계가 그래픽 구조로 정의된 계층적 구조를 제공한다.
  • Query Complexity : 한 번의 요청에 너무 많은 중첩 필드 데이터를 요청하는 경우 성능에 문제가 될 수 있다.
  • Caching : 간단한 캐시 구현이 어렵다.
  • Rate Limiting : REST API에서는 특정 시간에 특정 양의 요청만 허용하는 것이 가능하지만 GraphQL에서는 어렵다.

gRPC 통신

스크린샷 2026-03-27 오후 10 31 37
  • Google에서 개발한 오픈소스 원격 프로시저 호출(Remote Procedure Calls) 시스템
  • 서비스를 효율적으로 연결하고 분산 시스템을 구축하기 위한 프레임워크
  • 고성능, HTTP/2 프로토콜 사용 → Binary Message 전송
  • 서비스 계약 정의 → Protocol Buffers(Protobuf) 언어
    • Protobuf : 프로그래밍 언어에 상관없이 서비스 간 통신에 사용할 인터페이스 정의
    • 여러 언어에서 사용가능한 크로스플랫폼 클라이언트 및 서버 바인딩 생성
    • 프로그래밍 언어에 독립적, 서로 통신할 수 있는 서비스를 생성
    • Protobuf 계약 정의 : 각 서비스에서 정의된 계약을 사용하여 통신 인프라 설정 코드 자동 생성
  • gRPC를 사용하여 클라이언트 App에서 다른 서버 App의 메서드 호출이 가능하다.

장점

  • SSL/TLS : 다양한 인증 방법 지원
  • 멀티 플랫폼 : 다양한 언어 및 플랫폼 지원
  • Binary Serialization : 이진 직렬화를 사용하여 JSON보다 높은 성능
  • High Performance : HTTP/2 사용 시 30~40% 성능 향상 유도
  • Bi-directional Streaming : 양방향 스트리밍 작업 지원
  • 마이크로서비스 간 통신을 위해 백엔드 작업에서 주로 사용
  • Low Latency + High Throughput
  • P2P Real Time Comminucation
  • gRPC Binary Message < JSON Text Message

WebSocket 통신

image
  • 실시간 웹 애플리케이션 개발 - 클라이언트에 지속적인 데이터 표시, 연결된 소켓으로 PUSH
  • 채팅 애플리케이션 개발 - 구독자, 브로드캐스팅 채널 간의 메시지 교환, 메시지 송수신 처리 시 처리가 쉽고 빠르다.
REST APIs WebSocket APIs
단방향/Stateless 양방향/Stateful
비용이 크다 비용이 적다
CRUD 작업 처리 → 고수준 프로토콜 소켓 + 포트 사용 → 저수준 프로토콜
애플리케이션에 대한 요청 트래픽이 많은 경우 유리 실시간 애플리케이션 개발
요청이 발생할 때마다 TCP 연결이 필요 클라이언트와 서버 간 데이터 통신 전체에 동일한 TCP 연결 필요
수직적으로 연결 확장 가능 수평적으로 연결 처리
모든 요청에 오버헤드가 발생 오버헤드 없음

gRPC 통신 전체 흐름 정리📒

image
@GrpcClient("order-service")                                                                                                                                                  
private OrderServiceGrpc.OrderServiceBlockingStub orderStub;  // ①. order-service gRPC 서버를 호출하기 위한 stub 주입

// ②. user-service(클라이언트)가 order-service(서버)에 gRPC 요청을 보내 주문 목록을 받아오는 부분                                                                                                                                 
OrderRequest request = OrderRequest.newBuilder()                                                                                                                              
          .setUserId(userId)                                                                                                                                                    
          .build();                                                                  
                                                                                                                                                                                
OrderResponse response = orderStub.getOrders(request); // ← 핵심  

// ③. order-service(서버)가 user-service(클라이언트)로부터 gRPC 요청을 받아 DB에서 주문 목록을 조회한 후 응답을 반환하는 부분                                                                                                                                      
@GrpcService                                                                                                                                                                  
public class OrderGrpcService extends OrderServiceGrpc.OrderServiceImplBase {
                                                                                                                                                                                
    @Override                                                                      
    public void getOrders(OrderRequest request, StreamObserver<OrderResponse> responseObserver) {                                                                             
        Iterable<OrderEntity> orders = orderRepository.findByUserId(request.getUserId());  // DB 조회
        // ... 응답 구성                                                                                                                                                      
        responseObserver.onNext(response); // 응답 전송
        responseObserver.onCompleted();    // 스트림 종료                                                                                                                                        
    }                                                                              
}

GraphQL 통신 전체 흐름 정리📒

image
// order-service에서 GraphQL 스키마 & 쿼리 핸들러 정의
// schema.graphqls
type Query {
    ordersByUser(userId: ID!): [Order]  ← GraphQL 엔드포인트 정의
}

// OrderGraphQLController.java
@QueryMapping
public List<ResponseOrder> ordersByUser(@Argument String userId) {
    // /graphql 로 들어오는 쿼리를 처리
}
// UserServiceImpl.java - getUserByUserId() 메서드
// GraphQL 쿼리 작성
String graphQLQuery = """
    query($uid: ID!) {
      ordersByUser(userId: $uid) {
        orderId, productId, qty, unitPrice
      }
    }""";

// HTTP POST로 order-service GraphQL 엔드포인트 호출
ResponseEntity<Map> response = restTemplate.postForEntity(
    "http://localhost:8082/graphql",
    jsonRequest,
    Map.class
);
⚠️ **GitHub.com Fallback** ⚠️