Mastering Spring Cloud
00 서론
이 책은 개발자가 12 팩터를 기반으로하여 새로운 스프링 클라우드 기술을 기반으로 구축하고 하는 사용자를 위한 책입니다.
01 마이크로 서비스 소개
마이크로서비스의 장점
- 대규모 복잡한 애플리케이션도 션을 지속해서 배포하는 능력.
- 소스 코드 규모가 상대적으로 작아서 프로젝트에 새로 참여하는 개발자가 이해하기 쉬움.
- 분리가 쉬움.
스프링 프레임 워크로 마이크로 서비스 만들기
스프링 클라우드란 ? 서비스 레지스트리와 컨피규레이션 서버, 서킷 브레이커, 클라우드 버스, OAuth2 패턴, API Gateway 와 같은 마이크로서비스 기반 아키텍처에서 사용되는 모든 검증된 패턴을 구현 한것.
클라우드 네이티브 개발
클라우드 네이티브 어플리케이션이란? 클라우드 환경을 위해 잘 설계된 프로그램.
-
확장성과 신뢰성, 낮은 유지보수 비용.
- 모놀리식 어플리케이션을 무조건적으로 바꾼다 ? No, 비용면에서 혜택을 줄 수 있는것인지 확인해야함.
- 이로 개발된 어플리케이션은 피보탈 클라우드 파운드리나 도커에 쉽게 배포가 가능.
마이크로 서비스 아키텍처 배우기
모놀리식 어플리케이션이란? 하나의 어플리케이션에서 모든 코드를 관리하는 단일 구조의 어플리케이션.
- 기존의 하나의 코드안에서 큰 모듈로 관리 되던 부분이 각 마이크로서비스의 도메인으로 분리가능.
- 기존 클라이언트의 요청을 받던 부분은 API Gateway가 대체함.
- 각 도메인이 분리되면서 기존의 1개이던 데이터 소스도 각 도메인이 자신의 데이터 소스를 가지도록 변경됨.
서비스 디스커버리의 필요성 이해하기
서비스 디스커버리란? 컴퓨터 네트워크상의 디바이스가 제공하는 디바이스와 서비스를 자동으로 감지하는 서비스.
- 마이크로 서비스 아키텍처에서는 필수. Why? 각 도메인이 분리되고 배포도 각 도메인 안에서 진행되기 때문에 어느 부분으로 라우팅 되어야하는지에 대한 정보를 관리하는 부분이 필요함.
- 서비스 디스커버리를 서버 설정 기능과 함께 중앙에서 관리할수 있도록 만들 수도 있음.
서비스 간 통신
부하 분산기란? 클라이 언트로 들어온 요청을 처리할때 하나의 인스턴스로 요청이 몰리지 않도록 분산하는 서비스.
- 시스템의 신뢰성을 보장하려면 서비스가 최소 2개의 인스턴스로 유지가 필요함. Why? 장애를 방지하기 위해.
서비스를 나누는 기준
- One-to-One or One-to-Many : 서로의 요청이 단일인지 분산처리 되는지.
- Sync or Async : 응답을 바로 받는지 처리가 끝난 후 받는지.
- Publish And Subscribe : 메세지 기반의 처리. Ex) MQ, Kafka
장애와 서킷 브레이커
시스템을 아키텍팅 할때는 항상 장애에 대비해야함.
- 가장 좋은 방법은 응답을 기다릴 때의 네트워크 타임을 활용하여 응답이 오래걸리는 쓰레드에 에러코드를 반환할 수 있음.
- 서킷브레이커 패턴을 이용. 서킷브레이커란? 요청을 보내면서 실패와 성공 카운트를 세어 성공 카운트가 늘어나면 요청에 대한 처리를 하지만 실패 카운트가 일정 수치이상 증가하면 요청을 블로킹 처리하고 에러를 리턴함.
- 폴백(fall-back)을 이용 폴백 이란? 에러가 나는 상황에 에러가 아닌 기본적으로 에러라고 지칭할 수 있는 디폴트 값을 리턴함.
요약
- 스프링 클라우드의 가장 큰 장점은 모든 패턴과 매커니즘의 구현을 제공한다는 것.
- 마이크로 서비스는 태생적으로 클라우드 네이티브.
- 클라우드 네이티브로 이동하는 가장 큰 장점은 품질은 유지하면서 어플리케이션의 구현과 배포를 빠르게 할 수 있기 때문.
- 마이크로 서비스는 중앙에 무언가로 부터 관리됨.
02 마이크로서비스를 위한 스프링
스프링 부트 소개
스프링 부트란? 스프링 프레임워크를 더욱더 간편하고 쓸수 있도록 이니셜라이즈를 제공하며, 스프링 클라우드 내의 디펜던시와 버젼관리를 편하도록 도와줌. 독립 실행형 어플리케이션을 jave -jar로 실행함.
- spring-boot-starter를 통해서 모든 스프링 기반의 프로젝트 설정을 쉽게 할 수 있도록 도와줌.
- 다른 스프링 프레임워크를 역할에 맞도록 디펜던시를 쉽게 제공해주는 역할.
왜 마이크로 서비스에 적합한 것인가?
기존의 스프링 컨피규레이션은 웹 컨테이너를 포함하는 대신 WAR 형태로 웹 컨테이너에 배포를 함.
즉, 웹이 웹 도메인 외의 여러 WAR와 함께 웹 컨테이너에 배포됨으로써 독립성이 떨어졌기 때문에, 마이크로 서비스에서 단일 배포를 위해 도메인을 분리하기 힘듬.
스프링 부트를 이용해 어플리케이션 개발하기
- Initialize 를 이용
- 목적에 맞는 각 starter를 추가해서 내부의 디펜던시를 사용.
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
컨피규레이션 파일 사용자 정의하기
- spring.config.name / spring.config.location 설정을 오버라이드 함으로써 자신의 패스내에 다른 이름으로 존재하는 설정파일 로드가 가능
- 정의한 설정파일은 @Value 또는 @ConfigurationProperties를 통해 주입 가능
@ConfigurationProperties(prefix="{설정에서 지정한 이름}")
Public Class Config{
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
// this.servers = 설정파일에서 지정한 값을 리스트로 반환함.
return this.servers;
}
}
- properties, yml 사용 가능
RESTful 웹서비스 생성하기
- 기존의 @RequestMapping(method.Method.GET or POST or DELETE or PUT)을 각 분리된 어노테이션으로 사용가능(@GetMapping, @PostMapping, @DeleteMapping, @PutMapping)
- 바디가 리턴되는 컨트롤러에 대해서 기존의 @Controller&@ResponseBody대신 @RestController사용 가능.
- @RequestBody로 자신의 오브젝트 객체를 매핑하기위해 스프링부트는 루트에서 jackson 디펜던시를 의존하고 있음.
? SOAP(Simple Object Access Protocol) : XML 기반의 메세지를 주고받는 프로토콜
API 문서화
스웨거란? RESTful API를 설계하고 빌드하고 문서화 하기위해 가장 많이 사용되는 도구.
- swagger와 swagger ui를 디펜던시 추가
- @EnableSwagger2를 통해 사용 가능
- Docket빈의 정보를 기반으로 어플리케이션이 실행될때 자신의 API문서를 생성함
스프링 부트 액추에이터의 기능
스프링부트 액추에이터란? 모니터링과 메트릭 수집을 위해 사용하는 디펜던시.
상태정보
디스크의 사용량, 메일서비스 등을 모니터 할 수 있음.
매트릭스
힙과 힙이 아닌 메모리의 사용량을 알 수 있음. CounterService와 GaugeService를 통해서 메트릭 추가 가능.
@Service
public class PersonCounterService{
...
@Autowired
public PersonCounterService(CounterService counterService){
this.counterService = counterService
}
public void addPerson() {
this.counterService.increment("services.person.add");
}
...
}
어플리케이션 빌드하기
내장 데이터 베이스는 운영용이 아닌 개발 또는 단위테스트용.
운영에 배포가 나갈때는 실제 사용하려는 데이터 베이스를 별도로 셋팅하거나 인스턴스를 샤딩 클러스터로 구성해 연결하는 것이 좋다.
요약
스프링부트를 사용해서 어떻게 프로젝트를 셋팅하고 배포할 수 있는지에 대한 팁을 공유함.
03 스프링 클라우드 개요
기본부터 시작하기
스프링 클라우드는 원격 서버에서 컨피규레이션을 가저옴. 부트스트랩 컨텍스는 bootstrap.yml를 사용하며 일반적인 어플리케이션의 부모임. 일반적인 어플리케이션은 application.yml을 사용함.
부트스트랩 설정을 비활성화 하려면? spring.cloud.bootstrap.enable = false
넷플릭스 OSS
마이크로 서비스를 처음으로 성공적으로 도입한 회사. 스프링 클라우드를 기본으로 유레카, 히스트릭스, 리본, 주울 등을 통합함.
유레카를 사용한 서비스 디스커버리
- spring-cloud-stater-eureka 스타터를 사용.
- 클라이언트와 서버를 구분함.
- 클라이언트는 항상 어플리케이션의 일부로 서버에 연결하는 일을 담당함.
- 서버는 독립적인 스프링 부트 어플리케이션으로 실행됨.(spring-cloud-starter-eureka-server)
Zuul을 사용한 라우팅
- JVM 기반의 라우터이며, 서버측의 부하 분산이나 일부 필터링을 수행.
- Spring-cloud-starter-zuul을 사용.
Ribbon을 사용한 부하 분산
- TCP, UDP, HTTP 등 가장 유명한 프로토콜을 지원.
- 비동기 또는 리엑티브 모델도 지원함.
- Spring-colud-starter-ribbon을 사용
히스트릭스를 사용해 대기 시간 및 장애 내성 다루기
- 서킷브레이커 패턴을 구현함
- spring-cloud-starter-hystrix를 사용
디스커버리와 분산 컨피규레이션
Vault란? 토큰이나 패스워드, 자격 증명을 관리할 수 있는 해시코프에서 만든 오픈 소스 도구.
아파치 주키퍼
- 컨피규레이션과 이름을 쥬이하는 중앙 서비스로의 분산 동기화, 그룹서비스를 가능하게함.
- spring-cloud-starter-zookeepr-discovery를 사용
기타 프로젝트
- 쿠버네틱스 배포, 확장, 어플리케이션 컨테이너를 자동으로 관리하는 시스템. 컨테이너 오케스트레이션 및 서비스 디스커버리, 부하 분산 등의 기능 제공.
- 스프링 클라우드 에티시디(ETCD) 쿠버네틱스와 같이 분산 설정, 서비스 등록, 디스커버리를 제공하지만 쿠버네틱스 보다는 강력하지 않음.
메시징과 통합
-
스프링 클라우드 버스 : 컨피규레이션의 속성 변경이나 다른 명령등의 상태 변경을 이벤트로 어플리케이션에 알릴 수 있음.
-
스프링 클라우드 스트림 : 메세지 중심(MQ, Kafka)의 마이크로 서비스를 구현하기 위함. 11장 메시지 중심 마이크로 서비스에서 자세한 설명을 할 예정.
Publish/Subscribe구조는 해당 인스턴스의 갯수만큼 구독이 가능하기 때문에 그루핑 기능도 함께 제공함.
다른 유용한 라이브러리
- 보안 : spring-cloud-starter-security 를 통해서 싱글사인온, 토큰 리플레이와 같은 일반적인 패턴을 구현하는 시스템을 쉽게 개발 함.
릴리즈 트레인
하위 프로젝트의 혼란을 피하기 위해서 릴리즈 이름이 아니라 런던 지하철 역의 이름으로 구분함.
- M : Milestone
- X : Version Number
- SR(X) : Service Release - 중요한 버그 수정을 나타냄.
릴리즈 트레인을 사용하기 위해서는 아래와 같이 설정함.
dependencyManagement{
imports {
mavenBom: 'spring-cloud-dependencies:Finchley.M2'
}
}
요약
각 서비스 디스커버리, 분산 설정, 서킷브레이커를 어떻게 사용할 수 있고 어떤 특징을 가지고 있는지 알아봄.
04 서비스 디스커버리
Euraka란? 넷플릭스에서 디스커버리 서버를 지칭하는 말. 서버와 클라이언트로 구성되며, 서버는 주로 API의 수집과 등록을 담당하고 클라이언트는 서버의 등록, 해제 및 조회를 담당함.
서버 측에서 유레카 서버실행하기
- spring-cloud-starter-eureka-server 의존성 추가.
- Main Application에 @EnableEurekaServer 추가.
- 서버 스타터에는 클라이언트가 포함되어 있음으로, 분리를 위해서는 eureka.client.registerWithEureka와 eureka.client.fetchRegistry를 false로 지정한다.
클라이언트 측에서 유레카 활성화하기
- spring-cloud-starter-eureka 의존성 추가.
- 자신을 등록하고 호스트, 포트, 상태 정보, 홈페이지 URL을 보내거나 서버로 부터 데이터를 가져와 캐싱하는 일을 담당.
- @EnableDiscoveryClient(spring-common) 나 @EnalbeEurekaClient(netflix)로 활성화 시킴.
- 어플리케이션의 이름은 spring.application.name 속성을 통해 등록이 가능함.
종료 시 등록 해제
- 어플리케이션의 중단은 Graceful하게 발생되어야 함.
- 스프링 액추에이터의 /shutdown API를 사용함으로써 구현이 가능.
- 하지만 실제로는 서버 머신이 재시작하거나 어플리케이션 장애, 네트워크 문제 등 많은 문제가 발새할 수 있음.
- 이것을 피하기 위해 서버의 기본 설정을 변경해야함.
- Self-preservation mode는 자신의 서비스 상태를 갱신하지 않는 서비스가 일정 수를 넘으면 해제를 멈추는 것을 의미함. eureka.server.enableSelfPreservation속성의 값을 통해 비활성화가 가능함.
프로그램 방식으로 디스커버리 클라이언트 사용하기
DiscoveryClient 객체를 주입받아 해당 서버의 리스트를 가져올 수 있음.
@Autowired
private DiscoveryClient client;
public List<ServiceInstance> ping() {
return client.getInstances("CLIENT_SERVICE");
}
레지스트리 갱신하기
- Client
- 모든 클라이언트는 30초 마다 서버에게 자신의 생존여부를 알리는 Heartbeat를 보냄. eureka.instance.leaseRenealIntervalInSecond 속성으로 설정 가능.
- 등록을 해제하여 트래픽을 전달하지 않도록 함. eureka.instance.leaseExpirationdurationInSeconds 속성으로 설정 가능.
- Server
- 서버는 60초마다 Heartbeat가 수신되는지 확인. 즉, 임대를 만료하기까지 최악의 경우 60초까지 걸릴 수 있음.
- eureka.server.envictionIntervaltimerInMs 속성으로 설정 가능.
인스턴스 식별자 변경하기
인스턴스는 이름으로 묶임.
다음의 방법을 통해 일련변호를 사용하도록 식별자를 변경할 수 있음.
server:
port: 808${SEQUENCE_NO}
eureka:
instance:
instanceId: ${spring.application.name}-${SEQUENCE_NO}
IP 주소 우선하기
기본적으로 모든 인스턴스는 호스트명으로 등록됨.
유레카의 컨피규레이션 설정에서도 IP등록이 가능함. - eureka.instance.preferIpAddress를 true로 변경해야함.
다만, 머신에 하나 이상의 네트워크 인터페이스가 존재하는 경우 문제가 발생할 수 있으니 주의가 필요함.
이런 경우에는 제외 목록(spring.cloud.inetutils.ignoredInterfaces)이나 선호 목록(spring.cloud.inetutils.preferredNetworks)의 설정을 통해 관리가 가능함.
응답 캐시
- 유레카 서버 유레카 서버는 기본적으로 응답을 30초 동안 캐싱함. responseCacheUpdateIntervalMs 속성을 통해 캐시 시간을 설정할 수 있음.
- 유레카 클라이언트 유레카 클라이언트도 30초 동안 데이터를 캐싱함. registryFetchIntervalSeconds 속성을 통해 캐시 시간을 설정할 수 있음.
클라이언트와 서버 간의 보안 통신 사용하기
보안을 설정하는것이 개발에는 중요하지 않지만, 보안이 부족하면 문제가 될 수 있음.
스프링 클라우드 참조문서 에서는 “HTTP 기본 인증은 유레카 클라이언트에 자동으로 추가된다”고 했지만,
실제로는 security 스타터를 추가하고, 보안 활성화 설정을 해야함.
복제와 고가용성
디스커버리 서버를 1대로 운영해도 되지만, 운영인 경우 장애 상황에 대비해 최소 2대의 운영이 필요.
이런 경우 Peer To Peer 복제 모델에 기반하여 서로의 유레카 서버 사이의 통신을 함.
따라서 하나의 인스턴스에 연결되었던 유레카 서버가 장애가 발생하여도, 다른 유레카 서버와의 연결을 통해 서비스가 정상적으로 작동될 수 있음.
존(Zones)
단일 디스커버리 인스턴스에서도 eureka.client.serviceUrl.defaultZone 설정을 해야함.
요악
유레카의 서버와 클라이언트 설정을 통해 넷플릭스의 디스커버리 서버를 어떻게 설정하고 운영할 수 있는지 알수 있음.
05 스프링 클라우드 컨피그를 사용한 분산 컨피규레이션
기존에는 컨피규레이션을 JAR안에 포함해서 제공했기때문에, 컨피규레이션이 변경될 때마다 재빌드와 배포가 필요함. 하지만 이를 spring.config.location속성을 통해 원격에서 가져올 수 있도록 쉽게 구성이 가능함.
분산 컨피규레이션은 클라우드 네이티브 환경에서 가장 인기있는 표준 중 하나.
HTTP API 자원의 소개
컨피규레이션을 가져오기위한 여러 API가 존재함.
/{application}/{profile}/{label}
/{application}-{profile}.xml
/{label}/{application}-{profile}.xml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
- application : spring.application or config.name 으로 지정한 어플리케이션의 이름.
- profile: 현재 활성화 중인 모드.
- label: 옵셔널 밸류로써 git의 브랜치를 의미하며, default는 master브랜치.
네이티브 프로파일 지원
spring.profile.active옵션을 native로 하고 서버를 시작.
서버는 classpath:/, classpath:/config, file:./, file:./config에서 컨피규레이션파일을 찾음. 즉, yaml파일이 jar파일 안에 위치할 수 있음을 의미.
컨피규레이션을 서버로 옮기기로 했다면 어플리케이션 이름을 주의할 것. 어플리케이션 마다 주어질 설정 이름이 유일해야함.
서버 측 어플리케이션 개발하기
- spring-cloud-config-server 의존성 추가.
- @EnalbeConfigServer 어노테이션 추가.
- 기본 포트는 8888, client에서 접근하려는 포트도 8888이기 때문에 바꾸지 않는 것이 좋음. 바꾸려면 server.port의 값을 변경하거나 spring.config.name=configserver를 통해 해당 설정들을 configserver.yml에 오버라이드 할 수 있음.
클라이언트 측 어플리케이션 개발하기
- spring-cloud-starter-config 의존성 추가.
- application.yml을 bootstrap.yml로 바꿈.
- spring.profiles.active 옵션 값에 따라 해당하는 설정 파일을 가져올 수 있음.
유레카 서버 추가하기
클라이언트 속성에는 디스커버리 서비스의 내트워크 위치주소를 설정함. 즉, 컨피규레이션 서버가 작동하기 전에 유레카 서버가 먼저 실행중이어야함.
유레카는 서버가 시작할때 지정된 프로파일에 할당되는 컨피그를 컨피규레이션 서버로부터 가져옴.
06 마이크로서비스 간의 커뮤니케이션
07 고급 부하 분산 및 서킷 브레이커
08 API 게이트웨으를 사용한 라우팅과 필터링
09 분산 로깅과 추적
10 추가 컨피규레이션 및 디스커버리 기능
11 메시지 주도 마이크로 서비스
12 API 보안 강화하기
13 자바 마이크로서비스 테스팅
14 도커 지원
15 클라우드 플랫폼상의 스프링 마이크로서비스
출처
마스터링 스프링 클라우드 - 피요트르 민코프스키 지음(위키북스)