[마이크로서비스패턴] 3장 프로세스 간 통신

3장. 프로세스 간 통신

3장 핵심내용

  • 다양한 통신 패턴
  • 마이크로서비스 아키텍처에서 IPC 중요성
  • API 정의 및 발전
  • 여러 가지 IPC와 각각의 트레이드오프
  • 비동기 메시징 통신 장점
  • 메시지를 DB 트랜잭션에 태워 확실하게 전송

IPC(Inter-Process Communication, 프로세스 간 통신)

3.1 마이크로서비스 아키텍처 IPC 개요

상호작용 스타일

두 가지 기준

  1. 일대일/일대다
    • 일대일
      • 요청/응답 : 응답을 기다리기 때문에 강결합 스타일
      • 비동기 요청/응답
      • 단방향 알림
    • 일대다
      • 발행/구독
      • 발행/비동기 응답
  2. 동기/비동기

마이크로서비스에서 API 클라이언트와 서버는 함께 컴파일 되지 않음. 즉, 기존 API와 호환되지 않는 새 버전의 API가 배포되면 컴파일 에러 없이, 런타임 시 에러 발생.

API 변경 방법

시맨틱 버저닝

  • MAJOR.MINOR.PATCH 세파트로 구성
    • MAJOR : 하휘 호환되지 않는 변경분 API 적용 시
    • MINOR : 하휘 호환되는 변경분 API 적용 시
    • PATCH : 하휘 호환되는 오류 수정 시

      하휘 호환되는 소규모 변경

  • 견고성 원칙 : 요청 속성 누락 시 기본값 제공. 필요한 것보다 더 많은 속성 응답 시 클라이언트는 무시.

    중대한 대규모 변경

  • 신구 버전 API 모두 지원
    • url 경로에 v1, v2 등의 메이저 번호 기입
    • MIME 타입 내부에 버전 번호 삽입

메시지 포맷

텍스트

  • JSON, XML 등
  • 장점
    • 사람이 읽을 수 있음
    • 하휘 호환성 쉽게 보장 : 관심 있는 값만 골라쓰면 됨
    • 문서화 용이 : XML 스키마, JSON 스키마
  • 단점
    • 메시지가 김 : 속성 + 속성명 -> 파싱 오버헤드 가능성 존재

이진

3.2 동기 RPI 패턴 응용 통신

RPI(Remote Procedure Invocation, 원격 프로시저 호출)

  • 클라이언트가 서비스에 요청. 서비스가 처리 후 응답 회신하는 IPC

동기 RPI 패턴 : REST

HTTP 사용 IPC

  • 리소스에 대한 행위를 HTTP method로 표현

REST 성숙도 모델

  • 레벨 0 : 유일한 end point에 POST 요청. 액션 + 대상 + 매개변수
  • 레벨 1 : 리소스 개념 지원. 액션 + 매개변수 POST요청.
  • 레벨 2 : HTTP 동사 이용.
  • 레벨 3 : HATEOAS 원칙 기반 설계.

REST 장단점

장점

  • 단순, 익숙
  • postman, curl 등 통해 테스트 쉬움
  • 요청/응답 스타일 통신 직접 지원
  • 방화벽 친화적 : 단일 포트 사용, 인터넷에서 서버 접속 가능, TCP 사용
  • 시스템 아키텍처 단순 : 중간 브로커 불필요

    단점

  • 요청/응답 통신만 지워
  • 가용성 떨어짐 : 서버/클라이언트 모두 실행중이어야
  • 서비스 인스턴스 위치를 클라이언트가 알고 있어야 : 서비스 디스커버리 매커니즘 활용
  • 요청 한 번으로 여러 리소스 조회 어려움 : GraphQL, Netflix Falcor 등 통해 해결하고자
  • HTTP 동사 매핑 어려움 경우 존재 : 다중 업데이트 작업 등

동기 RPI 패턴 : gRPC

  • 다양한 언어로 클라이언트/서버 작성 가능한 프레임워크
  • 이진 메시지 기반 프로토콜
  • 프로토콜 버퍼 기반의 IDL로 정의
  • 프로토콜 버퍼 컴파일러 : 클라이언트 쪽 스텁 / 서버 쪽 스켈레톤 생성.
    • 다양한 언어 코드 생성 가능
  • HTTP/2 통해 교환
  • 스트리밍 RPC도 지워
  • 프로토콜 버퍼 메시지 포맷 사용

gRCP 장단점

장점

  • 다양한 업데이트 작업 API 설계 용이
  • 큰 메시지 교환 시 콤패트, 효율적
  • 양방향 스트리밍 -> RPI, 메시징 두 가지 통신 방식 모두 가능
  • 다양한 언어 연동 가능

단점

  • 자바스크립트 클라이언트가 하는 일이 REST/JSON 기반 API보다 많음
  • 구형 방화벽 HTTP/2 미지원

부분 실패처리 : 회로 차단기 패턴

circuit-breaker
circuit breaker : 연속 실패 횟수가 임계치 초과 시 일정 시간 동안 호출 즉시 거부 RPI 프로시

견고한 RPI 프록시 설계

  • 네트워크 타임아웃
  • 미처리 요청 개수 제한
  • 회로 차단기 패턴s

불능 서비스 복구

무응답 원격 서비스에 대한 복구는 상황에 맞게 조치. 중요하지 않은 데이터라면 캐시 활용 또는 에러, 데이터 자체를 제외하는 등의 방법이 있을 것.

서비스 디스커버리

클라우드 환경 마이크로서비스는 네트워크 위치가 동적 할당. 오토 스케일링, 실패, 업그레이드 등으로 네트워크는 계속해서 변화. => 서비스 디스커버리 필요성 대두

서비스 디스커버리 : 애플리케이션 서비스 인스턴스의 네트워크 위치를 DB화한 서비스 레지스트리

  • 클라이언트/서비스가 직접 서비스 레지스트리와 상호 작용
  • 배포 인프라로 서비스 디스커버리 처리

디스커버리 두 가지 요소

Netflix Eureka, Eureka java client, Ribbon(유레카 클라이언트 지원 HTTP 클라이언트) => Spring Cloud

1) 자가 등록 패턴

  • self-registration
  • 서비스 인스턴스는 서비스 레지스트리에 자기 자신을 등록
  • 서버 : 서비스 레지스트리 등록 API 호출 + 헬스 체크 제공

2) 디스커버리 패턴

  • 서비스 클라이언트는 서비스 레지스트리에 있는 가용 서비스 인스턴스 목록을 조회하고 부하 분산 참고

플랫폼 내장 서비스 디스커버리 패턴 적용

Docker, k8s 서비스 레지스트리, 서비스 디스커버리 메커니즘 탑재(k8s 의 service 오브젝트)

1) 서드파티 등록 패턴

  • 서드파티가 서비스 인스턴스를 서비스 레지스트리에 자동 등록
  • 배포 플랫폼의 등록기라는 서드 파티가 서비스 레지스트리에 등록하는 작업 수행

    2) 서버 쪽 디스커버리 패턴

  • 클라이언트가 서비스 디스커버리를 담당한 라우터에 요청
  • 클라이언트는 DNS명을 요청

플랫폼에 제한적이라는 단점. 하위 블로그 글 참조.
Spring Cloud vs Kubernetes

3.3 비동기 메시징 패턴 응용 통신

메시징? 서비스가 메시지를 서로 비동기적으로 주고받는 통신 방식
메시지는 메시지 채널을 통해 교환.

메시징

메시지

  • 헤더와 바디로 구성
    • 헤더 : 데이터에 관한 메타데이터. key-value
    • 바디 : 실제로 송신할 텍스트 또는 이진 포맷 데이터
  • 메시지 종류
    1. 문서 : 데이터만 포함된 제네릭한 메시지
    2. 커맨드 : 호출할 작업과 전달할 매개변수 지정되어 있음
    3. 이벤트 : 대부분 도메인 객체의 상태 변화를 나타냄

메시지 채널

  1. 점대점 채널
    • 컨슈머 하나만 지정하여 메시지 전달
    • 컨슈머 메시지
  2. 발행-구독
    • 동일 채널 바라보는 모든 컨슈머에세 메시지 전달
    • 이벤트 메시지

메시지 브로커

서비스가 서로 통신할 수 있게 해주는 인프라 서비스

브로커리스 메시징

ZeroMQ

장점

  • 네트워크 트래픽이 가볍고 지연시간 짧음
  • 메시지 브로커가 없어 성능 병목적이나 SPOF(Single Point of Failure, 단일 장애점) 될 일이 없음
  • 운영 복잡도 낮음 : 메시지 브로커 설정/관리 불필요

단점

  • 서비스가 서로의 위치를 알고 있어야 함
  • 송신자/수신자 모두 실행 중이어야. 가용성 떨어짐
  • 전달 보장 메커니즘 구현 어려움

브로커 기반 메시징

ActiveMQ, RabbitMQ, Kafka
AWS Kinesis, AWS SQS 등

장점

  • 느슨한 결합
  • 메시지 버퍼링
  • 유연한 통신
  • 명시적 IPC

단점

  • 성능 병목 가능성
  • 단일 장애점 가능성
  • 운영 복잡도 부가

수신자 경합과 메시지 순서 유지

수신자의 수평 확장으로 인해 수신자 경합이 발생할 수 있으며, 메시지 순서가 보장되어야 함.
카프카는 수신자를 컨슈머 그룹으로 묶으며 각 컨슈머에 대해 파티셔닝을 활용

중복 메시지 처리

  • 멱등한 메시지 핸들러 작성
  • 메시지 추적과 중복 메시지 솎아내기
    • DB에 메시지 저장

트랜잭셔널 메시징

DB 업데이트와 메시지 전송을 한 트랜잭션으로 묶어야 함.

메시지 확실하게 발행하는 방법

  1. DB 테이블 메시지 큐로 활용 (트랜잭셔널 아웃박스)
    • 서비스는 메시지를 DB 업데이트 트랜잭션에 태워 OUTBOX 테이블에 INSERT. 메시지 릴레이는 OUTBOX 테이블로부터 메시지 읽어 브로커에 발행
  2. 이벤트 발행 : 폴링 발행기 패턴
    • DB에 있는 아웃 박스를 폴링해서 메시지 발행
  3. 이벤트 발행 : 트랜잭션 로그 테일링 패턴
    • 트랜잭션 로그를 테일링하여 DB에 반영된 변경분을 발행
    • Debezium, LinkedIn Databus, DynamoDB streams, Eventuate Tram

3.4 비동기 메시징으로 가용성 개선

동기 통신의 한계점 : 가용성 낮음

동기 상호 작용 제거

비동기 상호작용 스타일로 전환 : 다만 동기 API가 있는 경우 데이터 복제통해 가용성 높일 수 있음
다만, 데이터를 복제하는 것은 비효율적.

응답 반환 후 마무리

  1. 로컬에서 가용한 데이터만 갖고 요청 검증
  2. 메시지를 OUTBOX 테이블에 삽입하는 식으로 DB 업데이트
  3. 클라이언트에 응답 반환

참조