대규모 프로젝트에서 전통적으로 폭포수 waterfall 개발 방법론을 따르는 경향이 있었지만,
실제 개발과정에서 고객과 소통하을 반복하는 진화 과정을 따르므로 절저한 명세를 따르는 개발 방법론을 사용하기 어려워지며
여러가지 단점 또한 발생 하였다.
- 강한 결합
비지니스 로직 호출이 프로그래밍 언어 수준에서 이루어지므로 약간의 수정의 여파가 큼. - 누설
같은 데이터 저장소 안에서 같은 데이터 모델을 유지하는 방식은 쉽게 데이터 접근이 가능해 의존성이 생겨나
데이터베이스 구조를 변경하기 쉽지 않다. - 모놀리식
여러 팀에서 공유되는 단일 코드 베이스에 저장되므로 추가 수정사항에도 전체 컴파일과 배포를 해야한다.
반면 마이크로 서비스 기반 아키텍처의 특성은
- 제한
하나의 책임을 가지며 범위가 좁다. - 느슨한 결합
MSA는 작은 서비스 집합으로 HTTP와 REST 호출 프로토콜 사용.
서비스에 대한 인터페이스가 변하지 않는한 서비스를 자유롭게 수정할 수 있다. - 추상화
마이크로서비스가 소유한 데이터는 해당 서비스만 수정할 수 있다. - 독립적
서로 독립적으로 컴파일하고 배포할 수 있다. 변경사항을 쉽게 분리하고 테스트 가능.
클라우드 기반 애플리케이션의 일반적 특징
- 사용자 층이 다양하며 대규모이다
작은 범위의 명확한 인터페이스를 통해 원하는 기능만 신속하게 제공. - 상당한 작동시간 uptime 이 요구된다
애플리케이션 전체를 중단하지 않고도 장애를 더 쉽게 격리.
작동중지시간 downtime 은 줄고 결함 저항력은 높아짐. - 볼륨이 균일하지 않다
부하를 받는 컴포넌트를 여러 서버에 수평 확장하기 쉽다.
성공적인 마이크로서비스 개발토대. 중요한 세 역할의 관점.
- 아키텍트
큰 그림을 보고 개별 마이크로서비스로 분해, 상호작용하는 방법을 이해하는 것. - 소프트웨어 개발자
프로그래밍 언어와 프레임워크 사용방법의 이해. - 데브옵스 엔지니어
운영환경 및 비운영환경에서 서비스 배포와 관리방법 정보 제공.
모든 환경에서의 일관성 광 반복성이 중요.
2.1 아키텍트의 이야기 : 마이크로서비스 아키텍처 설계
1 - 비즈니스 문제의 분해
아키텍트는 비지니스를 영역을 나눠 분해하고 연관된 규칙과 데이터 로직을 그 안에 캡슐화 한다.
그리고 데이터 영역이 어울리지 않으면 서비스 경계를 나눈다.
2개의 개별 데이터 영역이 있다면 2개의 다른 비지니스 트랜잭션 부분이 교류하는 방식이
일반적인 마이크로서비스의 서비스 인터테이스가 된다.
- 비지니스 문제를 기술하고 그 문제를 기술하는데 사용된 명사에 주목하라
반복되는 동일한 명사는 핵심 비지니스 영역의 키워드. - 동사에 주목하라
동사는 행위를 나타내고 이것은 여러 서비스가 어떻게 엮여서 동작하는지 상태를 알려준다. - 데이터 응집성을 찾아라
마이크로 서비스는 자기 데이터를 완전히 소유해야 한다.
비지니스 사용자의 대화에서 언급된 명사와 동사 분석
-> 주요 명사를 물리적 데이터 모델의 테이블로 매핑-> 논리 개체들의 단일 집합으로 매핑
-> 마이크로 서비스가 될 키워드 도출 (조직, 라이선스, 계약, 자산)
2 - 서비스 세분화의 확정
애플리케이션이 필요한 마이크로 서비스 정의하자.
목표는 서로 독립적으로 빌드 배포 가능한 유닛을 추출하는 것. self-contained unit
서비스가 접근하는 실제 db 테이블을 서비스에 따라 정리하고, 각 서비스가 특정 도메인의 테이블만 접근하게 함.
(서비스가 자기 영역의 모든 데이터를 소유하는 것.)
- 큰 마이크로서비스에서 시작해 작게 리팩토링하는 것이 더 낫다.
모든것을 작게 나누면 처음부터 너무 복잡해짐. - 서비스 간 교류하는 방식에 먼저 집중한다.
큰것을 작게 리팩토링 하는것이 더 쉬움. - 문제 영역에 대한 이애가 깊어짐에 따라 서비스 책임도 계속 변한다.
단일 서비스로 시작한다고 해도 점점 여러 서비스로 분화되며 성장함.
나쁜 마이크로서비스의 징후
- 너무 크게 나뉘어진 경우
- 책임이 너무 많은 서비스
- 많은 테이블의 데이터를 관리하는 서비스 (3-5개가 적당)
- 과다한 테스트 케이스
- 너무 작게 나뉘어진 경우
- 한 문제 영역 부분에 속한 마이크로서비스가 번식한다.(비지니스 로직을 만들기 복잡해짐.)
- 서비스가 지나치게 상호 의존적이다 (하나의 요청을 완료하기위해 서로 계속 호출하는 경우)
- 서비스가 단순한 CRUD 집합이 된다. (단순 데이터 조작으로서의 로직만 있음)
3 - 서비스 사이의 대화 : 서비스 인터페이스의 정의
- REST 철학을 수용하라
표준 HTTP 동사(GET, PUT, POST, DELETE..) - URI를 사용해 의도를 전달하라
서비스의 엔드포인트, 자원을 기술하고 자원관계 기본 메커니즘 제공 - 요청과 응답에 JSON을 사용하라
초경량 데이터 직렬화 프로토콜 - HTTP 상태 코드로 결과를 전달하라
성공과 실패를 명시하는 표준응답코드를 일관되게 사용
2.2 마이크로서비스를 사용하지 않아야 할 떄
1 - 분산 시스템 구축의 복잡성
마이크로서비스 아키텍처에는 높은 수준의 운영 성숙도가 필요하다.
분산된 애플리케이션 관리하는 자동화, 모니터링, 확장 작업에 투자해야 성공적으로 마이크로서비스를 운영할 수 있다.
2 - 서버 스프롤 server sprawl
대규모 마이크로서비스 애플리케이션의 운영환겨아에서 필요한 서버와 컨테이너 수가 많아지므로
관리하고 모니터링하는 운영작업이 복잡해진다.
3 - 애플리케이션 유형
작고 단순한 애플리케이션이나 사용자 수가 적다면 분산구축이 복잡성만 더 크게 만듬.
4 - 데이터 변환과 일관성
여러 데이터 소스에서 복잡한 데이터를 취합하고 변환해야 할 경우 마이크로서비스의 분산된 특성 때문에 작업이 어려워짐.
또한 마이크로서비스 사이에 트랜잭션을 처리하는 표준이 없다. 트랜잭션 관리는 직접 만들어야함.
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 을 이용해 접근해볼 수 있다.
엔드포인트 이름이 중요하다. 노출하는 엔드포인트에 대한 표준을 수립
- 서비스 의도, 관리하는 리소스, 서비스 안에서 관리되는 리소스 사이의 관계를 명확히 표현할 수 있어야 함.
- 서비스가 제공하는 리소스를 알 수 있는 명확한 URL 이름을 사용하라.
- 리소스 간 관계를 알 수 있는 URL을 사용하라
- URL 버전 체계를 일찍 세워라.
- 일반적 패턴 중 하나는 모든 엔드포인트 앞에 버전 번호를 붙이는 것. 일찍 버전 체계를 갖추고 준비하자.
2.4 데브옵스 이야기 : 혹독한 런타임 구축
데브옵스 엔지니어에게 마이크로서비스 설계란 양산 이후의 서비스 관리에 관한 설계이다.
코드 작성보다 계속 동작하게 만드는것이 더 어렵다.
4가지 원칙
- 단일 소프트웨어 산출물을 사용해 여러 서비스 인스턴스를 시작하거나 제거 가능해야함. 자체완비 - 독립 배포 가능.
- 사람의 개입없이 구성가능.
- 위치 투명성. 물리적 위치를 모르나 애플리케이션이 알수 있게 service discovery agent와 통신.
- 자신의 상태 전달. 잘못된 서비스를 피해 라우팅 할 수 있도록.
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 모든관점에서
각 역할 관점의 핵심
- 아키텍트
굵게 나뉜 마이크로서비스에서 시작해 작은서비스로 리팩토링. - 소프트웨어 엔지니어
각 계층이 개별 책임을 맡는 계층적 서비스를 구축하는데 집중. 독립적인 서비스 지향. - 데브옵스 엔지니어
서비스 수명주기 수립. 빌드 배포 자동화. 상태 모니터링. 많은 경험과 사전 숙고가 필요한 임무.
2.6 요약
- 마이크로 서비스 성공에는 아키텍트, 개발자, 데브옵스의 관점 통합이 있어야 함.
- 모든 애플리케이션이 마이크로 서비스를 도입할 필요는 없다.
- 아키텍트 관점에서 마이크로서비스는 작고 자체완비된 분산된 것. 좁은범위와 소규모 데이터를 관리함.
- 개발자 관점에서 REST 설계방식과 서비스의 데이터 송수신을 위한 JSON을 사용해 구축.
- 데브옵스 관점에서 패키징, 배포, 모니터링 하는 방법이 매우 중요.
- 서비스를 하나의 JAR 실행파일로 전달.
- 스프링 액추에이터는 서비스 런타임 정보와 운영상태 정보도 제공함.
'IT Book Summary > 스프링 마이크로 서비스 코딩공작소' 카테고리의 다른 글
Chapter 07 마이크로서비스의 보안 (0) | 2020.08.11 |
---|---|
Chapter 05 나쁜상황에 대비한 스프링 클라우드와 넷플릭스 히스트릭스의 클라이언트 회복성 패턴 (0) | 2020.07.27 |
Chapter 04 서비스 디스커버리 (0) | 2020.07.23 |
Chapter 03 스프링 클라우드 컨피그 서버로 구성 관리 (0) | 2020.07.06 |
Chapter 01 (0) | 2020.06.22 |