[MSA] 마이크로 서비스 아키텍처란?

in_ho_·2023년 10월 29일
0

MSA

목록 보기
1/1
post-thumbnail

1. 모놀로식 아키텍처

  • 하나의 시스템이 서비스 전체의 기능을 처리하도록 설계

1-1. 장점

  • 하나의 WAS(Web Application Server)에서 모든 기능을 처리하도록 구성한다.
    • 네트워크로 인한 지연이나 데이터 유실을 걱정할 필요가 없다.
  • 데이터를 저장하기 위한 하나의 DB를 사용한다.
    • DB가 하나이므로 트랜잭션을 쉽게 사용할 수 있다.
  • 간단한 구조 덕분에 시스템 운영과 개발이 편리한 장점이 있습니다.
  • 테스트 코드를 작성하기 용이함.
  • 소규모 개발 팀이 비교적 간단하고 작은 기능을 제공하는 서비스를 개발한다면 모놀로식 아키텍처가 효율적입니다.

1-2. 단점

  • 하나의 서버가 여러 기능을 제공하므로 서비스 기능이 많아지면 복잡해질 수 있다.
    • 스파게티 코드가 되기 쉬움.
  • 모놀로식 아키텍처 서버 같은 경우 정적(static) 파일뿐만 아니라 서비스 기능까지 웹 서비스에 필요한 모든 기능을 제공합니다.
    • 이럴 경우 서버 기능과 클라이언트 기능이 뒤 섞인채 개발할 수 밖에 없습니다.
  • 특정 기능만 트래픽이 늘어날 경우 서버를 scale-out(확장)할 때 서버를 하나 추가하는 방식밖에 없으므로 용이하지 않습니다.
  • 서비스의 규모가 커질 경우 확장이 용이하지 않습니다.

2. 마이크로서비스 아키텍처

  • 마이크로서비스 아키텍처는 기능이 나뉜 여러 애플리케이션이 있고, 각각의 독립된 데이터 저장소를 사용한다.

2-1. 키워드

  1. 대규모 시스템
  2. 분산 처리 시스템
  3. 컴포넌트들의 집합
  4. 시스템 확장
  • 이러한 특징들은 서비스 지향 아키텍처(Sercice Oriented Architecture, SOA)와 공통점이 많다.

    서비스 지향 아키텍처는 대규모 시스템을 설계할 때, 서비스 기능 단위로 시스템을 묶어 시스템 기능을 구현한 것을 말한다.

2-2. 느슨한 결합

  • 마이크로서비스스는 독립적으로 동작해야 하고, 다른 마이크로 서비스에 의존성을 최소화해야 합니다.
  • 이러한 느슨한 결합을 구현하기 위해 마이크로서비스마다 각각의 독립된 데이터 저장소가 필요합니다.

2-3. 설계 시 유의사항

  • 마이크로서비스들은 기능과 성격에 맞게 잘 분리되어야 한다.

    • 기능이 너무 작지도, 너무 크지도 않게 설계되어야 하기 때문입니다.
  • 네트워크 프로토콜이 가벼워야 함.

    • 각 마이크로서비스 컴포넌트들은 기능을 연동할 때 API를 통해 서로 데이터를 주고 받습니다.

      • 네트워크 프로토콜의 성능 저하가 장애가 될 수 있습니다.
    • 네트워크를 통해 마이크로서비스 사이에 데이터를 전달하려면 객체는 바이트 형태로 변경되어야 합니다.

      • 직렬화
        • 객체 -> 바이트
      • 역직렬화
        • 바이트 데이터 -> 객체
      • 직렬된 바이트가 원래의 객체보다 훨씬 크다면 네트워크에서 성능 저하가 발생합니다.
      • 또한 직렬화/역직렬화 과정에서 CPU와 메모리와 같은 시스템 리소스를 많이 사용하면 시스템의 전반적인 성능 저하가 발생합니다.
        • 보통은 JSON을 많이 주고 받으며, HTTP 기반의 REST API를 많이 사용합니다.

          이외에도 gRPC, Thrift, Avro, Protobuffer 등을 사용합니다.

          그리고 비동기 처리를 위해 AMQP 프로토콜을 사용하는 메시징 큐 시스템기반으로 데이터를 주고받을 수 있습니다. 대표적으로는 RabbitMQ가 있습니다. 최근에는 메세지 스트리밍 시스템인 Kafaka가 있습니다.

          메세징 큐 시스템은 REST API보다 통신에 높은 신뢰성을 제공한다는 장점이 있지만, 마이크로서비스 사이에 메세징 큐 시스템에 의존성이 생긴다는 단점이 있습니다.

2-4. 장점

  1. 독립성
    • 하나의 마이크로서비스는 하나의 비즈니스 기능을 담당하므로 다른 마이크로서비스와 간섭이 최소화됩니다.
  2. 대용량 데이터를 저장하고 처리하는데 자유로움
    • 독립된 데이터 저장소를 갖고 있기 때문에 대용량 데이터를 마이크로서비스마다 나누어 저장할 수 있습니다.
  3. 시스템 장애에 견고
    • 마이크로서비스는 느슨하게 서로가 결합되어 있고, 독립적이기 때문에 서로간에 미치는 영향이 적습니다.
  4. 서비스 배포 주기가 빠름
    • 배포를 자주하려면 CI/CD 시스템이 구축되어 있어야 합니다.
  5. 확장성
    • 마이크로서비스 단위로 확장할 수 있습니다.
  6. 사용자 반응에 민첩하게 대응
    • 새로운 서비스를 마이크로서비스로 분리하여 설계하고 시스템이 포함하면 사용자 반응에 따라 시스템을 고도화하거나 빠르게 시스템에서 제외할 수 있습니다.

2-5. 단점

  1. 개발하기 어려운 아키텍처

    • 시스템이 네트워크상에 분산되어 있기 때문에 발생한다.
    • 데이터 저장소가 분리되어 있으므로 트랜잭션을 사용할 수 없다.

      개발자는 여러 장애 상황을 대비하는 폴백(fallback) 기능을 고려해야 합니다.

      • 다른 마이크로서비스가 운영이 불가능한 상태일 때를 대비하는 기능을 의미한다. 이 기능을 사용하여 어떤 경우라도 사용자에게 서비스되도록 해야 한다.
  2. 운영하기 매우 어려운 아키텍처

    • 어디서 에러가 발생했는지 어려움.
    • 데이터가 분산되어 있기 때문에 분산 트랜잭션을 사용하지 않는다면 데이터의 일관성을 유지하기 어려움.
  3. 설계하기 어려운 아키텍처

    • 잘 설계된 마이크로서비스 아키텍처 시스템은 복잡한 비즈니스 로직을 개발해서 보다 쉽게 유지보수할 수 있고, 동시에 많은 사용자 요청을 처리할 수 있다. 하지만 잘못된 방향으로 설계한다면 이 장점들이 단점이 될 수 있습니다.
  4. 마이크로서비스 아키텍처로 설계된 서비스 운영에는 여러가지 자동화된 시스템이 필요하다.

    마이크로서비스를 도입하는 이유

    • 빠른 서비스 개발, 운영, 대규모 서비스를 처리하기 위하여.
    • 빠르게 배포하기 위해서 CI/CD 시스템이 필요합니다.
    • 수십, 수백개의 인스턴스를 제어해야 하므로 모니터링 시스템도 필요합니다.(알림, 로그)

3. 마이크로서비스 아키텍처의 설계

3-1. 서비스 세분화의 법칙

  • 서비스 세분화의 법칙은 서비스 지향 아키텍처의 여러 핵심 원칙 중 하나입니다.
  • 서비스 세분화 원칙은 4개의 요소로 구성되어 있습니다.
  1. 비즈니스 기능
    • 비즈니스 기능으로 서비스를 나눈다.
  2. 성능
    • 성능이 떨어지는 마이크로서비스는 너무 많은 기능을 처리하고 있는지 파악해서 설계 필요
  3. 메세지 크기
    • 메세지 크기가 너무 크면 직렬화/역직렬화하는데 성능 문제가 발생합니다.
    • 단, 비즈니스 기능이나 일관성을 유지하는 트랜잭션에 문제가 없다면 이는 무시해도 좋습니다.
  4. 트랜잭션
    • 데이터를 기준으로 서비스를 분리하는 방법

3-2. 바운디드 컨텍스트

  • 도메인 주도 개발의 핵심 개념 중 하나.

    도메인

    • 비즈니스 전체나 조직이 행하는 일
  • 도메인은 서브 도메인들로 구분할 수 있는데, 도메인과 다른 도메일이 확연되는 경계를 바운디드 컨텍스트라고 합니다.
  • 바운디드 컨텍스트는 다른 도메인 모델과 독립적인 영역으로, 바운디드 컨텍스트를 기준으로 설계하면 중복될 확률이 매우 줄어들게 됩니다.

3-3. 단일 책임의 원칙(Single Responsibility Principle)

  • 단일 책임 원칙은 모든 클래스는 하나의 책임을 가지며, 그 클래스의 기능은 이 책임을 기반으로 개발되어야 함을 의미한다.
  • 이를 마이크로서비스에 적용하면 하나의 책임을 갖는 마이크로서비스도 바운디드 컨텍스트처럼 독립 영역을 갖게되고 이처럼 설계하면 다른 마이크로서비스들과 간섭이 줄어들고 변경이 줄어듭니다.

3-4. 가벼운 통신 프로토콜

  • 모놀로식 아키텍처는 성능 면에서는 뛰어나다.
  • 마이크로서비스 아키텍처는 시스템을 아무리 이상적으로 설계하더라도 마이크로서비스들이 서로 데이터를 참조하거나, 수정, 변경하는 상황이 발생합니다.
  • 주로 HTTP를 사용합니다.

3-5. 외부 공개 인터페이스

  • 마이크로서비스들은 네트워크를 이용하여 서로 통신한다. 메세지 포맷과 같은 경우는 변경이 용이하지 않으므로 신중해야 한다.

3-6. 마이크로서비스마다 독립된 데이터 저장소

  • 마이크로서비스마다 독립된 데이터 저장소를 갖는 이유는 Join이나 FK를 사용하는 순간 두 테이블간의 독립성이 무효화되기 때문이다.
  • 독립된 데이터 저장소를 갖을 경우 데이터 정합성을 유지할 수 있다.

3-7. 단일 장애 지점

  • 시스템을 구성하는 컴포넌트 중 하나에 장애가 발생하면 전체 서비스에 문제가 생기는 것을 단일 장애 지점이라고 부릅니다.
  • 아키텍처를 설계할 때 가장 기본은 단일 장애 지점을 줄이고, 하나의 컴포넌트에 의존하지 않는 것입니다.

3-8. 고가용성 확보

  • 고가용성을 확보하기 위해서는 주로 로드밸런서를 활용합니다.
  • 로드 밸런서는 가상 서버 역할을 하고, 사용자 요청을 모두 받습니다.
  • 로드 밸런서에 연결된 애플리케이션 서버에 알고리즘에 따라 사용자 요청을 분산합니다.
  • 로드 밸런서에 연결된 애플리케이션 서버를 늘리는 것을 스케일아웃(scale-out)이라고 합니다.

3-9. 모니터링 시스템

  • 객관적인 자료로 시스템을 확장할 근거를 확인할 수 있고, 시스템에 문제가 생기면 알람도 받을 수 있기 때문이다.

    자빅스, 문인, 나기오스, APM

3-10. 마이크로서비스의 예시

3-11. 요소 애플리케이션

  • 마이크로서비스 아키텍처가 대중화되면서 기존의 인프라에서 클라우드로 인프라로 이동하고 있다.
  • 요소 애플리케이션은 컴퓨팅 환경에 적합한 애플리케이션 개발하는 방법론이다.
  • 클라우드 환경에 적합한 애플리케이션을 개발할 때 고려해야할 12가지 항목을 선정한 것이다.

3-11-1. 버전 관리되는 하나의 코드베이스와 하나의 배포

코드베이스

  • 프로젝트에 담긴 코드.
  • properties와 profile을 화룡해 쉽게 여러 환경을 대상으로 배포할 수 있다.

3-11-2. 명시적으로 선언할 수도 있고, 분리할 수도 있는 의존성

  • 스프링 프레임워크는 애플리케이션의 의존성을 관리하기 위해 Maven과 Gradle을 사용합니다.

3-11-3. 환경 변수를 이용한 설정

  • 하나의 코드 베이스는 여러 환경에서 동작할 수 있습니다. 하지만 외부에서 값을 지정해주어야 할 경우가 있습니다.
  1. 애플리케이션마다 고유 이름이 필요하다.
  2. 애플리케이션을 실행할 때 애플리케이션의 프로파일 이름이 필요하다.
java -Dspring.profiles.active=dev -jar ./spring-tour-1.0.0.jar

자바는 -D[환경변수]=[환경변수 값]으로 지정할 수 있습니다.

  • 환경 변수의 이름은 spring.profiles.active입니다.

3-11-4. 지원 서비스는 연결된 리소스로 처리

지원 서비스

  • 애플리케이션이 네트워크를 이용해서 사용하는 모든 서비스를 의미.
  • 예를들어 JDBC로 연결된 DB 같은 데이터 저장소나 결제 시스템 같은 다른 도메인 영역을 담당하는 마이크로 서비스들도 지원 서비스라고 합니다.
  • 이런 지원 서비스들은 네트워크로 연결되어 언제든지 애플리케이션과 연결하고 분리할 수 있어 리소스라고 합니다.
  • 리소스 간의 연결을 위해 RabbitMQ, Kafaka, RestTemplate, WebClient를 사용합니다.

3-11-5. 소스 빌드와 실행은 완전히 분리되어야 한다.

  • 코드 베이스는 빌드, 릴리스, 실행 이 3단계로 시스템에 배포된다. 각 단계는 완전히 분리되어야 합니다.
  1. 빌드
    • 먼저 의존성이 있는 라이브러리들과 코드 베이스를 조합하여 컴파일한다.
  2. 릴리스
    • 스프링 프로파일 혹은 메이븐 프로파일 설정을 이용하여 resources에 위치한 설정 파일들을 조합한다.
    • 컴파일된 코드와 설정 파일을 조합하여 실행 가능한 JAR 파일을 생성한다.
  3. 실행
    • JAR 파일을 java 명령어를 이용하여 실행한다.

3-11-6. 애플리케이션은 하나 이상의 무상태 프로세스로 실행되어야 한다.

  • 애플리케이션을 구성하는 프로세스들은 하나 혹은 그 이상의 프로세스들로 구성됩니다. 하지만 이 프로세스들은 무상태이며 공유하는 것이 없어야합니다.

3-11-7. 포트 바인딩을 통한 서비스 공개.

  • 모든 애플리케이션은 특정 포트가 바인딩되도록 설계한다.

3-11-8. 동시성

  • 자바 프로그래밍에서는 동시성을 다루는데 스레드를 사용합니다.
  • Jetty, Tomcat과 같은 WAS가 내부적으로 스레드를 관리해서 자연스럽게 멀티 스레드 프로그램이 동작합니다.

3-11-9. 프로세스는 빠르게 시작해야 하고, 안정적으로 종료해야 한다.

3-11-10. Dev 환경과 Production 환경 일치

  • 마이크로서비스를 운영하면 개발 완료된 프로그램이나 기능은 수시로 배포된다. 그러므로 우리는 Dev 환경과 실제 Production 환경을 가능한 비슷하게 설정하고 유지해야 한다.

3-11-11. 로그는 이벤트 스트림으로 다룬다.

  • ELK Stack 구축
    • ELK 스택은 로그의 저장 및 검색을 담당하는 엘라스틱 서치, 로그를 나르고 저장하는 로그 스테시, 뷰를 처리하는 키바나로 구성한다.

시스템 유지 보수를 위한 일회성 프로세스

  • 서비스를 운영하다보면 데이터를 마이크레이션하는 프로그램이 필요하다. 이러한 유지보수 프로그램을 admin 또는 maintenance 프로세스라고 한다.
  • 여기서는 커맨드라인에서 바로 실행할 수 있는 일회성프로그램이다.
    • Spring Boot의 CommandLineRunner, ApplicationRunner를 사용할 수 있습니다.

0개의 댓글