스프링
마이크로서비스 코딩
공작소
2019.05.04
Chapter 2. 스프링부트 마이크로서비스 구축
2. SW 개발 정의
소프트웨어 개발은 정의와 실행 선형 과정이 아닌 개발팀이 당면한 문제를 제대로 이해하기까지 고객과 소통하고 고객에게 배우며 전달하는 활동을 반복하는 진화 과정이다.
2. 폭포수 개발 방법론의 한계
강한 결합 - 비즈니스 로직 호출은 SOAP, REST 같은 구현 기술에 중립적인 프로토콜 수준이 아닌 프로그래밍 언어 수준에서 이루어짐, 애플리케이션 컴포넌트를 조금만 수정해도 side effect 발생 확률 높음
누설 - 데이터가 같은 데이터 저장소 안에서 같은 데이터 모델을 유지하므로 다른 영역의 데이터에 의존성이 생기고 컴포넌트의 내부 데이터 구조에 대한 세부 구현이 애플리케이션 전체에 유출될 수 있음, 조금의 테이블 수정도 애플리케이션 전반에 걸쳐 수정, 테스팅 필요
모놀리식 - 컴포넌트는 여러 팀에서 공유되는 단일 코드베이스에 저장, 코드 변경할 때마다 전체 애플리케이션을 재컴파일, 전체 테스팅 후 배포, 애플리케이션 코드 베이스를 조금만 변경해도 비용과 시간이 많이 소모됨
2. 마이크로서비스 기반 아키텍처 특성
제한 - 하나의 책임 집합을 가지며 범위가 좁다
'애플리케이션이 한 가지 일을 하며, 정말 잘하는 서비스 집합에 불과하다'
느슨한 결합 - HTTP, REST처럼 비독점적 호출 프로토콜을 사용하는 구현 기술에 중립적인 인터페이스로 소통, 서비스에 대한 인터페이스가 변하지 않는한 자유로운 서비스 수정 가능
추상화 - 자신의 데이터 구조와 데이터 소스를 완전히 소유, 소유한 데이터는 해당 서비스만 구정 가능, DB에 해당 서비스만 접근하도록 통제
독립적 - 서로 독립적으로 컴파일하고 배포, 의존성이 없으므로 변경 사항을 쉽게 분리하고 테스트할 수 있음
2. 클라우드 기반 애플리케이션 특징
사용자층이 다양하며 대규모
고객마다 요구 사항이 다르며 빠르게 수정되기를 원함
상당한 작동 시간 요구
마이크로서비스 자체의 분산적 특성 때문에 애플리케이션 전체 중단 없이 고장과 문제를 더 쉽게 격리 가능하므로 작동 중지 시간은 줄고 결함 저항력은 높아짐
볼륨 불균형
전통적인 애플리케이션은 일정한 사용 패턴이 있고 용량 계획이 간단함, 클라우드 기반 애플리케이션 환경에서는 트위터의 트윗 한 줄이나 슬래시닷 포스팅 하나가 엄청난 수요를 불러올 수 있음
마이크로서비스는 컴포넌트가 분리되어 있으므로 부하를 받는 컴포넌트를 조명하고 여러 서버에 수평 확장이 쉬움
2. 마이크로서비스 개발 토대
아키텍트
애플리케이션을 개별 마이크로서비스로 분해하는 방법과 마이크로서비스의 상호 작용 방법을 이해하는 것
소프트웨어 개발자
코드를 작성하고 마이크로서비스를 제공하기 위해 프로그래밍 언어와 개발 프레임워크 사용 방법을 자세히 이해해야 함
데브옵스 엔지니어
운영 환경 및 비운영 환경에서 서비스 배포와 관리 방법 정보 제공
데브옵스 엔지니어의 좌우명은 모든 환경에서의 일관성과 반복성
2.1 마이크로서비스 아키텍처 설계
아키텍트가 집중해야 하는 일
1. 비즈니스 문제의 분해
2. 서비스 세분화의 확정
3. 서비스 인터페이스의 정의
아키텍트의 역할
- 해결해야 될 문제의 동작 모델 제공
- 개발자를 위한 발판 제공
2.1.1 비즈니스 문제의 분해
1. 비즈니스 문제를 기술하고 사용된 명사에 주목
동일한 명사가 반복해서 사용되면 핵심 비즈니스 영역과 마이크로서비스로 만들 기회가 드러남
마이크로 서비스 분해 지침
2. 동사에 주목
동사는 행위를 부각하고 문제가 되는 영역의 윤곽을 드러냄
3. 데이터의 응집성 찾기
마이크로서비스는 자기 데이터를 완전히 소유해야 한다. 다른 데이터를 읽거나 업데이트한다면 다른 서비스 후보로 고려
2.1.2 서비스 세분화의 확정
1. 큰 마이크로서비스에서 시작해 작게 리팩토링
문제 영역을 한 번에 작은 서비스들로 분해하는 것은 마이크로서비스가 단순한 데이터 서비스로 전락하므로 복잡함을 겪게됨
2. 서비스 간 교류하는 방식에 집중
문제 영역에 대한 큰 단위의 인터페이스를 만드는데 도움
3. 문제 영역에 대한 이해가 깊어짐에 따라 서비스 책임도 변함
마이크로서비스는 단일 서비스에서 시작해 여러 서비스로 분화되며 성장, 원래 서비스는 새로운 서비스들을 오케스트레이션하고 애플리케이션의 다른 부분에서 새 서비스들의 기능을 캡슐화
2.1.2 나쁜 마이크로서비스의 징후
1. 책임이 너무 많은 서비스
비즈니스 로직의 일반 흐름은 복잡하며 지나치게 다양한 종류의 비즈니스 규칙을 시행
2. 많은 테이블의 데이터를 관리하는 서비스
여러 테이블에 데이터를 저장하거나 직속 데이터베이스 외부의 테이블에 액세스한다면 서비스가 너무 크다는 것을 암시
3. 과다한 테스트 케이스
시간이 지나면서 서비스 크기와 책임이 증가, 수백 개의 단위 테스트와 통합 테스트 케이스로 늘어난다면 리팩토링 필요
마이크로서비스가 크게 나뉜 경우
2.1.2 나쁜 마이크로서비스의 징후
1. 한 문제 영역 부분에 속한 마이크로서비스가 번식
모든 것이 마이크로서비스로 되면 작업 수행에 필요한 서비스 개수가 엄청나게 증가해서 서비스에서 비즈니스 로직을 만드는 것이 복잡하고 어려워짐
2. 마이크로서비스가 지나치게 상호 의존적
문제 영역의 한 부분에 있는 마이크로서비스는 하나의 사용자 요청을 완료하기 위해 각 서비스가 서로 계속 호출
3. 마이크로서비스가 단순한 CRUD 집합
마이크로서비스는 비즈니스로직의 표현이지 데이터 소스의 추상화 계층이 아님
마이크로서비스가 잘게 나뉜 경우
2.1.3 서비스 인터페이스
1. REST 철학을 수용
서비스의 호출 프로토콜로 HTTP를 수용하고 표준 HTTP동사 (GET, PUT, POST, DELETE)를 사용
2. URI를 사용해 의도를 전달
서비스의 엔드포인트로 사용되는 URI는 문제 영역에 존재하는 다양한 자원을 기술하고 자원 관계에 대한 기본 메커니즘 제공
서비스 인터페이스 설계 지침
3. 요청과 응답에 JSON 사용
초경량 데이터 직렬화 프로토콜이며 XML보다 쉬움
4. HTTP 상태 코드로 결과 전달
HTTP 프로토콜에는 서비스의 성공과 실패를 명시하는 표준 응답 코드 존재, 상태코드를 익히고 모든 서비스에 일관된 사용이 중요
2.2 마이크로서비스를 사용하지 않아야 할 때
1. 분산 시스템 구축의 복잡성
2. 가상 서버/컨테이너의 스프롤
3. 애플리케이션 유형
4. 데이터 변환과 일관성
- 스프롤 : 활용도가 낮은 여러 서버가 실제 작업량보다 더 많은 공간과 리소스를 차지하는 현상
2.2.1 분산 시스템 구축의 복잡성
마이크로서비스 아키텍처에는 높은 수준의 운영 성숙도 필요
분산된 애플리케이션을 운영하는데 필요한 자동화와 운영 작업(모니터링, 확장)이 필수
2.2.2 서버 스프롤
대규모 마이크로서비스 기반 애플리케이션의 운영 환경에서만 구축 및 관리가 필요한 서버나 컨테이너가 50~100개 있을 수 있음, 서버를 관리하고 모니터링하는 운영 작업이 복잡해짐
- 마이크로서비스의 유연성은 모든 서버를 운영하는 데 드는 비용과 함께 따져야 함
2.2.3 애플리케이션 유형
마이크로서비스는 재사용성을 추구하며 높은 회복성과 확장성이 필요한 대규모 애플리케이션의 구축에 유용
부서 수준의 소형, 소수 사용자를 위한 애플리케이션에 마이크로 서비스를 사용하면 구축에 따른 복잡성 우려
2.2.4 데이터 변환과 일관성
- 마이크로서비스는 적은 수의 테이블을 둘러싸고 추상화
- 저장소에 단순한 질의 생성, 추가, 실행 등 운영상의 작업을 수행하는 메커니즘으로도 잘 동작
- 여러 데이터 소스에서 복잡한 데이터를 취합하고 변환하는 경우 분산된 특성 때문에 작업이 어려움, 과도한 책임을 떠안고 성능 문제 발생
- 마이크로서비스 사이에 트랜잭션 표준이 없음, 메시지를 사용해 통신 하는데 데이터를 업데이트할 떄 지연 시간 발생하므로 업데이트한 데이터가 즉시 나타나지 않을 수 있어 애플리케이션은 최종 일관성을 유지해야 함
2.3 스프링부트와 자바로 마이크로서비스 생성
엔드포인트 이름이 중요
1. 서비스가 제공하는 리소스를 알 수 있는 명확한 URL 이름을 사용
URL을 정의하는 데 표준 형식을 사용하면 API의 직관성과 사용 편의성이 향상
2. 리소스 간 관계를 알 수 있는 URL을 사용
리소스 간에 부모-자식 관계가 생길경우 URL을 사용해 표현
URL이 지나치게 길거나 중첩되면 리팩토링 고려
3. URL 버전 체계를 일찍 세워라
URL과 엔드포인트는 서비스 소유자와 서비스 서비자 간의 계약을 의미
소비자가 사용후 URL 버전 체계를 개량하는 것은 어려움
2.4 데브옵스 이야기
마이크로서비스 개발 원칙
1. 단일 소프트웨어 산출물을 사용해 여러 서비스 인스턴스를 시작하거나 제거할 수 있도록 자체 완비형이며 독립적으로 배포 가능 해야한다
2. 구성 가능해야 한다. 서비스 인스턴스가 시작될 때 구성에 필요한 데이터를 중앙에서 읽어 들이거나 환경 변수로 전달된 구성 정보를 받아야 한다. 서비스를 구성하는데 사람의 개입은 필요 없음
3. 클라이언트가 위치를 알지 못하도록 투명해야 한다. 클라이언트는 인스턴스의 물리적 위치를 모르더라도 애플리케이션이 알 수 있도록 서비스 디스커버리 에이전트와 통신해야 한다
4. 자신의 상태를 전달해야 한다.
2.4 데브옵스 이야기
표준 수명 주기 이벤트
서비스 어셈블리: 동일한 서비스 코드와 런타임을 정확히 같은 방식으로 배포하기 위해 반복성과 일관성을 보장하는 서비스 패키징과 배포방식
서비스 부트스트래핑: 사람이 개입하지 않고 인스턴스를 신속하게 시작, 배포하기 위해 애플리케이션과 환경별 구성 코드를 런타임 코드와 분리하는 방법은 무엇인가
서비스 등록 및 디스커버리: 새로운 인스턴스가 배포될 때 다른 애플리케이션 클라이언트가 발견할 수 있는 방법
서비스 모니터링: 데브옵스 관점에서 마이크로서비스 인스턴스를 모니터링하고 고장을 회피하는 라우팅과 비정상 서비스 인스턴스를 제거하는지 확인해야 한다
2.4 데브옵스 이야기
Twelve-Factor 마이크로서비스 애플리케이션 구축
코드베이스
의존성
구성
백엔드 서비스
빌드, 릴리스, 실행
프로세스
포트바인딩
동시성
폐기 가능
개발 및 운영 환경 일치
로그
관리 프로세스
2.4.1 서비스 어셈블리: 마이크로서비스의 패키징과 배포
애플리케이션의 환경 변화에 대응해 인스턴스를 신속하게 배포하기 위해선 필요한 의존성을 모두 담아 단일 산출물로 패키징하고 설치
서비스 어셈블리 : 일관된 구축, 패키징 및 배포하는 과정
2.4.2 서비스 부트스트래핑: 마이크로서비스의 구성 관리
마이크로서비스가 처음 가동할 때 시작하며 애플리케이션 구성 정보를 로드한다.
애플리케이션과 함께 배포된 프로퍼티 파일이나 RDB 같은 데이터 저장소에서 데이터를 읽어오는 작업
2.4.3 서비스 등록과 디스커버리:
클라이언트가 마이크로서비스와 통시하는 방법
마이크로서비스 소비자 관점에서 마이크로서비스는 위치 투명성을 가져야 한다. 클라우드 환경에서 서버는 일시적이기 때문이다.
서비스를 일시적이며 폐기 가능한 객체로 취급하므로 고수준의 확장성과 가용성을 얻을 수 있음
마이크로서비스 인스턴스는 제3자 에이전트에 등록하는 과정을 디스커버리라고 한다.
인스턴스의 물리적인 IP 주소 또는 도메인 주소와 애플리케이션이 서비스 검색에 사용할 논리적인 서비스 이름, 두 가지 정보를 에이전트에 전달
상태 확인을 하는 데 필요한 URL을 요구하기도 함
2.4.4 마이크로서비스의 상태 전달
서비스 디스커버리 에이전트는 클라이언트에 서비스 위치를 안내하고 등록된 각 서비스 상태를 모니터링 한다. 클라이언트가 고장 난 서비스를 호출하지 않도록 자신의 라우팅 테이블에서 문제가 된 서비스 인스턴스를 제거 한다.
REST 기반 마이크로서비스 환경에서 상태 확인 인터페이스를 만드는 가장 단순한 방법은 JSON 페이로드와 HTTP 상태 코드를 반환하는 HTTP 엔드포인트를 노출하는 것
spring actuator - 서비스 상태를 이해하고 관리하는 데 도움이 되는 엔드포인트를 기본 기능으로 제공
2.5 모든 관점에서
아키텍트
- 비즈니스 문제의 실제 윤곽을 잡음
- 비즈니스 문제 영역을 기술하고 이야기되는 스토리 경청
- 출현할 마이크로서비스 후보에 주시
- 굵게 나뉜 마이크로서비스에서 작은 서비스로 리팩토링
소프트웨어 엔지니어
- 서비스 안의 각 계층이 개별 책임을 맡는 계층적 서비스를 구축하는 데 집중
- 완전히 독립적인 마이크로서비스를 지향
- 미숙한 프레임워크 설계와 도입은 애플리케이션 수명 주기 후반에 막대한 유지보수 비용을 초래
2.5 모든 관점에서
데브옵스 엔지니어
- 서비스 수명 주기를 일찍 수립
- 서비스 빌드와 배포를 자동화
- 서비스 상태를 모니터링하고 문제가 발생할 때 대응
2.6 요약
- 마이크로서비스의 성공을 위해 아키텍트, 소프트웨어 개발자, 데브옵스 관점을 통합해야 한다.
- 마이크로서비스는 강력한 아키텍처 패러다임이지만 혜택과 장단점이 있다. 모든 애플리케이션이 마이크로서비스 애플리케이션일 필요는 없다.
- 아키텍트 관점에서 마이크로서비스는 작고, 자체 완비형이며 분산된 것이다. 마이크로서비스는 좁은 범위와 소규모 데이터를 관리한다.
- 개발자 관점에서 REST 설계 방식과 서비스의 데이터 송수신을 위한 JSON을 사용해 마이크로서비스를 구축한다.
- 데브옵스 관점에서 마이크로서비스를 패키징, 배포, 모니터링하는 방법은 매우 중요하다.
- 스프링 부트를 사용하면 서비스를 하나의 JAR 실행 파일로 전달할 수 있다. JAR 파일에 내장된 톰캣 서버가 서비스를 호스팅한다.
- 스프링 부트 프레임워크에 포함된 스프링 액추에이터는 서비스 런타임 정보와 함께 서비스의 운영 상태 정보도 제공한다.
스프링부트로 마이크로서비스 구축
By Sungbin, Song
스프링부트로 마이크로서비스 구축
- 111