본문 바로가기

IT Book Summary/스프링 마이크로 서비스 코딩공작소

Chapter 02 스프링 부트로 마이크로 서비스 구축

 대규모 프로젝트에서 전통적으로 폭포수 waterfall 개발 방법론을 따르는 경향이 있었지만,

실제 개발과정에서 고객과 소통하을 반복하는 진화 과정을 따르므로 절저한 명세를 따르는 개발 방법론을 사용하기 어려워지며 

여러가지 단점 또한 발생 하였다.

  • 강한 결합
    비지니스 로직 호출이 프로그래밍 언어 수준에서 이루어지므로 약간의 수정의 여파가 큼.
  • 누설
    같은 데이터 저장소 안에서 같은 데이터 모델을 유지하는 방식은 쉽게 데이터 접근이 가능해 의존성이 생겨나 
    데이터베이스 구조를 변경하기 쉽지 않다.
  • 모놀리식
    여러 팀에서 공유되는 단일 코드 베이스에 저장되므로 추가 수정사항에도 전체 컴파일과 배포를 해야한다.

반면 마이크로 서비스 기반 아키텍처의 특성은 

  • 제한
    하나의 책임을 가지며 범위가 좁다.
  • 느슨한 결합
    MSA는 작은 서비스 집합으로 HTTP와 REST 호출 프로토콜 사용.
    서비스에 대한 인터페이스가 변하지 않는한 서비스를 자유롭게 수정할 수 있다.
  • 추상화
    마이크로서비스가 소유한 데이터는 해당 서비스만 수정할 수 있다.
  • 독립적
    서로 독립적으로 컴파일하고 배포할 수 있다. 변경사항을 쉽게 분리하고 테스트 가능.

 

클라우드 기반 애플리케이션의 일반적 특징

  • 사용자 층이 다양하며 대규모이다
    작은 범위의 명확한 인터페이스를 통해 원하는 기능만 신속하게 제공.
  • 상당한 작동시간 uptime 이 요구된다
    애플리케이션 전체를 중단하지 않고도 장애를 더 쉽게 격리.
    작동중지시간 downtime 은 줄고 결함 저항력은 높아짐.
  • 볼륨이 균일하지 않다
    부하를 받는 컴포넌트를 여러 서버에 수평 확장하기 쉽다.

 

성공적인 마이크로서비스 개발토대. 중요한 세 역할의 관점.

  • 아키텍트
    큰 그림을 보고 개별 마이크로서비스로 분해, 상호작용하는 방법을 이해하는 것.
  • 소프트웨어 개발자
    프로그래밍 언어와 프레임워크 사용방법의 이해.
  • 데브옵스 엔지니어
    운영환경 및 비운영환경에서 서비스 배포와 관리방법 정보 제공.
    모든 환경에서의 일관성 광 반복성이 중요.

2.1 아키텍트의 이야기 : 마이크로서비스 아키텍처 설계

 

1 - 비즈니스 문제의 분해

아키텍트는 비지니스를 영역을 나눠 분해하고 연관된 규칙과 데이터 로직을 그 안에 캡슐화 한다.

그리고 데이터 영역이 어울리지 않으면 서비스 경계를 나눈다.

2개의 개별 데이터 영역이 있다면 2개의 다른 비지니스 트랜잭션 부분이 교류하는 방식이

일반적인 마이크로서비스의 서비스 인터테이스가 된다.

 

  1. 비지니스 문제를 기술하고 그 문제를 기술하는데 사용된 명사에 주목하라
    반복되는 동일한 명사는 핵심 비지니스 영역의 키워드.
  2. 동사에 주목하라
    동사는 행위를 나타내고 이것은 여러 서비스가 어떻게 엮여서 동작하는지 상태를 알려준다.
  3. 데이터 응집성을 찾아라
    마이크로 서비스는 자기 데이터를 완전히 소유해야 한다.

비지니스 사용자의 대화에서 언급된 명사와 동사 분석

-> 주요 명사를 물리적 데이터 모델의 테이블로 매핑-> 논리 개체들의 단일 집합으로 매핑

-> 마이크로 서비스가 될 키워드 도출 (조직, 라이선스, 계약, 자산)

 

 

2 - 서비스 세분화의 확정

애플리케이션이 필요한 마이크로 서비스 정의하자.

목표는 서로 독립적으로 빌드 배포 가능한 유닛을 추출하는 것. self-contained unit

서비스가 접근하는 실제 db 테이블을 서비스에 따라 정리하고, 각 서비스가 특정 도메인의 테이블만 접근하게 함.

    (서비스가 자기 영역의 모든 데이터를 소유하는 것.)

 

  1. 큰 마이크로서비스에서 시작해 작게 리팩토링하는 것이 더 낫다.
    모든것을 작게 나누면 처음부터 너무 복잡해짐.
  2. 서비스 간 교류하는 방식에 먼저 집중한다.
    큰것을 작게 리팩토링 하는것이 더 쉬움.
  3. 문제 영역에 대한 이애가 깊어짐에 따라 서비스 책임도 계속 변한다.
    단일 서비스로 시작한다고 해도 점점 여러 서비스로 분화되며 성장함.

나쁜 마이크로서비스의 징후

- 너무 크게 나뉘어진 경우

  • 책임이 너무 많은 서비스
  • 많은 테이블의 데이터를 관리하는 서비스 (3-5개가 적당)
  • 과다한 테스트 케이스

- 너무 작게 나뉘어진 경우

  • 한 문제 영역 부분에 속한 마이크로서비스가 번식한다.(비지니스 로직을 만들기 복잡해짐.)
  • 서비스가 지나치게 상호 의존적이다 (하나의 요청을 완료하기위해 서로 계속 호출하는 경우)
  • 서비스가 단순한 CRUD 집합이 된다. (단순 데이터 조작으로서의 로직만 있음)

 

3 - 서비스 사이의 대화 : 서비스 인터페이스의 정의

  • REST 철학을 수용하라
    표준 HTTP 동사(GET, PUT, POST, DELETE..)
  • URI를 사용해 의도를 전달하라
    서비스의 엔드포인트, 자원을 기술하고 자원관계 기본 메커니즘 제공
  • 요청과 응답에 JSON을 사용하라
    초경량 데이터 직렬화 프로토콜
  • HTTP 상태 코드로 결과를 전달하라
    성공과 실패를 명시하는 표준응답코드를 일관되게 사용

 


2.2 마이크로서비스를 사용하지 않아야 할 떄

 

1 - 분산 시스템 구축의 복잡성

마이크로서비스 아키텍처에는 높은 수준의 운영 성숙도가 필요하다.

분산된 애플리케이션 관리하는 자동화, 모니터링, 확장 작업에 투자해야 성공적으로 마이크로서비스를 운영할 수 있다.

 

2 - 서버 스프롤 server sprawl

대규모 마이크로서비스 애플리케이션의 운영환겨아에서 필요한 서버와 컨테이너 수가 많아지므로
관리하고 모니터링하는 운영작업이 복잡해진다.

 

3 - 애플리케이션 유형

작고 단순한 애플리케이션이나 사용자 수가 적다면 분산구축이 복잡성만 더 크게 만듬.

 

4 - 데이터 변환과 일관성
여러 데이터 소스에서 복잡한 데이터를 취합하고 변환해야 할 경우 마이크로서비스의 분산된 특성 때문에 작업이 어려워짐.

또한 마이크로서비스 사이에 트랜잭션을 처리하는 표준이 없다. 트랜잭션 관리는 직접 만들어야함.

 

 


2.3 개발자 이야기: 스프링 부트와 자바로 마이크로서비스 생성

 

  1. 기본구조와 메이븐 스크립트로 애플리케이션 빌드
  2. 스프링 컨테이너를 시작할 스프링 부트스트랩 클래스 구현후 초기화 작업 시작
  3. 서비스 엔드포인트 매핑하는 컨트롤러 클래스 구현

EagleEye 도메인 모델에서 라이선싱 마이크로 서비스를 구축하면서 개발자의 우선순위를 살펴보자.

 

1 - 기본 골격 프로젝트로 시작

spring-boot-starter

spring-boot-starter-web

spring-boot-starter-actuator

java 1.8

spring-boot-maven-plugin

 

2 - 스프링 부트 애플리케이션 부팅 : Bootstrap 클래스 작성

@SpringBootApplication 스프링 부트가 애플리케이션을 시작하고 초기화 하는데 사용되는 클래스

main() 메서드에서 SpringApplication.run(Application.class, args) 호출은

스프링 컨테이너를 시작하고 스프링 ApplicationContext객체를 반환한다.

따라서 서비스 초기화를 위한 핵심 로직을 이 클래스에 두어야 한다.

 

3 - 마이크로서비스의 출입구 만들기 : 스프링 부트 컨트롤러

HTTP 요청 데이터를 이요청을 처리할 자바 메서드와 매핑.

POST, GET, PUT, DELETE 동사에 매핑되는 4개의 HTTP엔드포인트를 노출.

 

@RestController - REST 기반 서비스라 명시하고 요청 및 응답을 JSON으로 자동으로 직렬화 및 역직렬화

@RequestMapping - 최상위 URL 설정. HTTP 엔드포인트를 외부에 공개한다고 알리는데 사용.

@PathVariable -  URL에 전달된 값을 매개변수로 매핑.

 

서비스를 스타트한 후 노출되는 엔드포인트로 POSTMAN, CURL 을 이용해 접근해볼 수 있다.

 

엔드포인트 이름이 중요하다. 노출하는 엔드포인트에 대한 표준을 수립

- 서비스 의도, 관리하는 리소스, 서비스 안에서 관리되는 리소스 사이의 관계를 명확히 표현할 수 있어야 함.

  1. 서비스가 제공하는 리소스를 알 수 있는 명확한 URL 이름을 사용하라.
  2. 리소스 간 관계를 알 수 있는 URL을 사용하라
  3. URL 버전 체계를 일찍 세워라.
    - 일반적 패턴 중 하나는 모든 엔드포인트 앞에 버전 번호를 붙이는 것. 일찍 버전 체계를 갖추고 준비하자.

2.4 데브옵스 이야기 : 혹독한 런타임 구축

 

데브옵스 엔지니어에게 마이크로서비스 설계란 양산 이후의 서비스 관리에 관한 설계이다.

코드 작성보다 계속 동작하게 만드는것이 더 어렵다.

 

4가지 원칙

  1. 단일 소프트웨어 산출물을 사용해 여러 서비스 인스턴스를 시작하거나 제거 가능해야함. 자체완비 - 독립 배포 가능.
  2. 사람의 개입없이 구성가능.
  3. 위치 투명성. 물리적 위치를 모르나 애플리케이션이 알수 있게 service discovery agent와 통신.
  4. 자신의 상태 전달. 잘못된 서비스를 피해 라우팅 할 수 있도록.

12개의 모범 지침 참고

Heroku's Twelve-Factor Application manifesto https://12factor.net

 

 

마이크로서비스 수명주기의 여러 단계

 

 

1 - 서비스 어셈블리 : 마이크로서비스의 패키징과 배포

일관된 구축, 패키징 및 배포하는 과정.

내장 톰캣 엔진을 포함한 자바 JAR 실행 파일 빌드.

전체 산출물을 소스 제어하에 관리하고

내장형 런타임 엔진을 포함한 단일 산출물로 배포하면 구성편차 configuration drift 문제를 상당부분 해결한다.

 

2 - 서비스 부트스트래핑 : 마이크로서비스의 구성 관리

애플리케이션과 함께 배포된 property 파일에서 구성 데이터를 읽고 db 저장소에서 데이터를 읽어오는 작업.

서비스가 시작할 때 중앙의 구성 저장소에서 구성정보를 읽어온다.

구성 저장소는 모든 구성 변경을 버전 관리하고 변경 이력을 감시한다.

구성 정보가 변경되면 이전 구성으로 실행되는 서비스를 제거하거나 다시 읽어오도록 알려준다.

 

3 - 서비스 등록과 디스커버리 : 클라이언트가 마이크로서비스와 통신하는 방법

서비스를 일시적이며 폐기 가능한 객체로 취급하므로 

마이크로서비스 아키텍처는 많은 서비스 인스턴스를 실행하며 고수준의 확장성과 가용성을 얻을 수 있다.

일시적 서비스를 대량으로 관리하면서 장애가 발생할 수 있다.

따라서 서비스 디스커버리 에이젼트에 인스턴스를 등록하여 관리해야 한다.

서비스 디스커버리 에이젼트에 서비스 인스턴스 상태 확인 후 

서비스 클라이언트는 서비스 위치를 찾는다.

 

4 - 마이크로서비스의 상태 전달

등록된 각 서비스 상태를 모니터링하고

자신의 라우팅 테이블에서 문제가 된 서비스 인스턴스 제거한다.

REST 기반해서 JSON페이로드와 HTTP 상태코드 반환하는 HTTP 엔드포인트를 노출해 상태확인 인터페이스를 만들 수 있다.

개발자는 이런 서비스 상태를 제공할 엔드포인트를 작성해야한다.

스프링 actuator를 사용해 서비스 상태를 이해하고 관리할 수 있다.


2.5 모든관점에서

각 역할 관점의 핵심

  1. 아키텍트
    굵게 나뉜 마이크로서비스에서 시작해 작은서비스로 리팩토링. 
  2. 소프트웨어 엔지니어
    각 계층이 개별 책임을 맡는 계층적 서비스를 구축하는데 집중. 독립적인 서비스 지향.
  3. 데브옵스 엔지니어
    서비스 수명주기 수립. 빌드 배포 자동화. 상태 모니터링. 많은 경험과 사전 숙고가 필요한 임무.

2.6 요약

  • 마이크로 서비스 성공에는 아키텍트, 개발자, 데브옵스의 관점 통합이 있어야 함.
  • 모든 애플리케이션이 마이크로 서비스를 도입할 필요는 없다.
  • 아키텍트 관점에서 마이크로서비스는 작고 자체완비된 분산된 것. 좁은범위와 소규모 데이터를 관리함.
  • 개발자 관점에서 REST 설계방식과 서비스의 데이터 송수신을 위한 JSON을 사용해 구축.
  • 데브옵스 관점에서 패키징, 배포, 모니터링 하는 방법이 매우 중요.
  • 서비스를 하나의 JAR 실행파일로 전달.
  • 스프링 액추에이터는 서비스 런타임 정보와 운영상태 정보도 제공함.