Posts 마이크로서비스간 통신(2) - 동기 방식
Post
Cancel

마이크로서비스간 통신(2) - 동기 방식

※ 해당 내용은 ‘마이크로서비스 패턴(크리스 리처드슨)’ 3장을 읽고 정리한 내용입니다.

동기 RPI 패턴 응용 통신


  • RPI(Remote Procedure Invocation)는 클라이언트가 서비스에 요청을 보내고 서비스가 처리 후 응답을 회신하는 IPC
  • 응답 대기 중에 블로킹하는 클라이언트, 리액티브한 논블로킹 아키텍처를 가진 클라이언트도 있지만, 메시징으로 통신하는 클라이언트와 달리 응답이 제때 도착한다고 가정한다.
  • RPI의 작동 원리
    • 클라이언트의 비즈니스 로직은 프록시 인터페이스 호출 (프록시 인터페이스는 RPI 프록시 어댑터 클래스로 구현)
    • RPI 프록시가 서비스에 전달한 요청은 RPI 서버 어댑터 클래스가 접수
    • 이 클래스는 서비스 인터페이스를 통해 비즈니스 로직 호출
    출처 : https://thebook.io/007035/ch03/02-01/

1. 동기 RPI 패턴 : REST

  • HTTP 동사를 사용해서 URL로 참조되는 리소스를 조작
  • REST API 설계시, 어떻게 최소한의 호출(요청)로 연관된 많은 객체들을 가져올 수 있을지 고민해야한다.
  • 따라서 데이터를 효율적으로 조회할 수 있게 설계된 GraphQL, Netflix Falcor등의 기술이 각광을 받기 시작했다.
  • 장점
    • API 자체가 단순하고, Postman, curl 등의 도구를 사용해서 테스트를 간편하게 할 수 있다.
    • HTTP는 방화벽 친화적
      (방화벽 입장에서 쉽게 접근 가능한 특성을 지닌다 - 단일 포트 사용, 인터넷에서 서버 접속 가능, TCP 사용)
    • 중간 브로커가 필요하지 않기 때문에 시스템 아키텍처가 단순해진다.
  • 단점
    • 시나리오가 복잡해질수록 효율이 떨어질 수 있다.
    • 요청/응답 스타일의 통신만 지원한다.
    • 클라이언트/서비스가 직접 통신하기 때문에 가용성이 떨어질 수 있다.(항상 양쪽 모두가 실행중이어야 하기 때문에)
    • 요청 한 번으로 여러 리소스를 가져오기 어렵다.
    • 다중 업데이트 작업을 HTTP 동사에 매핑하기 어려울 수 있다.

2. 동기 RPI 패턴 : gRPC

  • gRPC는 구글에서 개발한 RPC(Remote Procedure Call) 시스템이다.
  • HTTP는 한정된 동사만 지원하기 때문에 다양한 업데이트 작업을 지원하는 REST API를 설계하기가 쉽지 않다.
    바로 이러한 문제를 해결하고자 등장한 기술이 바로 gRPC이다.
  • 장점
    • 다양한 업데이트 작업이 포함된 API를 설계하기 쉽다
    • 큰 메시지를 교환할 때 콤팩트하고 효율적이다
    • 양방향 스트리밍으로 인해 RPI, 메시징 두 가지 통신 방식이 모두 가능하다.
    • 다양한 언어로 작성된 클라이언트/서버 간 연동이 가능하다.
  • 단점
    • 자바스크립트 클라이언트가 하는일이 REST/JSON 기반 API 보다 많다.
    • 구현 방화벽은 HTTP/2를 지원하지 않는다.

3. 부분 실패 처리

분산 시스템은 서비스가 다른 서비스를 동기 호출할 때마다 부분 실패할 가능성이 항상 존재한다. 예를 들어, 요청에 제때 응답하지 못하거나, 요청한 서비스가 내려가는 등의 상황이 있을 수 있다. 클라이언트는 응답을 기다리면서 블로킹되기 때문에 요청한 서비스의 실패가 클라이언트로 거슬러 올라가면서 전체 시스템의 중단을 초래할 수도 있다. 따라서, 부분 실패가 애플리케이션 전체에 전파되지 않도록 서비스를 설계해야 한다.

견고한 RPI 프록시 설계를 통한 해결 방법

Netflix Histrix는 아래와 같은 다양한 패턴이 구현된 오픈 소스 라이브러리이므로
JVM 환경이라면 이를 통해 RPI 프록시를 구현해보는 것을 권장.

  • 네트워크 타임아웃
    • 응답 대기시 무한정 블로킹되지 않도록 타임아웃 설정하여 리소스 고갈 방지
  • 미처리 요청 개수 제한
    • 클라이언트가 특정 서비스에 요청 가능한 미처리 요청의 최대 개수 설정
    • 최대 개수에 이르면 해당 요청은 즉시 실패 처리
  • 회로 차단기 패턴
    • 성공/실패 비율(에러율)이 임계치를 초과하면 그 이후 요청은 바로 실패로 처리
    • 타임아웃 시간 이후 클라이언트가 재시도해서 성공하면 회로 차단기는 닫힌다.

실패시 조치 방법 결정

Netflix Histrix 같은 라이브러리는 부분적인 솔루션에 불과하기 때문에
무응답 원격 서비스를 어떻게 복구하면 좋을지는 상황에 맞게 판단해야 한다.

  • 클라이언트가 알 수 있도록 요청 서비스에서 클라이언트에게 에러 반환
  • 부분 실패 시 미리 정해진 기본값이나 캐시된 응답 등 대체 값(fallback value) 반환
  • 위 방법 이외에도 각각의 서비스가 실패할 경우를 대비한 대응 방안이 준비되어 있어야 한다.

4. 서비스 디스커버리

서비스를 호출하는 코드는 서비스 인스턴스의 IP 주소 및 포트를 알고 있어야 한다. 클라우드 기반의 마이크로서비스 애플리케이션은 이러한 네트워크 위치가 동적이기 때문에 이를 식별하는 일이 결코 간단하지 않다. 서비스 인스턴스마다 네트워크 위치가 동적 배정되고, 자동 확장, 실패, 업그레이드 등 여러 가지 사유로 계속 달라지므로 이러한 네트워크 위치를 관리해줄 ‘서비스 디스커버리’가 반드시 필요하다.

서비스 레지스트리(Service Registry)

  • 서비스 인스턴스의 네트워크 위치를 DB화 한 것
  • 서비스 인스턴스가 시작/종료할 때마다 서비스 레지스트리 업데이트
  • 클라이언트에서 서비스 호출시, 서비스 디스커버리가 서비스 레지스트리에서 가용 서비스 인스턴스 목록을 가져오고
    그중 한 서비스로 요청을 보낸다.
  • 서비스 레지스트리를 사용하는 일반적인 방법
    • 클라이언트/서비스가 직접 서비스 레지스트리와 상호 작용
    • 배포 인프라로 서비스 디스커버리 처리
  • 대표적인 서비스 레지스트리로는 Netflix Eureka가 있다.

애플리케이션 수준의 서비스 디스커버리 패턴

  • 서비스 클라이언트는 서비스 레지스트리로부터 전체 인스턴스 목록을 가져와 한 인스턴스로 요청을 라우팅한다.
  • 라우팅시 라운드-로빈, 랜덤과 같은 부하분산 알고리즘 사용
  • 장점
    • 다양한 플랫폼에 서비스가 배포된 경우에도 처리 가능 (ex : 서비스 일부는 쿠버네티스, 나머지는 레거시 환경)
  • 단점
    • 사용하는 언어(프레임워크)에 맞는 각각의 서비스 디스커버리 라이브러리가 필요
      (따라서, 배포 인프라를 사용하여 서비스 디스커버리 매커니즘 활용하는 것이 좋다)
    출처 : https://thebook.io/007035/ch03/02/04/02/

플랫폼에 내장된 서비스 디스커버리 패턴

도커, 쿠버네티스 등과 같은 최신 배포 플랫폼에는 대부분 서비스 레지스트리, 서비스 디스커버리 매커니즘이 탑재되어 있다.

  • 배포 플랫폼은 가상IP(VIP) 주소, VIP 주소로 해석되는 DNS명을 각 서비스마다 부여
  • 서비스 클라이언트가 DNS명/VIP를 요청하면 배포 플랫폼이 가용 서비스 인스턴스 중 하나로 요청을 라우팅
  • 즉, 배포 플랫폼이 서비스 등록, 서비스 디스커버리, 요청 라우팅을 전부 담당
    출처 : https://thebook.io/007035/ch03/02/04/03/

실제로 적용해보기


더 공부해야할 부분


  • gRPC
  • 블로킹과 동기

참고 자료


  • 크리스 리처드슨, 『마이크로서비스 패턴』, 길벗(2020), p104-152.
This post is licensed under CC BY 4.0 by the author.

마이크로서비스간 통신(1) - 개요

마이크로서비스간 통신(3) - 비동기 방식