SlideShare a Scribd company logo
1 of 111
Download to read offline
Spring Cloud Workshop

SK planet

개발혁신팀 

윤용성(Yongsung Yoon)
시작하기에 앞서…
실습에 사용 되는 모든 코드는 아래의 주소에 있습니다.
https://github.com/yongsungyoon/spring-cloud-
workshop
시작하기에 앞서…
오늘 실습의 완성된 코드는 master branch에 있습니
다.

실제 실습은 별도 Branch에서 진행합니다.
특정 단계에서 실습에 못 따라 오시더라도 각 단계별로 `tag`
를 부여해 놨으니 막바로 Checkout해서 시작하시면 됩니다.
Presentation 우측 상단에 `tag`이름이 해당 단계
실습 완료 코드가 들어있어 있는 곳입니다.
Tag : step-0
이 발표의 목적은…
Spring Cloud의 가장 핵심이 되는 개념을 실습을 통해 정확하
게 이해하는 것
Spring Cloud의 주요 요소를 당장 자신의 Project에 적용할 수
있게 도와드리는 것
Project Vine
11st Legacy Application 개선 Project
Strangler Application Pattern
열대 우림 지역의 Stranger Vine에서 유래

Legacy 교살 전략

새로운 Application 은 독립된 API 서버로

Legacy와 함께 운영

위의 과정을 반복
Application
Modernization
Strategy
“Strangler Application”
by Martin Fowler
Strangler Application Pattern in 11st - Hybrid MSA
WAR
Front/Mobile
WAS
WAR
Front/Mobile
WAS
REST

API
Zuul
API Gateway
전시
API
Server
상품
API
Server
추천
API
Server
추천
Service
XXX
API
Server
…
Eureka Server
Config Server
Admin Server
?
Challenges
Best Practice - Netflix OSS & Spring Cloud
Hystrix
Eureka
Ribbon
EvCache
Spectator
Archaius
….
Spring Cloud
….
Config
Stream
Sleuth
Contract
….
Step-1 : Hystrix
Circuit Breaker
Hystrix - Circuit Breaker
public String anyMethodWithExternalDependency() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand
Hystrix 적용하기
위의 메소드를 호출할 때 벌어지는 일
- 이 메소드 호출을 'Intercept' 하여 “대신” 실행 - 대신 ??
- 실행된 결과의 성공 / 실패 (Exception) 여부를 기록하고 “통계”를 낸다. -
통계 ??
- 실행 결과 “통계”에 따라 Circuit Open 여부를 판단하고 필요한 “조치”를 취
한다. 조치 ??
Hystrix - Circuit Breaker
Circuit Open ??
- Circuit이 오픈된 Method는 (주어진 시간동안) 호출이 “제한”되며, “즉시”
에러를 반환한다.
Why ?
- 특정 메소드에서의 지연 (주로 외부 연동에서의 지연)이 시스템 전체의 Resource
를 (Thread, Memory등)를 모두 소모하여 시스템 전체의 장애를 유발한다.
- 특정 외부 시스템에서 계속 에러를 발생 시킨다면, 지속적인 호출이 에러 상
황을 더욱 악화 시킨다.
So !
- 장애를 유발하는 (외부) 시스템에 대한 연동을 조기에 차단 (Fail Fast) 시킴
으로서 나의 시스템을 보호한다.
기본 설정
- 10초동안 20개 이상의 호출이 발생 했을때 50% 이상의 호출에서 에러가 발
생하면 Circuit Open
Hystrix - Circuit Breaker
public String anyMethodWithExternalDependency() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand
이제 이 메소드가 호출된다면 ?
- 이 메소드는 'Intercept' 되어 별도의 Hystrix Thread Pool에서 “대신” 실행 된다.
- 메소드 내부에서 발생한 Exception의 횟수는 Circuit Breaker 내에서 통계
가 내어진다.
- Circuit Open 조건에 도달하면 Circuit이 Open되어 호출이 차단 된다.
* 가장 기본적인 Circuit Breaker 개념 적용 완료 !
Hystrix - Circuit Breaker
- 기본 설정으로는 유사한 일을 하는 두개의 메소드가 별도의 Circuit Breaker를
갖게된다.

public String anyMethodWithExternalDependency1() {
URI uri = URI.create("http://172.32.1.22:8090/recommend");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand
public String anyMethodWithExternalDependency2() {
URI uri = URI.create("http://172.32.1.22:8090/mainrecommend");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand
Circuit Breaker는 어떤 단위로 생성되는가 ?
- Default로 @HystrixCommand가 명시된 메소드 단위
Hystrix - Circuit Breaker
Circuit의 단위 명시하기 - CommandKey
- “CommandKey”는 Circuit Breaker의 단위이며 여러개의 메소드를 같은
Key를 명시함으로써 하나의 Circuit을 사용하게 할 수 있다.
public String anyMethodWithExternalDependency1() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand(commandKey = “ExtDep1”)
public String anyMethodWithExternalDependency2() {
URI uri = URI.create("http://172.32.1.22:8090/mainrecommend");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand(commandKey = “ExtDep1”)
- 즉, A 메소드와 B 메소드가 같은 Circuit Breaker를 사용한다면, A
와 B의 에러 비율이 함께 통계내어지고, Circuit이 오픈되면 함께 차
단된다.
Hystrix - Circuit Breaker
public String anyMethodWithExternalDependency1() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
public String recommendFallback() {
return “<미리 준비된 상품 목록>”;
}
@HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”)
Hystrix의 또 하나의 중요한 개념 - Fallback
- Fallback method는 Circuit이 오픈된 경우 혹은 Exception이 발생한 경우
대신 호출될 Method. 

- 오류 발생시 Exception 대신 응답할 Default 구현을 넣는다.
Hystrix - Circuit Breaker
오랫동안 응답이 없는 메소드에 대한 처리 방법은 ?
- 특정 메소드의 총 소요시간에 대한 Timeout을 직접 관리/예측하는 것은 매우 힘들다

- ex) Socket Connect/Read Timeout, JDBC Timeout, 3rd Party 라이브러디
등
- 설정하지 않으면 default 1,000ms 

- 물론 이경우에도 Fallback이 있다면 Fallback을 수행
Hystrix에서는 Circuit Breaker별로 Timeout 설정 가능
- 해당 메소드가 설정된 시간안에 안 끝나면 Timeout으로 인한 Exception 자
동 발생
Hystrix - Circuit Breaker
public String anyMethodWithExternalDependency1() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
public String recommendFallback() {
return "No recommend available";
}
@HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”,
commandProperties = {
@HystrixProperty(name =
"execution.isolation.thread.timeoutInMilliseconds", value = "500")
})
오랫동안 응답이 없는 메소드에 대한 처리 방법은 ? - Timeout
- 실습에서는 yml로 설정하겠습니다.
[실습] 프로젝트 import
1. 실습 시작 시점으로 Git 이동
> git checkout -b step-0
Tag : step-0
2. IntelliJ에서 build.gradle import
File > Open - root 폴더 build.gradle 선택 - Open as Project
[실습] 프로젝트 import
3. Import Project from Gradle
Tag : step-0
주의
[실습] 소스 살펴 보기
1. 전체 구조
request : /products/{productId}
response : "[product id = " + productId +
" at " + System.currentTimeMillis() + "]";
Tag : step-0
Display

(8081)
Product

(8082)
request : /displays/{displayId}
response : "[display id = %s at %s %s ]"
,displayId
,System.currentTimeMillis()
,/products/12345의 응답
localhost:8081/displays/{displayId} localhost:8082/products/12345
[실습] Rest API로 Display -> Product 연동
1. 프로젝트 구조 보기
Tag : step-0
2. Display -> Product 호출
3. Display / Product 실행
- Product 동작 확인 : http://localhost:8082/products/22222    

- Display 동작 확인 :http://localhost:8081/displays/11111
Step-1 : Hystrix 사용하기
실습
[실습 Step-1] Hystrix
배경
Display 서비스는 외부 Server인 Product API와 연동되어있음
Product API에 장애가 나더라도 Display의 다른 서비스는 이상없이 동작하
였으면 합니다
Product API에 응답 오류인경우, Default값을 넣어 주고 싶습니다
결정 내용
Display -> Product 연동 구간에 Circuit Breaker를 적용 !
[실습 Step-1] Hystrix 사용하기
Tag : step-1-hystrix-basic
1. [display] build.gradle에 hystrix dependency추가
compile('org.springframework.cloud:spring-cloud-starter-hystrix’)
2. [display] DisplayApplication에 @EnableCircuitBreaker추가
@EnableCircuitBreaker
3. [display] ProductRemoteServiceImp에
@HystrixCommand 추가
@HystrixCommand
[실습 Step-1] Hystrix Fallback 적용하기
Tag : step-1-hystrix-fallback
4. [product] ProductController에서 항상 Exception 던지게 수
정하기 (장애 상황 흉내)
throw new RuntimeException(“I/O Error”)
5. [display] ProductRemoteServiceImp에 Fallback Method
작성하기
[실습 Step-1] Hystrix Fallback 적용하기
Tag : step-1-hystrix-fallback
6. 확인
http://localhost:8082/products/22222   
http://localhost:8081/displays/11111
Hystrix가 발생한 Exception을 잡아서 Fallback을 실행 

Fallback 정의 여부와 상관없이 Circuit 오픈 여부 판단을 위한 `에
러통계`는 계산하고 있음

아직, Circuit이 오픈된 상태 X
[실습 Step-1] Hystrix Fallback 적용하기
Tag : step-1-hystrix-fallback2
7. Fallback 원인 출력하기
Fallback 메소드의 마지막 파라매터를 `Throwable`로 추가하면
Fallback 일으킨 Exception을 전달 해줌
[실습 Step-1] Hystrix Fallback 적용하기
Tag : step-1-hystrix-fallback2
8. 정리
Hystrix에서 Fallback의 실행 여부는 Exception이 발생 했는가 여부
Fallback의 정의 여부는 Circuit Breaker Open과 무관
Throwable 파래매터의 추가로 Fallback 원인을 알 수 있다.
[실습 Step-1] Hystrix로 Timeout 처리하기
Tag : step-1-hystrix-timeout
Hystrix로 할 수 있는 또 한가지 ! Timeout 처리
@HystrixCommand로 표시된 메소드는 지정된 시간안에 반환되지 않
으면 자동으로 Exception 발생 (기존 설정 : 1,000ms)
1. [product] ProductController의 throw Exception을
Thread.sleep(2000)로 수정
2. 확인 

Product API를 직접 호출하는 경우는 동작하나, Display는 동작 안함
t = com.netflix.hystrix.exception.HystrixTimeoutException
[실습 Step-1] Hystrix로 Timeout 처리하기
Tag : step-1-hystrix-timeout
3. [display] application.yml 수정하여 Hystrix Timeout 시간 조정하기
4. 다시 확인 

Product/Display 모두 동작
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
[실습 Step-1] Hystrix로 Timeout 처리하기
Tag : step-1-hystrix-timeout
5. 정리
Hystrix를 통해 실행 되는 모든 메소드는 정해진 응답시간 내에 반
환 되어야 한다.
그렇지 못한 경우, Exception이 발생하며, Fallback이 정의된 경
우 수행된다.
Timeout 시간은 조절할 수 있다. (Circuit 별로 세부 수정 가능하
며 뒷 부분에 설명)
언제 유용한가 ?
모든 외부 연동은 최대 응답 시간을 가정할 수 있어야 한다.

여러 연동을 사용하는 경우 최대 응답시간을 직접 Control하는
것은 거의 불가능하다 (다양한 timeout, 다양한 지연등..)
[실습 Step-1] Hystrix Circuit Open 테스트
Tag : step-1-hystrix-circuit-open
1. [display] application.yml 수정하여 Hystrix 프로퍼티 추가
기본 설정 (테스트 하기 힘들다)

- 10초동안 20개 이상의 호출이 발생 했을때 50% 이상의 호출에서 에러가 발생하면
Circuit Open
변경설정 

- h.c.d.circuitBreaker.requestVolumeThreshold : 1

- h.c.d.circuitBreaker.errorThresholdPercentage: 50
[실습 Step-1] Hystrix Circuit Open 테스트
Tag : step-1-hystrix-circuit-open
2. [product] ProductController 다시 수정하여 Exception 던지도록 수정
Thread.sleep(2000) 제거 - 테스트 편의

Throw new RuntimeException 복원 - Exception 발생으로
Circuit Open 유도하기 위해
[실습 Step-1] Hystrix Circuit Open 테스트
Tag : step-1-hystrix-circuit-open
3. 확인
http://localhost:8082/products/22222   
> Exception 발생 확인
http://localhost:8081/displays/11111
> 10초 이상 호출. Exception 메세지 변경되었나 확인
> Product Console 지운 후 Display 호출 및 확인
“Hystrix Circuit Short-Circuited and is OPEN”이 Display
에 출력되는 경우는 Product 콘솔에는 아무것도 찍히지 않는다.

-> Circuit Open (호출 차단)
[실습 Step-1] Hystrix Circuit Open 테스트
Tag : step-1-hystrix-circuit-open
4. 부가 설명
- Circuit Open 여부는 통계를 기반으로 한다.
- 최근 10초간 호출 통계
(execution.isolation.thread.timeoutInMilliseconds)

- 최소 요청 갯수 넘는 경우 만
(circuitBreaker.requestVolumeThreshold)

- 에러 비율 넘는 경우 

(circuitBreaker.errorThresholdPercentage)
- 한번 Circuit이 오픈되면 5초간 호출이 차단되며, 5초 경과후 단 “1개”
의 호출을 허용하며 (Half-Open), 이것이 성공하면 Circuit을 다시
CLOSE하고, 여전히 실피하면 Open이 5초 연장된다.

(circuitBreaker.sleepWindowInMilliseconds)
[실습 Step-1] Hystrix에서 Circuit Breaker의 단위는 ??
Circuit Breaker의 단위 ? 

- 에러 비율을 통계의 단위

- Circuit Open / Close가 함께 적용되는 단위

- 즉, A 메소드와 B 메소드가 같은 Circuit Breaker를 사용한다면, A와 B의 에러
비율이 함께 통계내어지고, Circuit이 오픈되면 함께 차단된다.
Circuit의 지정은 ?

- `commandKey`라는 프로퍼티로 지정 가능.

- @HystrixCommand에서는 지정하지 않는 경우 메소드 이름 사용

- 이렇게 사용하지 말것 !

- 메소드 이름은 겹칠 수 있으며, 나중에 나오는 Feign의 경우 또 다르기 때문에 헷
갈릴 수 있다. 

- 항상 직접 지정 해서 사용하기
[실습 Step-1] Hystrix에서 Circuit Breaker의 단위는 ??
Tag : step-1-hystrix-command-key
1. [display] `commandKey` 부여하기
2. [display] application.yml에 commandKey로 속성 지정해보기
`default` : global 설정. 이 위치에 `commandKey`값을 넣으면, 해당
Circuit Breaker에만 해당 속성 적용된다.
[실습 Step-1] Hystrix에서 Circuit Breaker의 단위는 ??
Tag : step-1-hystrix-command-key
3. 확인 - 각자 쉬는 시간에 (앞선 상태와 동일하게 동작해야 함)
Hystrix - Circuit Breaker
연동 

System A
Thread Pool
A

(20 threads)
Thread Pool
B

(10 threads)
Thread Pool
C

(15 threads)
Circuit
Breaker A
Circuit
Breaker B
Circuit
Breaker C
Circuit
Breaker D
Circuit
Breaker F
연동 

System B
연동 

System C
User Request
Hystrix를 쓴다는 것의 또다른 의미
- Hystrix를 통해 실행한다는 것은 별도의 Thread Pool에서 내 Code를 실행
한다는 것

- 각 Circuit Breaker는 한 개의 Thread Pool과 연동

- 하나의 ThreadPool을 여러 개의 Circuit Breaker가 공유할 수 있다.
Hystrix - Circuit Breaker
각 Circuit Breaker가 사용할 Thread Pool의 지정
- 내 시스템의 Resource가 다양한 기능(서비스)들을 위해 골고루 분배 될
수 있도록..

- Semaphore 방식의 Isolation도 있음

- 가벼움. Thread Isolation에 비해서 성능상 약간의 이득이 있음

- Timeout이 정확하게 동작하지 않음. (Blocking 호출등에 멈춰있는
경우 대기)
- 어느 하나 외부 Dependency (외부 연동 시스템)의 문제 발생시 그 영
향으로 부터 시스템의 다른 요소를 보호 - Isolation
- ThreadPoolKey (혹은 CommandGroupKey) 속성으로 지정

- 각 Thread Pool 별로 Max Thread 지정
Thread Pool을 사용하는 의미
소스 : https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a
가정

각 서버 별 가용성 : 99.99%

30개의 Dependency 존재
99.99% ^ 30 = 99.7%
Uptime = 1달 기준 2시
간
인용 : https://speakerdeck.com/benjchristensen/performance-and-fault-tolerance-for-the-netflix-api-august-201
Hystrix - Circuit Breaker
동시에 실행될 수 있는 Command의 갯수 제한 - ThreadPool 설정
- HystrixCommand로 선언된 Method는 default로 호출한 Thread가 아닌
별도의 ThreadPool에서 “대신” 실행된다. 

- ThreadPool에 대한 설정을 하지 않으면 Default로는 @HystrixCommand
가 선언된 클래스 이름이 ThreadPool 이름로 사용된다.
public class MySerice {
@HystrixCommand(commandKey = “serviceA”)
public String anyMethodWithExternalDependency1() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
@HystrixCommand(commandKey = “serviceB”)
public String anyMethodWithExternalDependency2() {
URI uri = URI.create(“http://172.32.2.33:8090/search");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
}
- 위의 같은 경우 두개의 메소드는 각각 Circuit Breaker를 갖지만, 두개의
Command가 “MyService”라는 하나의 ThreadPool에서 수행됨.
Hystrix - Circuit Breaker
ThreadPool 직접 설정하는 방법 - CommandGroupKey
public String anyMethodWithExternalDependency1() {
URI uri = URI.create("http://172.32.1.22:8090/recommended");
String result = this.restTemplate.getForObject(uri, String.class);
return result;
}
public String recommendFallback() {
return "No recommend available";
}
@HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”,
commandGroupKey = “Myservice1”)
- @HystrixCommand 별로 사용할 Thread Pool을 명시적으로 지정할 수
있다. - CommandGroupKey
- 같은 외부 Dependency가 있는 Method들을 하나의 ThreadPool을 사용
하도록 Grouping 하는 것이 가능
Hystrix - Circuit Breaker
ThreadPool의 세부 옵션 설정
@HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”,
commandGroupKey = “Myservice1”, commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
value = "500")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "101"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value =
"1440")
}
- Hystrix에 관한 모든 세부 옵션 : https://github.com/Netflix/Hystrix/
wiki/Configuration
- ThreadPool의 기본 사이즈는 10이므로 적용시 필히 상향 여부 검토 필요
Hystrix - Circuit Breaker
Project에 적용 하기
- Spring Boot 프로젝트인 경우

- Spring Cloud Dependency 추가 와 @EnableHystrix 주석 

- Spring 프로젝트인 경우 혹은 AOP 사용 가능한 경우

- Netflix Hystrix-Javanica

- https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica

- 기타 Java Project인 경우

- (Pure) Netflix Hystrix

- 주석 없이 Coding으로 가능

- https://github.com/Netflix/Hystrix
Step-2 : Ribbon
Client Load Balancer
> git checkout tags/step-2-baseline -b my-step-2
* 앞선 예제 못따라 오신 분들이나, 늦게 참여하신 분들은 막바로 Git 이동
Server Side Load Balancer (with L4 Switch)
Client

(Caller)
Server1
Server2
Server3
Server4
L4
Switc
h
- 일반적인 L4 Switch 기반의 Load Balancing

- Client는 L4의 주소만 알고 있음

- L4 Switch는 Server의 목록을 알고 있음 (Server Side Load Balancer)
- H/W Server Side Load Balancer 단점 (장점도 있지만..)

- H/W가 필요 (비용↑, 유연성↓)

- 서버 목록의 추가를 위해서는 설정 필요 (자동화 어려움)

- Load Balancing Scheme이 한정적 (Round Robin, Sticky)
Client Side Load Balancer - Ribbon
Client 

(Caller)
Server1
Server2
Server3
Server4
- Client (API Caller)에 탑재되는 S/W 모듈

- 주어진 서버 목록에 대해서 Load Balancing을 수행함
- Ribbon의 장점 (단점도 있지만… )

- H/W가 필요 없이 S/W로만 가능 (비용↓, 유연성↑)

- 서버 목록의 동적 변경이 자유로움

- Load Balancing Scheme이 마음대로 구성 가능
R

i

b

b

o
Client Side Load Balancer - Ribbon
단순한 Load Balancer ?
ServerList - Load Balancing의 대상이될 Server 목록 결정
- 1) Configuration을 통해 직접 목록 설정

- 2) Discovery 기반으로 Runtime에 획득한 서버 목록 사용
IRule - 트래픽을 보낼 서버를 선택
- 1) Simple Round Robbin

- 2) Response Time Weighted - 서버별 응답 시간에 따라 트래픽 양 조절

- 3) Availability Filter

- 최근 3번 연속 에러를 발생시킨 서버를 Load Balancing 대상에서 일정
시간 동안 제외 시킴 (최초 5초, 4번째 실패시 10초. 2배씩 증가되며 최대
값이 기본 값 설정 가능)
Client Side Load Balancer - Ribbon
단순한 Load Balancer ?
IPing - 주기적으로 호출하여 해당 서버의 Aliveness를 검사
- 1) 특정 URL 호출

- 2) Discovery 기반 - Discovery 서버로 부터 가져온 목록에 있는지 확인

- Ping에 실패한 서버는 임시로 Load Balancing 대상에서 제외

ServerList, IRule, IPing 등 Ribbon의 주요 기능은 다양하게 설
정이 가능하며, 직접 구현하여 넣는 것도 가능
Client Side Load Balancer - Ribbon
Ribbon의 또 하나의 중요한 기능 - Retry
Client 

(Caller)
Server1
Server2
Server3
Server4
R

i

b

b

o

O
선택된 대상으로의 호출 실패 시 정해진 횟수 만큼의 Retry 설정 가능

- 같은 서버 재시도 횟수, 다른 서버 재시도 횟수 설정

- Exception 발생 경우 뿐만 아니라 재시도 할 HTTP Status 지정
가능
Client Side Load Balancer - Ribbon
How to Use
- 다양한 사용 방법이 존재…..

- 직접 API 호출하여 대상 서버/포트 획득 후 사용
다양한 Http Client 및 Server에 이미 내장되어 있음
- Spring `RestTemplate` 

- @LoadBalanced RestTemplate

- Spring Cloud Feign Client

- Declarative Http Client

- Ribbon이 내장되어 있음

- Zuul API Gateway

- Ribbon이 내장되어 있음
[실습 Step-2] RestTemplate에 Ribbon 적용하기
Tag : step-2-baseline
1. [product] ProductController 정상 코드로 복원
- 준비작업 (Application 정상화)

- Sleep 제거 / Throw Exception 제거
[실습 Step-2] RestTemplate에 Ribbon 적용하기
2. [display] build.gradle에 dependency 추가
- compile(‘org.springframework.cloud:spring-cloud-starter-
ribbon’)
잠시 대기 후 외부 라이브러리에 아래 확인
[실습 Step-2] RestTemplate에 Ribbon 적용하기
3. [display] DisplayApplication의 RestTemplate 빈에 @LoadBalanced 추가
[실습 Step-2] RestTemplate에 Ribbon 적용하기
4. [display] ProductRemoteServiceImpl에서 주소 제거하고
`product`로 변경
5. [display] application.yml에 ribbon 설정 넣기

Tag : step-2-ribbon-loadbalanced
- Ribbon의 기본은 eureka가 동작하므로 우선은 false (추후 설명)

- listOfServers에 서버 목록 추가
[실습 Step-2] RestTemplate에 Ribbon 적용하기
7. 확인

http://localhost:8081/displays/11111
동작 !!! 

RestTemplate에 주소가 아닌 단지 이름 `product`을 넣었는데 동작
Tag : step-2-ribbon-loadbalanced
[실습 Step-2] RestTemplate에 Ribbon 적용하기
8. 정리
Tag : step-2-ribbon-loadbalanced
- Ribbon 디펜던시 추가 후 RestTemplate에 `@LoadBalanced` 주석
- 설정에 특정 서비스(product)의 주소 설정
- RestTemplate 사용 시 주소 넣지 않고 서비스 이름(product) 사용
- 로드 발란스는 ???
[실습 Step-2] Ribbon의 Retry 기능
1. [display] build.gradle 보기
Ribbon에는 Retry 기능이 내장되어 있어 하나의 서버에서 실패하면 다
른 서버로 재시도 가능
spring-retry 가 필요
2. [display] application.yml에 retry 추가
Tag : step-2-ribbon-retry
* 현 시점의 Release에 default가 true이나 변경의 여지가
있어서 명시해 놓음
[실습 Step-2] Ribbon의 Retry 기능
3. [display] applicaiton.yml에 서버 주소 추가 및 Retry 관련 속성 조
정
Tag : step-2-ribbon-retry
4 확인

http://localhost:8081/displays/11111
localhost:7777은 없는 주소 이므로 Exception 발생. 그러나 Ribbon Retry로 항상 성
공

-> Round Robin Client Load Balancing & Retry
[실습 Step-2] Ribbon의 Retry 기능
5. 주의 

- Retry를 시도하다가도 HystrixTimeout이 발생하면, 즉시 에러 반환 리
턴할 것이다. (Hystrix로 Ribbon을 감싸서 호출한 상태이기 때문에)

- Retry를 끄거나, 재시도 횟수를 0으로 하여도 해당 서버로의 호출이 항
상 동일한 비율로 실패하지는 않는다. (IRule의 기본 구현에 의해 3회 실
패한 서버의 목록 제거)
Tag : step-2-ribbon-retry
6. 정리 

- Ribbon은 여러 Component에 내장되어있으며, 이를 통해 Client
Load Balancing이 수행 가능하다.

- Ribbon에는 매우 다양한 설정이 가능하다 (서버선택, 실패시 Skip
시간, Ping 체크) 

- Ribbon에는 Retry기능이 내장 되어있다.

- Eureka와 함께 사용될 때 강력하다 (뒤에 실습)
[실습 Step-2] Ribbon의 Retry 기능
Tag : step-2-ribbon-retry
7. 추가 정보 

- Ribbon의 Retry는 기본적으로 Spring-Retry를 사용하며,
Exception이 발생한 경우에 Retry가 시도됨

- Ribbon의 옵션으로 응답이 수신된 경우 특정 Status Code에 따라서
Retry를 시도하도록 설정하는 것도 가능

- ex) product.ribbon.retryableStatusCodes=502,503

- 현재 Release (Dalston.SR1)에 포함된 spring-cloud-
commons(1.2.2)에 버그로 인하여 @LoadBalanced
RestTemplate을 사용할 때 Status Code 기반의 Retry가 동작하
고 있지 앉음

- spring-cloud-commons 1.2.3에 수정될 예정이며
Dalston.SR2부터 지원될 예정
Step-3 : Eureka
Dynamic Service Discovery
MSA를 적용한다고 하나의 서버를 여러개의 API 서버로 분할했는데… 

- 수많은 API 서버의 IP Address와 Port 번호는 어떻게 Caller에게 전달하
지 ? 

- L4도 없이 Client Load Balancer를 사용하는데, 각 Ribbon 설정에 언제
서버 주소와 포트 번호를 설정하지 ?
서버 분할 후 고민…
“서버가 새롭게 투입되면 그것을 감지하여 목록에 자동으로 추가되고,
서버가 종료되면 자동으로 목록에서 삭제하기 위한 방법은 없을까 ?”
“API를 호출하는 쪽에서도 상대방 주소(들)을 알 필요 없이 이름 만으
로 호출하게 할 수는 없을까 ? ”
Dynamic Service Discovery - Eureka
API Server “A”
Eureka

Client
Eureka Server
Service A ip1:8081
Service B
Service C
Service D
API Caller “가”
Eureka

Client
0. Eureka를 사용할 모든 Server에 Eureka Client 탑재
주기적으로 Fetch
②
2. Eureka Client는 주기적으로 Service별 IP 목록을
Fetch 보관
서버 시작시 - 등록 / 종료시 - 제거
IP주소:port:”Service A”
①
1. 서버 가동시 자신의 정보(ip/port/서비스명)을
Eureka Server에 등록 (반대로 종료시 삭제)
③
Eureka에 획득한 주소로 호
출
3. API 호출시 서비스 이름 (Service A)를 사용하여 해당
서버 목록 획득 후 호출
Dynamic Service Discovery - Eureka
API Server “A” - instance #1
Eureka

Client
Eureka Server
Service A ip1:8081 ip2:8081 ip3:8081
Service B
Service C
Service D
서버 시작시 - 등록 / 종료시 - 제거
IP주소:port:”Service A”
API Server “A” - instance #2/3/4/5/6
Eureka

Client
Eureka

Client
Eureka

Client
Eureka

Client
Eureka

Client 서버 인스턴스 추가 / 제거시 별도의 설정 작업 없이 가능
Dynamic Service Discovery - Eureka
Eureka Server 만들기
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class);
}
}
- Eureka + Ribbon의 결합 시 Ribbon의 LoadBalancing 서버 목록을
Eureka를 통해서 공급
* dependency 추가 및 추가 설정 필요
Dynamic Service Discovery - Eureka
Eureka Client 만들기 - 내 서버 정보 등록 하기 

- 내가 호출의 대상이 되고 싶을 때
@EnableEurekaClient
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class);
}
}
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- Spring Boot Application 작성 후 `@EnableEurekaClient` 만 주석을 달
고, 등록할 Eureka Server 정보를 설정하면 끝
Dynamic Service Discovery - Eureka
Eureka Client 만들기 - 다른 서버의 목록을 가져오고 싶을때 

- 내가 Eureka에 등록된 서버 주소 목록을 알고 싶을때
- `DiscoveryClient`를 주입 받아 다양한 API 호출 가능

- 특별한 시나리오 없이 DiscoveryClient 직접 호출 필요 없음

- Ribbon이 DiscoveryClient를 이용해서 서버 목록을 가져옴.
@EnableEurekaClient
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class);
}
}
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
앞 페이지 코드와 동일
@Service
class ServiceInstanceRestController {
@Autowired
private DiscoveryClient discoveryClient;
public void doSomething() {
List<ServiceInstance> = this.discoveryClient.getInstances(applicationName);
:
}
}
[실습 Step-3] Eureka Server 실행
Tag : step-3-baseline
1. [준비작업] Eureka Server 띄우기
시간 절약을 위해 미리 준비된 Eureka Server 사용

> git reset HEAD --hard

> git checkout tags/step-3-baseline -b my-step-3
2. [eurekaserver] 소스 보기
build.gradle
application.yml : 데모용 각종 설정들
Main Class : @EnableEurekaServer
[실습 Step-3] Eureka Server 실행
Tag : step-3-baseline
3. [eurekaserver] 서버 실행
EurekaServerApplication 실행

http://localhost:8761/ 확인
[실습 Step-3] Eureka Client 적용하기 - Product 서버
Tag : step-3-eureka-product
1. [product] bulid.gradle
compile('org.springframework.cloud:spring-cloud-starter-eureka')
2. [product] ProductApplication : @EnableEurekaClient
3. [product] application.yml
OS에서 제공하는 hostname대신 자신의 ip address를 사용하여 등록
[실습 Step-3] Eureka Client 적용하기 - Display 서버
Tag : step-3-eureka-display
4. [display] bulid.gradle
compile('org.springframework.cloud:spring-cloud-starter-eureka')
5. [display] DisplayApplication : @EnableEurekaClient
6. [display] application.yml
[실습 Step-3] Eureka Client 적용하기 - 서버 확인
Tag : step-3-eureka-display
7. Display / Product 서버 둘 다 재시작 후 Eureka 서버 확인
http://localhost:8761/ 확인
[실습 Step-3] Eureka 서버 주소 직접 명시
Tag : step-3-eureka-addresses
8. [product/display] application.yml에 Eureka Server 주소 명시
default 값이 http://127.0.0.1:8761/eureka이므로 로컬 테스트 시 설정 불필요
[실습 Step-3] Eureka 서버 주소 직접 명시
Tag : step-3-eureka-addresses
9. 정리
@EnableEurekaServer / @EnableEurekaClient를 통해 서버
구축, 클라이언트 Enable 가능하다.
@EnableEurekaClient를 붙인 Application은 Eureka 서버로 부터 남의
주소를 가져오는 역할 과 자신의 주소를 등록하는 역할을 둘다 수행 가능하다.
Eureka Client가 Eureka Server에 자신을 등록할 때
`spring.application.name`이 이름으로 사용된다.
[실습 Step-3] RestTemplate에 Eureka 적용하기
Tag : step-3-eureka-completed
1. 목적
Display -> Product 호출시에 Eureka를 적용하여 ip주소를 코드나
설정 `모두`에서 제거하려고 함.
2. [display] application.yml 변경 (주석 처리)
product.ribbon.eureka.enabled = false 제거

-> ribbon의 default는 eureka 사용

product.ribbon.listOfServers 제거

-> 서버 주소는 Eureka Server에서 가져와라 !
[실습 Step-3] RestTemplate에 Eureka 적용하기
Tag : step-3-eureka-completed
3. [확인] display 서버 재시작
http://localhost:8081/displays/11111
- Product의 주소가 설정/코드에서 모두 제거

- 코드에서는 http://product/으로 접근
4. 정리
- @LoadBalanced RestTemplate에는 Ribbon + Eureka 연동

- Eureka Client가 설정되면, 코드상에서 서버 주소 대신
Application 이름을 명시해서 호출 가능

- Ribbon의 Load Balancing과 Retry가 함께 동작
Step-4 : Spring Cloud Feign
Declarative Http Client
> git checkout tags/step-4-baseline -b my-step-4
* 앞선 예제 못따라 오신 분들이나, 늦게 참여하신 분들은 막바로 Git 이동
Declarative Http Client - Spring Cloud Feign
인터페이스 선언 만으로 Http Client 구현물을 만들어 줌
@FeignClient(name="dp", url = "http://localhost:8080/")
public interface ProductResource {
@RequestMapping(value = "/query/{itemId}", method=RequestMethod.GET)
String getItemDetail(
@PathVariable(value = "itemId") String itemId);
}
- @FeignClient를 Interface에 명시

- 각 API를 Spring MVC Annotation을 이용해서 정의
@Autowired
ProductResource productResouce;
How to Use
- @Autowired를 통해 DI 받아 사용
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
1. 목적
Display -> Product 호출시에 Feign을 사용해서 RestTemplate
을 대체해 보려고 함.
2. [display] build.gradle에 dependency 추가
compile('org.springframework.cloud:spring-cloud-starter-
feign')
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
3. [display] DisplayApplication에 @EnableFeignClients 추가
4. [display] Feign용 Interface 추가
- 이전 `ProductRemoteService` 사용하지 않고 데모를 위해 별도 정의
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
5. [display] FeignProductRemoteService에 Annotation 넣기
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
5. [display] FeignProductRemoteService에 Annotation 넣기
Client 구현 완성. 서버 가동시
`FeignProductRemoteService`용 Spring Bean 자동 생성
`FeignProductRemoteService`를 주입 받아서 사용하면 됨.
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
6. [display] DisplayController에서 호출 부분 변경
기존 RestTemplate사용했던 서비스 대신 Feign이 자동으
로 생성해준 서비스 빈을 사용
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
7. 동작 확인
http://localhost:8081/displays/11111
8. 정리
Feign은 Interface 선언을 통해 자동으로 HTTP Client를 만들어
주는 Declarative Http Client
Open-Feign 기반으로 Spring Cloud가 Wrapping한것이 오늘
실습한 Spring Cloud Feign
방금 한 실습 (Feign + URL 명시)는 

- No Ribbon

- No Eureka

- No Hystrix
[실습 Step-4] Feign 클라이언트 사용하기
Tag : step-4-feign-url
9. 부가 정보

- Feign Client의 Interace에 SpringMVC의 Annotation을 사용하는
경우에 SpringMVC와 달리 parameter이름을 항상 명시해 주어야 함

- ex) 

- Spring MVC : @PathVariable String productId

- Feign Client : @PathVariable(“productId”) String productId

- Java 8을 사용하는 경우 “-parameters” 옵션과 함께 컴파일 하면 해
결 가능. 

- Spring MVC에서는 Parameter이름을 Reflection으로 못가져오 오는
경우 Class 파일속의 Debugging Info에서 꺼내오나, Feign의 경우
Interface에 Annotation을 사용하며 Interface의 경우 이
Debugging Info가 존재하지 않음.

- 이 옵션을 사용하지 않는 경우 직접 명시 필요
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-eureka
1. 배경
Feign의 또 다른 강점은 Ribbon + Eureka + Hystrix와 통합되어
있다는 점.
2. [display] Feign에 Eureka + Ribbon 적용하기
@FeignClient에서 url만 제거
완성 !!!
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-eureka
3. Feign의 동작
@FeignClient에 URL 명시 시

-> 순수 Feign Client로서만 동작
@FeignClient에 URL 명시 하지 않으면 ? 

-> Feign + Ribbon + Eureka 모드로 동작

-> 어떤 서버 호출하나 ? @FeignClient(name=“product”)

-> 즉, eureka에서 product 서버 목록을 조회해서 ribbon을 통
해 load-balancing하면서 HTTP 호출을 수행
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-eureka
4. [display] application.yml : Feign + Hystrix
위의 설정이 들어가면 메소드 하나 하나가 Hystrix Command 로
서 호출 된다. !!!
5. Feign에서 Fallback은 ? Hystrix 설정은 ?
Declarative Http Client - Spring Cloud Feign
그럼 Hystrix Fallback은 ??
@Component
public class ProductResourceFallback implements ProductResource {
@Override
public String getItemDetail(String itemId) {
return “default value”;
}
}
- Fallback 클래스를 @Feign선언시 명시
- Feign으로 정의한 Interface를 직접 구현 하고 Spring Bean으로 선언
@FeignClient(fallback= ProductResourceFallback.class, name=“dp", url = “http://
localhost:8080/“)
public interface ProductResource {
@RequestMapping(value = "/query/{itemId}", method=RequestMethod.GET)
String getItemDetail(
@PathVariable(value = "itemId") String itemId);
}
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-hystrix
6. [display] Feign용 Hystrix Fallback 선언 - Spring Bean으로 정의
7. [display] Feign용 Hystrix Fallback 명시
@FeignClient에 `fallback` 속성으로 클래스 명시
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-hystrix-properties
8. [display] Feign용 Hystrix 프로퍼티 정의하는 법
Feign 사용하는 경우 commandKey 이름 주의

ex) FeignProductRemoteService#getProductInfo(String)
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-hystrix-properties
9. 추가정보

- Spring Cloud Feign에 의해서 생성된 Bean은 자동으로 @Primary
가 선언됨

- 따라서 동일 타입의 다른 빈에 비해서 Autowired 시 우선순위를 갖음

- 옵션을 통해 Primary 속성 제거 가능
[실습 Step-4] Feign + Hystrix,Ribbon,Eureka
Tag : step-4-feign-eureka
정리
Feign은 인터페이스 선언 + 설정으로 다음과 같은 것들이 가능하다

- Http Client

- Eureka 타겟 서버 주소 획득

- Ribbon을 통한 Client-Side Load Balancing

- Hystrix를 통한 메소드별 Circuit Breaker
Step-5 : Zuul
API Gateway for MSA
WAR
Front/
WAR
Front/
?
첫번째 고민

- Legacy Application에서 새로 만들어진 수많은 API 서버들을 어떻게
호출할까 ? 

- Old S/W Stack, 대단위 수정 배포의 Risk 등으로 Eureka, Ribbon
등을 Legacy Application에 직접 탑재하는 것이 어려움
Legacy/App로 부터의 호출
WAR
Front/
WAR
Front/
?
두번째 고민

- 모든 API 서버들에 들어갈 공통된 기능을 구현할 곳과, 전체 API
호출을 통제할 곳이 필요해
“전체 API Server들의 맨 앞단에 API Gateway의 도입으로 해결 가
능”
Legacy/App로 부터의 호출
API Gateway - Zuul
- API의 외부 노출을 위한 Endpoint

- URL별로 Mapping된 Server 군으로 API 호출을 Forward
- ? Box 만이 다른 API Gateway와의 차별점
API Gateway - Zuul
1. HystrixCommand
1. Zuul의 모든 API 요청은 HystrixCommand로 구성되어 전달된다. 

- 각 API 경로 (서버군) 별로 Circuit Breaker 생성 

- 하나의 서버군이 장애를 일으켜도 다른 서버군의 서비스에는 영향이 없다.

- CircuitBreaker / ThreadPool의 다양한 속성을 통해 서비스 별 속성에
맞는 설정 가능
Service “A” Servers
API Gateway - Zuul
1. HystrixCommand
2. API를 전달할 서버의 목록을 갖고 Ribbon을 통해 Load-Balancing을 수행
한다.

- 주어진 서버 목록들을 Round-Robin으로 호출

- Coding을 통해 Load Balancing 방식 Customize 가능

Service “A” Servers
2. Ribbon
API Gateway - Zuul
1. HystrixCommand
3. Eureka Client를 사용하여 주어진 URL의 호출을 전달할 “서버 리스트”를 찾는다.

- Zuul에는 Eureka Client가 내장

- 각 URL에 Mapping된 서비스 명을 찾아서 Eureka Server를 통해 목록을 조회
한다.

- 조회된 서버 목록을 `Ribbon` 클라이언트에게 전달한다.

Service “A” Servers
2. Ribbon
3. Eureka Client
API Gateway - Zuul
1. HystrixCommand
4. Eureka + Ribbon에 의해서 결정된 Server 주소로 HTTP 요청

- Apache Http Client가 기본 사용

- OKHttp Client 사용 가능
Service “A” Servers
2. Ribbon
3. Eureka Client
4. Http Client
API Gateway - Zuul
1. HystrixCommand
5. 선택된 첫 서버로의 호출이 실패할 경우 Ribbon에 의해서 자동으로 Retry 수행

- Retry 수행 조건 

- Http Client에서 Exception 발생 (IOException)

- 설정된 HTTP 응답코드 반환 (ex 503)
Service “A” Servers
2. Ribbon
3. Eureka Client
4. Http Client
5. Retry By Ribbon
API Gateway - Zuul
1. HystrixCommand
Zuul의 모든 호출은….
Service “A” Servers
2. Ribbon
3. Eureka Client
4. Http Client
5. Retry By Ribbon
- HystrixCommand로 실행되므로 Circuit Breaker를 통해 

- 장애시 Fail Fast 및 Fallback 수행 가능
- Ribbon + Eureka 조합을 통해

- 현재 서비스가 가능한 서버의 목록을 자동으로 수신
- Ribbon의 Retry 기능을 통해

- 동일한 종류의 서버들로의 자동 재시도가 가능
API Gateway - Zuul
부가 정보 

- Spring Cloud Zuul에서 사용하는 Hystrix Command는 기본적으로
Thread Pool 방식이 아닌 Semaphore 방식을 사용

- Thread Pool을 사용하기 위해서는 설정 변경 필요

- Spring Cloud Zuul에서는 기본 설정으로 `RibbonCommand`라는 하나의
Global Thread pool을 모든 Route에 대해서 공유

- 각 Route 별로 분리하는 것이 Zuul의 안정성에 도움이 되며 이를 위해서는
추가적인 설정이 필요
Project Vine

Lessons Learned
Lessons Learned
“Open Source를 100% 신뢰하지는 말것”
Documentation은 부실할 수 있으며,

Bug가 다수 존재할 수 있으며, 

심지어 Bug가 발견되어도 아무도 급하게 Bug를 수정해
주지 않는다.
Source 보는 것을 두려워 하지 않으며, 확인이 필요한 중
요한 기능은 소스코드를 확인하라 

Github의 Issues / Pull Request를 자주 확인하라
Lessons Learned
“Test, Test, Test”
Open Source의 현재 동작하던 기능이 Version Up과 함
께 사라지거나 다르게 동작할 수 있다. 

Property는 쉽게 추가되거나 삭제될 수 있다. 

대부분의 경우 우리는 이러한 변화를 인지하지 못한다.
Open Source를 통해 사용하는 주요 기능에 대해서
Integration 테스트를 작성하여 Version Up 이후에도 여전
히 원하는 대로 동작하는지 확인하라
ex) 틀린 주소를 주입하고 우리의 Fallback이 호출되는
지 확인하는 테스트
The End

More Related Content

What's hot

소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해Terry Cho
 
MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?
MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?
MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?VMware Tanzu Korea
 
REST API 설계
REST API 설계REST API 설계
REST API 설계Terry Cho
 
Microservices & API Gateways
Microservices & API Gateways Microservices & API Gateways
Microservices & API Gateways Kong Inc.
 
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019min woog kim
 
암호화 이것만 알면 된다.
암호화 이것만 알면 된다.암호화 이것만 알면 된다.
암호화 이것만 알면 된다.KwangSeob Jeong
 
Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQLI Goo Lee
 
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례YongSung Yoon
 
Understanding MicroSERVICE Architecture with Java & Spring Boot
Understanding MicroSERVICE Architecture with Java & Spring BootUnderstanding MicroSERVICE Architecture with Java & Spring Boot
Understanding MicroSERVICE Architecture with Java & Spring BootKashif Ali Siddiqui
 
Workshop spring session 2 - La persistance au sein des applications Java
Workshop spring   session 2 - La persistance au sein des applications JavaWorkshop spring   session 2 - La persistance au sein des applications Java
Workshop spring session 2 - La persistance au sein des applications JavaAntoine Rey
 
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)Ji-Woong Choi
 
Kong API Gateway
Kong API Gateway Kong API Gateway
Kong API Gateway Chris Mague
 
Sonatype nexus 로 docker registry 관리하기
Sonatype nexus 로 docker registry 관리하기Sonatype nexus 로 docker registry 관리하기
Sonatype nexus 로 docker registry 관리하기KwangSeob Jeong
 
Microservice API Gateways with NGINX
Microservice API Gateways with NGINXMicroservice API Gateways with NGINX
Microservice API Gateways with NGINXGeoffrey Filippi
 
Api gateway
Api gatewayApi gateway
Api gatewayenyert
 
소프트웨어 아키텍처
소프트웨어 아키텍처소프트웨어 아키텍처
소프트웨어 아키텍처영기 김
 

What's hot (20)

소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
 
Springboot Microservices
Springboot MicroservicesSpringboot Microservices
Springboot Microservices
 
MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?
MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?
MSA 전략 2: 마이크로서비스, 어떻게 구현할 것인가?
 
REST API 설계
REST API 설계REST API 설계
REST API 설계
 
Microservices & API Gateways
Microservices & API Gateways Microservices & API Gateways
Microservices & API Gateways
 
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
 
암호화 이것만 알면 된다.
암호화 이것만 알면 된다.암호화 이것만 알면 된다.
암호화 이것만 알면 된다.
 
Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQL
 
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
 
Understanding MicroSERVICE Architecture with Java & Spring Boot
Understanding MicroSERVICE Architecture with Java & Spring BootUnderstanding MicroSERVICE Architecture with Java & Spring Boot
Understanding MicroSERVICE Architecture with Java & Spring Boot
 
Workshop spring session 2 - La persistance au sein des applications Java
Workshop spring   session 2 - La persistance au sein des applications JavaWorkshop spring   session 2 - La persistance au sein des applications Java
Workshop spring session 2 - La persistance au sein des applications Java
 
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
 
Kong API Gateway
Kong API Gateway Kong API Gateway
Kong API Gateway
 
Sonatype nexus 로 docker registry 관리하기
Sonatype nexus 로 docker registry 관리하기Sonatype nexus 로 docker registry 관리하기
Sonatype nexus 로 docker registry 관리하기
 
02 api gateway
02 api gateway02 api gateway
02 api gateway
 
Microservice API Gateways with NGINX
Microservice API Gateways with NGINXMicroservice API Gateways with NGINX
Microservice API Gateways with NGINX
 
Api gateway
Api gatewayApi gateway
Api gateway
 
소프트웨어 아키텍처
소프트웨어 아키텍처소프트웨어 아키텍처
소프트웨어 아키텍처
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Api Gateway
Api GatewayApi Gateway
Api Gateway
 

Similar to Spring Cloud Workshop

Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례SangIn Choung
 
HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2SeungHyun Hwang
 
Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용지원 이
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509영석 조
 
웹서버 부하테스트 실전 노하우
웹서버 부하테스트 실전 노하우웹서버 부하테스트 실전 노하우
웹서버 부하테스트 실전 노하우IMQA
 
실전 서버 부하테스트 노하우
실전 서버 부하테스트 노하우 실전 서버 부하테스트 노하우
실전 서버 부하테스트 노하우 YoungSu Son
 
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by NetflixJi-Woong Choi
 
[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발NAVER D2
 
Node.js 시작하기
Node.js 시작하기Node.js 시작하기
Node.js 시작하기Huey Park
 
스프링 어플리케이션의 문제해결사례와 안티패턴
스프링 어플리케이션의 문제해결사례와 안티패턴스프링 어플리케이션의 문제해결사례와 안티패턴
스프링 어플리케이션의 문제해결사례와 안티패턴Sanghyuk Jung
 
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화sung ki choi
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.Ryan Park
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Ryan Park
 
Design Pattern - Multithread Ch10
Design Pattern - Multithread Ch10Design Pattern - Multithread Ch10
Design Pattern - Multithread Ch10hyun soomyung
 
Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기jongho jeong
 
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요NAVER D2
 
Confd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOS
Confd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOSConfd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOS
Confd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOS충섭 김
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 

Similar to Spring Cloud Workshop (20)

Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례
 
HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2
 
Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509
 
웹서버 부하테스트 실전 노하우
웹서버 부하테스트 실전 노하우웹서버 부하테스트 실전 노하우
웹서버 부하테스트 실전 노하우
 
실전 서버 부하테스트 노하우
실전 서버 부하테스트 노하우 실전 서버 부하테스트 노하우
실전 서버 부하테스트 노하우
 
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
 
[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발
 
Node.js 시작하기
Node.js 시작하기Node.js 시작하기
Node.js 시작하기
 
스프링 어플리케이션의 문제해결사례와 안티패턴
스프링 어플리케이션의 문제해결사례와 안티패턴스프링 어플리케이션의 문제해결사례와 안티패턴
스프링 어플리케이션의 문제해결사례와 안티패턴
 
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 
Design Pattern - Multithread Ch10
Design Pattern - Multithread Ch10Design Pattern - Multithread Ch10
Design Pattern - Multithread Ch10
 
Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기
 
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
 
Confd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOS
Confd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOSConfd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOS
Confd, systemd, fleet을 이용한 어플리케이션 배포 in CoreOS
 
Kafka slideshare
Kafka   slideshareKafka   slideshare
Kafka slideshare
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 

Spring Cloud Workshop

  • 1. Spring Cloud Workshop SK planet 개발혁신팀 윤용성(Yongsung Yoon)
  • 2. 시작하기에 앞서… 실습에 사용 되는 모든 코드는 아래의 주소에 있습니다. https://github.com/yongsungyoon/spring-cloud- workshop
  • 3. 시작하기에 앞서… 오늘 실습의 완성된 코드는 master branch에 있습니 다. 실제 실습은 별도 Branch에서 진행합니다. 특정 단계에서 실습에 못 따라 오시더라도 각 단계별로 `tag` 를 부여해 놨으니 막바로 Checkout해서 시작하시면 됩니다. Presentation 우측 상단에 `tag`이름이 해당 단계 실습 완료 코드가 들어있어 있는 곳입니다. Tag : step-0
  • 4. 이 발표의 목적은… Spring Cloud의 가장 핵심이 되는 개념을 실습을 통해 정확하 게 이해하는 것 Spring Cloud의 주요 요소를 당장 자신의 Project에 적용할 수 있게 도와드리는 것
  • 5. Project Vine 11st Legacy Application 개선 Project
  • 6. Strangler Application Pattern 열대 우림 지역의 Stranger Vine에서 유래 Legacy 교살 전략 새로운 Application 은 독립된 API 서버로 Legacy와 함께 운영 위의 과정을 반복 Application Modernization Strategy “Strangler Application” by Martin Fowler
  • 7. Strangler Application Pattern in 11st - Hybrid MSA WAR Front/Mobile WAS WAR Front/Mobile WAS REST
 API Zuul API Gateway 전시 API Server 상품 API Server 추천 API Server 추천 Service XXX API Server … Eureka Server Config Server Admin Server ?
  • 9. Best Practice - Netflix OSS & Spring Cloud Hystrix Eureka Ribbon EvCache Spectator Archaius …. Spring Cloud …. Config Stream Sleuth Contract ….
  • 11. Hystrix - Circuit Breaker public String anyMethodWithExternalDependency() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand Hystrix 적용하기 위의 메소드를 호출할 때 벌어지는 일 - 이 메소드 호출을 'Intercept' 하여 “대신” 실행 - 대신 ?? - 실행된 결과의 성공 / 실패 (Exception) 여부를 기록하고 “통계”를 낸다. - 통계 ?? - 실행 결과 “통계”에 따라 Circuit Open 여부를 판단하고 필요한 “조치”를 취 한다. 조치 ??
  • 12. Hystrix - Circuit Breaker Circuit Open ?? - Circuit이 오픈된 Method는 (주어진 시간동안) 호출이 “제한”되며, “즉시” 에러를 반환한다. Why ? - 특정 메소드에서의 지연 (주로 외부 연동에서의 지연)이 시스템 전체의 Resource 를 (Thread, Memory등)를 모두 소모하여 시스템 전체의 장애를 유발한다. - 특정 외부 시스템에서 계속 에러를 발생 시킨다면, 지속적인 호출이 에러 상 황을 더욱 악화 시킨다. So ! - 장애를 유발하는 (외부) 시스템에 대한 연동을 조기에 차단 (Fail Fast) 시킴 으로서 나의 시스템을 보호한다. 기본 설정 - 10초동안 20개 이상의 호출이 발생 했을때 50% 이상의 호출에서 에러가 발 생하면 Circuit Open
  • 13. Hystrix - Circuit Breaker public String anyMethodWithExternalDependency() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand 이제 이 메소드가 호출된다면 ? - 이 메소드는 'Intercept' 되어 별도의 Hystrix Thread Pool에서 “대신” 실행 된다. - 메소드 내부에서 발생한 Exception의 횟수는 Circuit Breaker 내에서 통계 가 내어진다. - Circuit Open 조건에 도달하면 Circuit이 Open되어 호출이 차단 된다. * 가장 기본적인 Circuit Breaker 개념 적용 완료 !
  • 14. Hystrix - Circuit Breaker - 기본 설정으로는 유사한 일을 하는 두개의 메소드가 별도의 Circuit Breaker를 갖게된다. public String anyMethodWithExternalDependency1() { URI uri = URI.create("http://172.32.1.22:8090/recommend"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand public String anyMethodWithExternalDependency2() { URI uri = URI.create("http://172.32.1.22:8090/mainrecommend"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand Circuit Breaker는 어떤 단위로 생성되는가 ? - Default로 @HystrixCommand가 명시된 메소드 단위
  • 15. Hystrix - Circuit Breaker Circuit의 단위 명시하기 - CommandKey - “CommandKey”는 Circuit Breaker의 단위이며 여러개의 메소드를 같은 Key를 명시함으로써 하나의 Circuit을 사용하게 할 수 있다. public String anyMethodWithExternalDependency1() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand(commandKey = “ExtDep1”) public String anyMethodWithExternalDependency2() { URI uri = URI.create("http://172.32.1.22:8090/mainrecommend"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand(commandKey = “ExtDep1”) - 즉, A 메소드와 B 메소드가 같은 Circuit Breaker를 사용한다면, A 와 B의 에러 비율이 함께 통계내어지고, Circuit이 오픈되면 함께 차 단된다.
  • 16. Hystrix - Circuit Breaker public String anyMethodWithExternalDependency1() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } public String recommendFallback() { return “<미리 준비된 상품 목록>”; } @HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”) Hystrix의 또 하나의 중요한 개념 - Fallback - Fallback method는 Circuit이 오픈된 경우 혹은 Exception이 발생한 경우 대신 호출될 Method. - 오류 발생시 Exception 대신 응답할 Default 구현을 넣는다.
  • 17. Hystrix - Circuit Breaker 오랫동안 응답이 없는 메소드에 대한 처리 방법은 ? - 특정 메소드의 총 소요시간에 대한 Timeout을 직접 관리/예측하는 것은 매우 힘들다 - ex) Socket Connect/Read Timeout, JDBC Timeout, 3rd Party 라이브러디 등 - 설정하지 않으면 default 1,000ms - 물론 이경우에도 Fallback이 있다면 Fallback을 수행 Hystrix에서는 Circuit Breaker별로 Timeout 설정 가능 - 해당 메소드가 설정된 시간안에 안 끝나면 Timeout으로 인한 Exception 자 동 발생
  • 18. Hystrix - Circuit Breaker public String anyMethodWithExternalDependency1() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } public String recommendFallback() { return "No recommend available"; } @HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”, commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500") }) 오랫동안 응답이 없는 메소드에 대한 처리 방법은 ? - Timeout - 실습에서는 yml로 설정하겠습니다.
  • 19. [실습] 프로젝트 import 1. 실습 시작 시점으로 Git 이동 > git checkout -b step-0 Tag : step-0 2. IntelliJ에서 build.gradle import File > Open - root 폴더 build.gradle 선택 - Open as Project
  • 20. [실습] 프로젝트 import 3. Import Project from Gradle Tag : step-0 주의
  • 21. [실습] 소스 살펴 보기 1. 전체 구조 request : /products/{productId} response : "[product id = " + productId + " at " + System.currentTimeMillis() + "]"; Tag : step-0 Display (8081) Product (8082) request : /displays/{displayId} response : "[display id = %s at %s %s ]" ,displayId ,System.currentTimeMillis() ,/products/12345의 응답 localhost:8081/displays/{displayId} localhost:8082/products/12345
  • 22. [실습] Rest API로 Display -> Product 연동 1. 프로젝트 구조 보기 Tag : step-0 2. Display -> Product 호출 3. Display / Product 실행 - Product 동작 확인 : http://localhost:8082/products/22222    - Display 동작 확인 :http://localhost:8081/displays/11111
  • 23. Step-1 : Hystrix 사용하기 실습
  • 24. [실습 Step-1] Hystrix 배경 Display 서비스는 외부 Server인 Product API와 연동되어있음 Product API에 장애가 나더라도 Display의 다른 서비스는 이상없이 동작하 였으면 합니다 Product API에 응답 오류인경우, Default값을 넣어 주고 싶습니다 결정 내용 Display -> Product 연동 구간에 Circuit Breaker를 적용 !
  • 25. [실습 Step-1] Hystrix 사용하기 Tag : step-1-hystrix-basic 1. [display] build.gradle에 hystrix dependency추가 compile('org.springframework.cloud:spring-cloud-starter-hystrix’) 2. [display] DisplayApplication에 @EnableCircuitBreaker추가 @EnableCircuitBreaker 3. [display] ProductRemoteServiceImp에 @HystrixCommand 추가 @HystrixCommand
  • 26. [실습 Step-1] Hystrix Fallback 적용하기 Tag : step-1-hystrix-fallback 4. [product] ProductController에서 항상 Exception 던지게 수 정하기 (장애 상황 흉내) throw new RuntimeException(“I/O Error”) 5. [display] ProductRemoteServiceImp에 Fallback Method 작성하기
  • 27. [실습 Step-1] Hystrix Fallback 적용하기 Tag : step-1-hystrix-fallback 6. 확인 http://localhost:8082/products/22222    http://localhost:8081/displays/11111 Hystrix가 발생한 Exception을 잡아서 Fallback을 실행 Fallback 정의 여부와 상관없이 Circuit 오픈 여부 판단을 위한 `에 러통계`는 계산하고 있음 아직, Circuit이 오픈된 상태 X
  • 28. [실습 Step-1] Hystrix Fallback 적용하기 Tag : step-1-hystrix-fallback2 7. Fallback 원인 출력하기 Fallback 메소드의 마지막 파라매터를 `Throwable`로 추가하면 Fallback 일으킨 Exception을 전달 해줌
  • 29. [실습 Step-1] Hystrix Fallback 적용하기 Tag : step-1-hystrix-fallback2 8. 정리 Hystrix에서 Fallback의 실행 여부는 Exception이 발생 했는가 여부 Fallback의 정의 여부는 Circuit Breaker Open과 무관 Throwable 파래매터의 추가로 Fallback 원인을 알 수 있다.
  • 30. [실습 Step-1] Hystrix로 Timeout 처리하기 Tag : step-1-hystrix-timeout Hystrix로 할 수 있는 또 한가지 ! Timeout 처리 @HystrixCommand로 표시된 메소드는 지정된 시간안에 반환되지 않 으면 자동으로 Exception 발생 (기존 설정 : 1,000ms) 1. [product] ProductController의 throw Exception을 Thread.sleep(2000)로 수정 2. 확인 Product API를 직접 호출하는 경우는 동작하나, Display는 동작 안함 t = com.netflix.hystrix.exception.HystrixTimeoutException
  • 31. [실습 Step-1] Hystrix로 Timeout 처리하기 Tag : step-1-hystrix-timeout 3. [display] application.yml 수정하여 Hystrix Timeout 시간 조정하기 4. 다시 확인 Product/Display 모두 동작 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
  • 32. [실습 Step-1] Hystrix로 Timeout 처리하기 Tag : step-1-hystrix-timeout 5. 정리 Hystrix를 통해 실행 되는 모든 메소드는 정해진 응답시간 내에 반 환 되어야 한다. 그렇지 못한 경우, Exception이 발생하며, Fallback이 정의된 경 우 수행된다. Timeout 시간은 조절할 수 있다. (Circuit 별로 세부 수정 가능하 며 뒷 부분에 설명) 언제 유용한가 ? 모든 외부 연동은 최대 응답 시간을 가정할 수 있어야 한다. 여러 연동을 사용하는 경우 최대 응답시간을 직접 Control하는 것은 거의 불가능하다 (다양한 timeout, 다양한 지연등..)
  • 33. [실습 Step-1] Hystrix Circuit Open 테스트 Tag : step-1-hystrix-circuit-open 1. [display] application.yml 수정하여 Hystrix 프로퍼티 추가 기본 설정 (테스트 하기 힘들다) - 10초동안 20개 이상의 호출이 발생 했을때 50% 이상의 호출에서 에러가 발생하면 Circuit Open 변경설정 - h.c.d.circuitBreaker.requestVolumeThreshold : 1 - h.c.d.circuitBreaker.errorThresholdPercentage: 50
  • 34. [실습 Step-1] Hystrix Circuit Open 테스트 Tag : step-1-hystrix-circuit-open 2. [product] ProductController 다시 수정하여 Exception 던지도록 수정 Thread.sleep(2000) 제거 - 테스트 편의 Throw new RuntimeException 복원 - Exception 발생으로 Circuit Open 유도하기 위해
  • 35. [실습 Step-1] Hystrix Circuit Open 테스트 Tag : step-1-hystrix-circuit-open 3. 확인 http://localhost:8082/products/22222    > Exception 발생 확인 http://localhost:8081/displays/11111 > 10초 이상 호출. Exception 메세지 변경되었나 확인 > Product Console 지운 후 Display 호출 및 확인 “Hystrix Circuit Short-Circuited and is OPEN”이 Display 에 출력되는 경우는 Product 콘솔에는 아무것도 찍히지 않는다. -> Circuit Open (호출 차단)
  • 36. [실습 Step-1] Hystrix Circuit Open 테스트 Tag : step-1-hystrix-circuit-open 4. 부가 설명 - Circuit Open 여부는 통계를 기반으로 한다. - 최근 10초간 호출 통계 (execution.isolation.thread.timeoutInMilliseconds) - 최소 요청 갯수 넘는 경우 만 (circuitBreaker.requestVolumeThreshold) - 에러 비율 넘는 경우 (circuitBreaker.errorThresholdPercentage) - 한번 Circuit이 오픈되면 5초간 호출이 차단되며, 5초 경과후 단 “1개” 의 호출을 허용하며 (Half-Open), 이것이 성공하면 Circuit을 다시 CLOSE하고, 여전히 실피하면 Open이 5초 연장된다. (circuitBreaker.sleepWindowInMilliseconds)
  • 37. [실습 Step-1] Hystrix에서 Circuit Breaker의 단위는 ?? Circuit Breaker의 단위 ? - 에러 비율을 통계의 단위 - Circuit Open / Close가 함께 적용되는 단위 - 즉, A 메소드와 B 메소드가 같은 Circuit Breaker를 사용한다면, A와 B의 에러 비율이 함께 통계내어지고, Circuit이 오픈되면 함께 차단된다. Circuit의 지정은 ? - `commandKey`라는 프로퍼티로 지정 가능. - @HystrixCommand에서는 지정하지 않는 경우 메소드 이름 사용 - 이렇게 사용하지 말것 ! - 메소드 이름은 겹칠 수 있으며, 나중에 나오는 Feign의 경우 또 다르기 때문에 헷 갈릴 수 있다. - 항상 직접 지정 해서 사용하기
  • 38. [실습 Step-1] Hystrix에서 Circuit Breaker의 단위는 ?? Tag : step-1-hystrix-command-key 1. [display] `commandKey` 부여하기 2. [display] application.yml에 commandKey로 속성 지정해보기 `default` : global 설정. 이 위치에 `commandKey`값을 넣으면, 해당 Circuit Breaker에만 해당 속성 적용된다.
  • 39. [실습 Step-1] Hystrix에서 Circuit Breaker의 단위는 ?? Tag : step-1-hystrix-command-key 3. 확인 - 각자 쉬는 시간에 (앞선 상태와 동일하게 동작해야 함)
  • 40. Hystrix - Circuit Breaker 연동 System A Thread Pool A (20 threads) Thread Pool B (10 threads) Thread Pool C (15 threads) Circuit Breaker A Circuit Breaker B Circuit Breaker C Circuit Breaker D Circuit Breaker F 연동 System B 연동 System C User Request Hystrix를 쓴다는 것의 또다른 의미 - Hystrix를 통해 실행한다는 것은 별도의 Thread Pool에서 내 Code를 실행 한다는 것 - 각 Circuit Breaker는 한 개의 Thread Pool과 연동 - 하나의 ThreadPool을 여러 개의 Circuit Breaker가 공유할 수 있다.
  • 41. Hystrix - Circuit Breaker 각 Circuit Breaker가 사용할 Thread Pool의 지정 - 내 시스템의 Resource가 다양한 기능(서비스)들을 위해 골고루 분배 될 수 있도록.. - Semaphore 방식의 Isolation도 있음 - 가벼움. Thread Isolation에 비해서 성능상 약간의 이득이 있음 - Timeout이 정확하게 동작하지 않음. (Blocking 호출등에 멈춰있는 경우 대기) - 어느 하나 외부 Dependency (외부 연동 시스템)의 문제 발생시 그 영 향으로 부터 시스템의 다른 요소를 보호 - Isolation - ThreadPoolKey (혹은 CommandGroupKey) 속성으로 지정 - 각 Thread Pool 별로 Max Thread 지정 Thread Pool을 사용하는 의미
  • 42. 소스 : https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a 가정 각 서버 별 가용성 : 99.99% 30개의 Dependency 존재 99.99% ^ 30 = 99.7% Uptime = 1달 기준 2시 간 인용 : https://speakerdeck.com/benjchristensen/performance-and-fault-tolerance-for-the-netflix-api-august-201
  • 43. Hystrix - Circuit Breaker 동시에 실행될 수 있는 Command의 갯수 제한 - ThreadPool 설정 - HystrixCommand로 선언된 Method는 default로 호출한 Thread가 아닌 별도의 ThreadPool에서 “대신” 실행된다. - ThreadPool에 대한 설정을 하지 않으면 Default로는 @HystrixCommand 가 선언된 클래스 이름이 ThreadPool 이름로 사용된다. public class MySerice { @HystrixCommand(commandKey = “serviceA”) public String anyMethodWithExternalDependency1() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } @HystrixCommand(commandKey = “serviceB”) public String anyMethodWithExternalDependency2() { URI uri = URI.create(“http://172.32.2.33:8090/search"); String result = this.restTemplate.getForObject(uri, String.class); return result; } } - 위의 같은 경우 두개의 메소드는 각각 Circuit Breaker를 갖지만, 두개의 Command가 “MyService”라는 하나의 ThreadPool에서 수행됨.
  • 44. Hystrix - Circuit Breaker ThreadPool 직접 설정하는 방법 - CommandGroupKey public String anyMethodWithExternalDependency1() { URI uri = URI.create("http://172.32.1.22:8090/recommended"); String result = this.restTemplate.getForObject(uri, String.class); return result; } public String recommendFallback() { return "No recommend available"; } @HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”, commandGroupKey = “Myservice1”) - @HystrixCommand 별로 사용할 Thread Pool을 명시적으로 지정할 수 있다. - CommandGroupKey - 같은 외부 Dependency가 있는 Method들을 하나의 ThreadPool을 사용 하도록 Grouping 하는 것이 가능
  • 45. Hystrix - Circuit Breaker ThreadPool의 세부 옵션 설정 @HystrixCommand(commandKey = “ExtDep1”, fallbackMethod=“recommendFallback”, commandGroupKey = “Myservice1”, commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500") }, threadPoolProperties = { @HystrixProperty(name = "coreSize", value = "30"), @HystrixProperty(name = "maxQueueSize", value = "101"), @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"), @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"), @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"), @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440") } - Hystrix에 관한 모든 세부 옵션 : https://github.com/Netflix/Hystrix/ wiki/Configuration - ThreadPool의 기본 사이즈는 10이므로 적용시 필히 상향 여부 검토 필요
  • 46. Hystrix - Circuit Breaker Project에 적용 하기 - Spring Boot 프로젝트인 경우 - Spring Cloud Dependency 추가 와 @EnableHystrix 주석 - Spring 프로젝트인 경우 혹은 AOP 사용 가능한 경우 - Netflix Hystrix-Javanica - https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica - 기타 Java Project인 경우 - (Pure) Netflix Hystrix - 주석 없이 Coding으로 가능 - https://github.com/Netflix/Hystrix
  • 47. Step-2 : Ribbon Client Load Balancer > git checkout tags/step-2-baseline -b my-step-2 * 앞선 예제 못따라 오신 분들이나, 늦게 참여하신 분들은 막바로 Git 이동
  • 48. Server Side Load Balancer (with L4 Switch) Client (Caller) Server1 Server2 Server3 Server4 L4 Switc h - 일반적인 L4 Switch 기반의 Load Balancing - Client는 L4의 주소만 알고 있음 - L4 Switch는 Server의 목록을 알고 있음 (Server Side Load Balancer) - H/W Server Side Load Balancer 단점 (장점도 있지만..) - H/W가 필요 (비용↑, 유연성↓) - 서버 목록의 추가를 위해서는 설정 필요 (자동화 어려움) - Load Balancing Scheme이 한정적 (Round Robin, Sticky)
  • 49. Client Side Load Balancer - Ribbon Client (Caller) Server1 Server2 Server3 Server4 - Client (API Caller)에 탑재되는 S/W 모듈 - 주어진 서버 목록에 대해서 Load Balancing을 수행함 - Ribbon의 장점 (단점도 있지만… ) - H/W가 필요 없이 S/W로만 가능 (비용↓, 유연성↑) - 서버 목록의 동적 변경이 자유로움 - Load Balancing Scheme이 마음대로 구성 가능 R i b b o
  • 50. Client Side Load Balancer - Ribbon 단순한 Load Balancer ? ServerList - Load Balancing의 대상이될 Server 목록 결정 - 1) Configuration을 통해 직접 목록 설정 - 2) Discovery 기반으로 Runtime에 획득한 서버 목록 사용 IRule - 트래픽을 보낼 서버를 선택 - 1) Simple Round Robbin - 2) Response Time Weighted - 서버별 응답 시간에 따라 트래픽 양 조절 - 3) Availability Filter - 최근 3번 연속 에러를 발생시킨 서버를 Load Balancing 대상에서 일정 시간 동안 제외 시킴 (최초 5초, 4번째 실패시 10초. 2배씩 증가되며 최대 값이 기본 값 설정 가능)
  • 51. Client Side Load Balancer - Ribbon 단순한 Load Balancer ? IPing - 주기적으로 호출하여 해당 서버의 Aliveness를 검사 - 1) 특정 URL 호출 - 2) Discovery 기반 - Discovery 서버로 부터 가져온 목록에 있는지 확인 - Ping에 실패한 서버는 임시로 Load Balancing 대상에서 제외 ServerList, IRule, IPing 등 Ribbon의 주요 기능은 다양하게 설 정이 가능하며, 직접 구현하여 넣는 것도 가능
  • 52. Client Side Load Balancer - Ribbon Ribbon의 또 하나의 중요한 기능 - Retry Client (Caller) Server1 Server2 Server3 Server4 R i b b o O 선택된 대상으로의 호출 실패 시 정해진 횟수 만큼의 Retry 설정 가능 - 같은 서버 재시도 횟수, 다른 서버 재시도 횟수 설정 - Exception 발생 경우 뿐만 아니라 재시도 할 HTTP Status 지정 가능
  • 53. Client Side Load Balancer - Ribbon How to Use - 다양한 사용 방법이 존재….. - 직접 API 호출하여 대상 서버/포트 획득 후 사용 다양한 Http Client 및 Server에 이미 내장되어 있음 - Spring `RestTemplate` - @LoadBalanced RestTemplate - Spring Cloud Feign Client - Declarative Http Client - Ribbon이 내장되어 있음 - Zuul API Gateway - Ribbon이 내장되어 있음
  • 54. [실습 Step-2] RestTemplate에 Ribbon 적용하기 Tag : step-2-baseline 1. [product] ProductController 정상 코드로 복원 - 준비작업 (Application 정상화) - Sleep 제거 / Throw Exception 제거
  • 55. [실습 Step-2] RestTemplate에 Ribbon 적용하기 2. [display] build.gradle에 dependency 추가 - compile(‘org.springframework.cloud:spring-cloud-starter- ribbon’) 잠시 대기 후 외부 라이브러리에 아래 확인
  • 56. [실습 Step-2] RestTemplate에 Ribbon 적용하기 3. [display] DisplayApplication의 RestTemplate 빈에 @LoadBalanced 추가
  • 57. [실습 Step-2] RestTemplate에 Ribbon 적용하기 4. [display] ProductRemoteServiceImpl에서 주소 제거하고 `product`로 변경 5. [display] application.yml에 ribbon 설정 넣기 Tag : step-2-ribbon-loadbalanced - Ribbon의 기본은 eureka가 동작하므로 우선은 false (추후 설명) - listOfServers에 서버 목록 추가
  • 58. [실습 Step-2] RestTemplate에 Ribbon 적용하기 7. 확인 http://localhost:8081/displays/11111 동작 !!! RestTemplate에 주소가 아닌 단지 이름 `product`을 넣었는데 동작 Tag : step-2-ribbon-loadbalanced
  • 59. [실습 Step-2] RestTemplate에 Ribbon 적용하기 8. 정리 Tag : step-2-ribbon-loadbalanced - Ribbon 디펜던시 추가 후 RestTemplate에 `@LoadBalanced` 주석 - 설정에 특정 서비스(product)의 주소 설정 - RestTemplate 사용 시 주소 넣지 않고 서비스 이름(product) 사용 - 로드 발란스는 ???
  • 60. [실습 Step-2] Ribbon의 Retry 기능 1. [display] build.gradle 보기 Ribbon에는 Retry 기능이 내장되어 있어 하나의 서버에서 실패하면 다 른 서버로 재시도 가능 spring-retry 가 필요 2. [display] application.yml에 retry 추가 Tag : step-2-ribbon-retry * 현 시점의 Release에 default가 true이나 변경의 여지가 있어서 명시해 놓음
  • 61. [실습 Step-2] Ribbon의 Retry 기능 3. [display] applicaiton.yml에 서버 주소 추가 및 Retry 관련 속성 조 정 Tag : step-2-ribbon-retry 4 확인 http://localhost:8081/displays/11111 localhost:7777은 없는 주소 이므로 Exception 발생. 그러나 Ribbon Retry로 항상 성 공 -> Round Robin Client Load Balancing & Retry
  • 62. [실습 Step-2] Ribbon의 Retry 기능 5. 주의 - Retry를 시도하다가도 HystrixTimeout이 발생하면, 즉시 에러 반환 리 턴할 것이다. (Hystrix로 Ribbon을 감싸서 호출한 상태이기 때문에) - Retry를 끄거나, 재시도 횟수를 0으로 하여도 해당 서버로의 호출이 항 상 동일한 비율로 실패하지는 않는다. (IRule의 기본 구현에 의해 3회 실 패한 서버의 목록 제거) Tag : step-2-ribbon-retry 6. 정리 - Ribbon은 여러 Component에 내장되어있으며, 이를 통해 Client Load Balancing이 수행 가능하다. - Ribbon에는 매우 다양한 설정이 가능하다 (서버선택, 실패시 Skip 시간, Ping 체크) - Ribbon에는 Retry기능이 내장 되어있다. - Eureka와 함께 사용될 때 강력하다 (뒤에 실습)
  • 63. [실습 Step-2] Ribbon의 Retry 기능 Tag : step-2-ribbon-retry 7. 추가 정보 - Ribbon의 Retry는 기본적으로 Spring-Retry를 사용하며, Exception이 발생한 경우에 Retry가 시도됨 - Ribbon의 옵션으로 응답이 수신된 경우 특정 Status Code에 따라서 Retry를 시도하도록 설정하는 것도 가능 - ex) product.ribbon.retryableStatusCodes=502,503 - 현재 Release (Dalston.SR1)에 포함된 spring-cloud- commons(1.2.2)에 버그로 인하여 @LoadBalanced RestTemplate을 사용할 때 Status Code 기반의 Retry가 동작하 고 있지 앉음 - spring-cloud-commons 1.2.3에 수정될 예정이며 Dalston.SR2부터 지원될 예정
  • 64. Step-3 : Eureka Dynamic Service Discovery
  • 65. MSA를 적용한다고 하나의 서버를 여러개의 API 서버로 분할했는데… - 수많은 API 서버의 IP Address와 Port 번호는 어떻게 Caller에게 전달하 지 ? - L4도 없이 Client Load Balancer를 사용하는데, 각 Ribbon 설정에 언제 서버 주소와 포트 번호를 설정하지 ? 서버 분할 후 고민… “서버가 새롭게 투입되면 그것을 감지하여 목록에 자동으로 추가되고, 서버가 종료되면 자동으로 목록에서 삭제하기 위한 방법은 없을까 ?” “API를 호출하는 쪽에서도 상대방 주소(들)을 알 필요 없이 이름 만으 로 호출하게 할 수는 없을까 ? ”
  • 66. Dynamic Service Discovery - Eureka API Server “A” Eureka Client Eureka Server Service A ip1:8081 Service B Service C Service D API Caller “가” Eureka Client 0. Eureka를 사용할 모든 Server에 Eureka Client 탑재 주기적으로 Fetch ② 2. Eureka Client는 주기적으로 Service별 IP 목록을 Fetch 보관 서버 시작시 - 등록 / 종료시 - 제거 IP주소:port:”Service A” ① 1. 서버 가동시 자신의 정보(ip/port/서비스명)을 Eureka Server에 등록 (반대로 종료시 삭제) ③ Eureka에 획득한 주소로 호 출 3. API 호출시 서비스 이름 (Service A)를 사용하여 해당 서버 목록 획득 후 호출
  • 67. Dynamic Service Discovery - Eureka API Server “A” - instance #1 Eureka Client Eureka Server Service A ip1:8081 ip2:8081 ip3:8081 Service B Service C Service D 서버 시작시 - 등록 / 종료시 - 제거 IP주소:port:”Service A” API Server “A” - instance #2/3/4/5/6 Eureka Client Eureka Client Eureka Client Eureka Client Eureka Client 서버 인스턴스 추가 / 제거시 별도의 설정 작업 없이 가능
  • 68. Dynamic Service Discovery - Eureka Eureka Server 만들기 @EnableEurekaServer @SpringBootApplication public class EurekaServiceApplication { public static void main(String[] args) { SpringApplication.run(EurekaServiceApplication.class); } } - Eureka + Ribbon의 결합 시 Ribbon의 LoadBalancing 서버 목록을 Eureka를 통해서 공급 * dependency 추가 및 추가 설정 필요
  • 69. Dynamic Service Discovery - Eureka Eureka Client 만들기 - 내 서버 정보 등록 하기 - 내가 호출의 대상이 되고 싶을 때 @EnableEurekaClient @SpringBootApplication public class EurekaServiceApplication { public static void main(String[] args) { SpringApplication.run(EurekaServiceApplication.class); } } application.yml eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ - Spring Boot Application 작성 후 `@EnableEurekaClient` 만 주석을 달 고, 등록할 Eureka Server 정보를 설정하면 끝
  • 70. Dynamic Service Discovery - Eureka Eureka Client 만들기 - 다른 서버의 목록을 가져오고 싶을때 - 내가 Eureka에 등록된 서버 주소 목록을 알고 싶을때 - `DiscoveryClient`를 주입 받아 다양한 API 호출 가능 - 특별한 시나리오 없이 DiscoveryClient 직접 호출 필요 없음 - Ribbon이 DiscoveryClient를 이용해서 서버 목록을 가져옴. @EnableEurekaClient @SpringBootApplication public class EurekaServiceApplication { public static void main(String[] args) { SpringApplication.run(EurekaServiceApplication.class); } } application.yml eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ 앞 페이지 코드와 동일 @Service class ServiceInstanceRestController { @Autowired private DiscoveryClient discoveryClient; public void doSomething() { List<ServiceInstance> = this.discoveryClient.getInstances(applicationName); : } }
  • 71. [실습 Step-3] Eureka Server 실행 Tag : step-3-baseline 1. [준비작업] Eureka Server 띄우기 시간 절약을 위해 미리 준비된 Eureka Server 사용 > git reset HEAD --hard > git checkout tags/step-3-baseline -b my-step-3 2. [eurekaserver] 소스 보기 build.gradle application.yml : 데모용 각종 설정들 Main Class : @EnableEurekaServer
  • 72. [실습 Step-3] Eureka Server 실행 Tag : step-3-baseline 3. [eurekaserver] 서버 실행 EurekaServerApplication 실행 http://localhost:8761/ 확인
  • 73. [실습 Step-3] Eureka Client 적용하기 - Product 서버 Tag : step-3-eureka-product 1. [product] bulid.gradle compile('org.springframework.cloud:spring-cloud-starter-eureka') 2. [product] ProductApplication : @EnableEurekaClient 3. [product] application.yml OS에서 제공하는 hostname대신 자신의 ip address를 사용하여 등록
  • 74. [실습 Step-3] Eureka Client 적용하기 - Display 서버 Tag : step-3-eureka-display 4. [display] bulid.gradle compile('org.springframework.cloud:spring-cloud-starter-eureka') 5. [display] DisplayApplication : @EnableEurekaClient 6. [display] application.yml
  • 75. [실습 Step-3] Eureka Client 적용하기 - 서버 확인 Tag : step-3-eureka-display 7. Display / Product 서버 둘 다 재시작 후 Eureka 서버 확인 http://localhost:8761/ 확인
  • 76. [실습 Step-3] Eureka 서버 주소 직접 명시 Tag : step-3-eureka-addresses 8. [product/display] application.yml에 Eureka Server 주소 명시 default 값이 http://127.0.0.1:8761/eureka이므로 로컬 테스트 시 설정 불필요
  • 77. [실습 Step-3] Eureka 서버 주소 직접 명시 Tag : step-3-eureka-addresses 9. 정리 @EnableEurekaServer / @EnableEurekaClient를 통해 서버 구축, 클라이언트 Enable 가능하다. @EnableEurekaClient를 붙인 Application은 Eureka 서버로 부터 남의 주소를 가져오는 역할 과 자신의 주소를 등록하는 역할을 둘다 수행 가능하다. Eureka Client가 Eureka Server에 자신을 등록할 때 `spring.application.name`이 이름으로 사용된다.
  • 78. [실습 Step-3] RestTemplate에 Eureka 적용하기 Tag : step-3-eureka-completed 1. 목적 Display -> Product 호출시에 Eureka를 적용하여 ip주소를 코드나 설정 `모두`에서 제거하려고 함. 2. [display] application.yml 변경 (주석 처리) product.ribbon.eureka.enabled = false 제거 -> ribbon의 default는 eureka 사용 product.ribbon.listOfServers 제거 -> 서버 주소는 Eureka Server에서 가져와라 !
  • 79. [실습 Step-3] RestTemplate에 Eureka 적용하기 Tag : step-3-eureka-completed 3. [확인] display 서버 재시작 http://localhost:8081/displays/11111 - Product의 주소가 설정/코드에서 모두 제거 - 코드에서는 http://product/으로 접근 4. 정리 - @LoadBalanced RestTemplate에는 Ribbon + Eureka 연동 - Eureka Client가 설정되면, 코드상에서 서버 주소 대신 Application 이름을 명시해서 호출 가능 - Ribbon의 Load Balancing과 Retry가 함께 동작
  • 80. Step-4 : Spring Cloud Feign Declarative Http Client > git checkout tags/step-4-baseline -b my-step-4 * 앞선 예제 못따라 오신 분들이나, 늦게 참여하신 분들은 막바로 Git 이동
  • 81. Declarative Http Client - Spring Cloud Feign 인터페이스 선언 만으로 Http Client 구현물을 만들어 줌 @FeignClient(name="dp", url = "http://localhost:8080/") public interface ProductResource { @RequestMapping(value = "/query/{itemId}", method=RequestMethod.GET) String getItemDetail( @PathVariable(value = "itemId") String itemId); } - @FeignClient를 Interface에 명시 - 각 API를 Spring MVC Annotation을 이용해서 정의 @Autowired ProductResource productResouce; How to Use - @Autowired를 통해 DI 받아 사용
  • 82. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 1. 목적 Display -> Product 호출시에 Feign을 사용해서 RestTemplate 을 대체해 보려고 함. 2. [display] build.gradle에 dependency 추가 compile('org.springframework.cloud:spring-cloud-starter- feign')
  • 83. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 3. [display] DisplayApplication에 @EnableFeignClients 추가 4. [display] Feign용 Interface 추가 - 이전 `ProductRemoteService` 사용하지 않고 데모를 위해 별도 정의
  • 84. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 5. [display] FeignProductRemoteService에 Annotation 넣기
  • 85. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 5. [display] FeignProductRemoteService에 Annotation 넣기 Client 구현 완성. 서버 가동시 `FeignProductRemoteService`용 Spring Bean 자동 생성 `FeignProductRemoteService`를 주입 받아서 사용하면 됨.
  • 86. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 6. [display] DisplayController에서 호출 부분 변경 기존 RestTemplate사용했던 서비스 대신 Feign이 자동으 로 생성해준 서비스 빈을 사용
  • 87. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 7. 동작 확인 http://localhost:8081/displays/11111 8. 정리 Feign은 Interface 선언을 통해 자동으로 HTTP Client를 만들어 주는 Declarative Http Client Open-Feign 기반으로 Spring Cloud가 Wrapping한것이 오늘 실습한 Spring Cloud Feign 방금 한 실습 (Feign + URL 명시)는 - No Ribbon - No Eureka - No Hystrix
  • 88. [실습 Step-4] Feign 클라이언트 사용하기 Tag : step-4-feign-url 9. 부가 정보 - Feign Client의 Interace에 SpringMVC의 Annotation을 사용하는 경우에 SpringMVC와 달리 parameter이름을 항상 명시해 주어야 함 - ex) - Spring MVC : @PathVariable String productId - Feign Client : @PathVariable(“productId”) String productId - Java 8을 사용하는 경우 “-parameters” 옵션과 함께 컴파일 하면 해 결 가능. - Spring MVC에서는 Parameter이름을 Reflection으로 못가져오 오는 경우 Class 파일속의 Debugging Info에서 꺼내오나, Feign의 경우 Interface에 Annotation을 사용하며 Interface의 경우 이 Debugging Info가 존재하지 않음. - 이 옵션을 사용하지 않는 경우 직접 명시 필요
  • 89. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-eureka 1. 배경 Feign의 또 다른 강점은 Ribbon + Eureka + Hystrix와 통합되어 있다는 점. 2. [display] Feign에 Eureka + Ribbon 적용하기 @FeignClient에서 url만 제거 완성 !!!
  • 90. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-eureka 3. Feign의 동작 @FeignClient에 URL 명시 시 -> 순수 Feign Client로서만 동작 @FeignClient에 URL 명시 하지 않으면 ? -> Feign + Ribbon + Eureka 모드로 동작 -> 어떤 서버 호출하나 ? @FeignClient(name=“product”) -> 즉, eureka에서 product 서버 목록을 조회해서 ribbon을 통 해 load-balancing하면서 HTTP 호출을 수행
  • 91. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-eureka 4. [display] application.yml : Feign + Hystrix 위의 설정이 들어가면 메소드 하나 하나가 Hystrix Command 로 서 호출 된다. !!! 5. Feign에서 Fallback은 ? Hystrix 설정은 ?
  • 92. Declarative Http Client - Spring Cloud Feign 그럼 Hystrix Fallback은 ?? @Component public class ProductResourceFallback implements ProductResource { @Override public String getItemDetail(String itemId) { return “default value”; } } - Fallback 클래스를 @Feign선언시 명시 - Feign으로 정의한 Interface를 직접 구현 하고 Spring Bean으로 선언 @FeignClient(fallback= ProductResourceFallback.class, name=“dp", url = “http:// localhost:8080/“) public interface ProductResource { @RequestMapping(value = "/query/{itemId}", method=RequestMethod.GET) String getItemDetail( @PathVariable(value = "itemId") String itemId); }
  • 93. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-hystrix 6. [display] Feign용 Hystrix Fallback 선언 - Spring Bean으로 정의 7. [display] Feign용 Hystrix Fallback 명시 @FeignClient에 `fallback` 속성으로 클래스 명시
  • 94. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-hystrix-properties 8. [display] Feign용 Hystrix 프로퍼티 정의하는 법 Feign 사용하는 경우 commandKey 이름 주의 ex) FeignProductRemoteService#getProductInfo(String)
  • 95. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-hystrix-properties 9. 추가정보 - Spring Cloud Feign에 의해서 생성된 Bean은 자동으로 @Primary 가 선언됨 - 따라서 동일 타입의 다른 빈에 비해서 Autowired 시 우선순위를 갖음 - 옵션을 통해 Primary 속성 제거 가능
  • 96. [실습 Step-4] Feign + Hystrix,Ribbon,Eureka Tag : step-4-feign-eureka 정리 Feign은 인터페이스 선언 + 설정으로 다음과 같은 것들이 가능하다 - Http Client - Eureka 타겟 서버 주소 획득 - Ribbon을 통한 Client-Side Load Balancing - Hystrix를 통한 메소드별 Circuit Breaker
  • 97. Step-5 : Zuul API Gateway for MSA
  • 98. WAR Front/ WAR Front/ ? 첫번째 고민 - Legacy Application에서 새로 만들어진 수많은 API 서버들을 어떻게 호출할까 ? - Old S/W Stack, 대단위 수정 배포의 Risk 등으로 Eureka, Ribbon 등을 Legacy Application에 직접 탑재하는 것이 어려움 Legacy/App로 부터의 호출
  • 99. WAR Front/ WAR Front/ ? 두번째 고민 - 모든 API 서버들에 들어갈 공통된 기능을 구현할 곳과, 전체 API 호출을 통제할 곳이 필요해 “전체 API Server들의 맨 앞단에 API Gateway의 도입으로 해결 가 능” Legacy/App로 부터의 호출
  • 100. API Gateway - Zuul - API의 외부 노출을 위한 Endpoint - URL별로 Mapping된 Server 군으로 API 호출을 Forward - ? Box 만이 다른 API Gateway와의 차별점
  • 101. API Gateway - Zuul 1. HystrixCommand 1. Zuul의 모든 API 요청은 HystrixCommand로 구성되어 전달된다. - 각 API 경로 (서버군) 별로 Circuit Breaker 생성 - 하나의 서버군이 장애를 일으켜도 다른 서버군의 서비스에는 영향이 없다. - CircuitBreaker / ThreadPool의 다양한 속성을 통해 서비스 별 속성에 맞는 설정 가능 Service “A” Servers
  • 102. API Gateway - Zuul 1. HystrixCommand 2. API를 전달할 서버의 목록을 갖고 Ribbon을 통해 Load-Balancing을 수행 한다. - 주어진 서버 목록들을 Round-Robin으로 호출 - Coding을 통해 Load Balancing 방식 Customize 가능 Service “A” Servers 2. Ribbon
  • 103. API Gateway - Zuul 1. HystrixCommand 3. Eureka Client를 사용하여 주어진 URL의 호출을 전달할 “서버 리스트”를 찾는다. - Zuul에는 Eureka Client가 내장 - 각 URL에 Mapping된 서비스 명을 찾아서 Eureka Server를 통해 목록을 조회 한다. - 조회된 서버 목록을 `Ribbon` 클라이언트에게 전달한다. Service “A” Servers 2. Ribbon 3. Eureka Client
  • 104. API Gateway - Zuul 1. HystrixCommand 4. Eureka + Ribbon에 의해서 결정된 Server 주소로 HTTP 요청 - Apache Http Client가 기본 사용 - OKHttp Client 사용 가능 Service “A” Servers 2. Ribbon 3. Eureka Client 4. Http Client
  • 105. API Gateway - Zuul 1. HystrixCommand 5. 선택된 첫 서버로의 호출이 실패할 경우 Ribbon에 의해서 자동으로 Retry 수행 - Retry 수행 조건 - Http Client에서 Exception 발생 (IOException) - 설정된 HTTP 응답코드 반환 (ex 503) Service “A” Servers 2. Ribbon 3. Eureka Client 4. Http Client 5. Retry By Ribbon
  • 106. API Gateway - Zuul 1. HystrixCommand Zuul의 모든 호출은…. Service “A” Servers 2. Ribbon 3. Eureka Client 4. Http Client 5. Retry By Ribbon - HystrixCommand로 실행되므로 Circuit Breaker를 통해 - 장애시 Fail Fast 및 Fallback 수행 가능 - Ribbon + Eureka 조합을 통해 - 현재 서비스가 가능한 서버의 목록을 자동으로 수신 - Ribbon의 Retry 기능을 통해 - 동일한 종류의 서버들로의 자동 재시도가 가능
  • 107. API Gateway - Zuul 부가 정보 - Spring Cloud Zuul에서 사용하는 Hystrix Command는 기본적으로 Thread Pool 방식이 아닌 Semaphore 방식을 사용 - Thread Pool을 사용하기 위해서는 설정 변경 필요 - Spring Cloud Zuul에서는 기본 설정으로 `RibbonCommand`라는 하나의 Global Thread pool을 모든 Route에 대해서 공유 - 각 Route 별로 분리하는 것이 Zuul의 안정성에 도움이 되며 이를 위해서는 추가적인 설정이 필요
  • 109. Lessons Learned “Open Source를 100% 신뢰하지는 말것” Documentation은 부실할 수 있으며, Bug가 다수 존재할 수 있으며, 심지어 Bug가 발견되어도 아무도 급하게 Bug를 수정해 주지 않는다. Source 보는 것을 두려워 하지 않으며, 확인이 필요한 중 요한 기능은 소스코드를 확인하라 Github의 Issues / Pull Request를 자주 확인하라
  • 110. Lessons Learned “Test, Test, Test” Open Source의 현재 동작하던 기능이 Version Up과 함 께 사라지거나 다르게 동작할 수 있다. Property는 쉽게 추가되거나 삭제될 수 있다. 대부분의 경우 우리는 이러한 변화를 인지하지 못한다. Open Source를 통해 사용하는 주요 기능에 대해서 Integration 테스트를 작성하여 Version Up 이후에도 여전 히 원하는 대로 동작하는지 확인하라 ex) 틀린 주소를 주입하고 우리의 Fallback이 호출되는 지 확인하는 테스트