일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Spring Cloud Netflix
- 백명석님
- ksql
- aws
- 자바 ORM 표준 JPA 프로그래밍 정리
- CompletableFuture
- 원격 브랜 삭제
- ksqldb
- @TransactionalEventListener
- 자바 ORM 표준 JPA 프로그래밍
- 리팩토링 2판
- javascript case
- 친절한 SQL 튜닝
- findTopBy
- intellij 즐겨찾기
- @Transactional Propagation
- intellij 핵심 단축키
- JPA
- 리눅스
- vue.js
- java
- git
- Linux
- multipart테스트
- HandlerMethodArgumentResolver
- intellij favorites
- #docker compose
- IntelliJ
- Stream
- 마이크로 서비스
- Today
- Total
시그마 삽질==six 시그마
Spring Cloud Netflix 본문
11번가의 MSA 전환 관련 동영상을 보고 정리한 내용입니다
https://www.youtube.com/watch?v=J-VP0WFEQsY&list=WL&index=100&t=3419s
https://www.youtube.com/watch?v=D6drzNZWs-Y&list=PL9mhQYIlKEhdtYdxxZ6hZeb0va2Gm17A5
spring.io/projects/spring-cloud-netflix
모노리틱 구조에서
업무 도메인 별로 (혹은 더 잘게) 서버 분리
-Legacy 코드에서는 한개씩 새로운 api 서버들을 호출(한개씩 옮김)
-기존 코드와 새로운 API 호출은 DB flag를 통해서 switchable하게 롤백가능하게
netflix OSS --> Spring Cloud Netflix
1. Hystrix
Netflix가 만든 Fault Toerance Library
-장애 전파 방재 & Resilience
기능적 관점에서 본 Hytrix의 주요 4가지 기능
-Circuit Breaker
-Fallback
-Thread Isolation
-Timeout
HystrixCommand호출시 벌어지는일
1)이 메소드를 Intercept하여 대신 실행한다 -Thread Isolation
두가지 Isolation 방식을 Circuit Breaker 별로 지정 가능
(1)Semaphore(optional)
-Circuit Breaker 1개당 1개의 Semaphore 생성
- Semaphore별로 최대 동시 요청개수 지정
-최대 개수 초과시 Semaphore Rejection 발생 -Fallback 실행
-Command를 호출한 Caller Thread에서 메소드 실행
*Timeout이 제 시간에 발생하지 못함
(2)Thread(default)
-Circuit Breaker별로 사용할 Thread Pool을 지정(ThreadPoolKey)
-Circuit Breaker: Thread Pool = N:1 관계 가능
- 최대 개수 초과시 Thread Pool rejection 발생 -Fallback 실행
-Command를 호출한 Caller Thread가 아닌 Thread Pool에서 메소드 실행
“실제 메소드의 실행은 다른 Thread에서 실행되므로 Thread local 사용시 주의 필요”
2) 메소드의 실행 결과 성공 혹은 실패(exception) 발생 여부를 기록하고 통계를 낸다.
통계에 따라 Circuit Open여부를 결정한다 -Circuit Breaker
(1)일정 시간 동안 (2)일정개수 이상의 호출이 발생한 경우, (3) 일정 비율 이상의 에러가 발생하면—>Circuit Open(호출차단)
(4)일정시간 경과 후에 단 한개의 요청에 대해서 호출을 허용하며(Half Open) 이 호출이 성공하면—>Circuit Close(호출허용)
Hystrix Circuit Breaker는 한 프로세스 내에서 주어진 CommandKey 단위로 통계를내고 동작한다
-즉, Circuit Breaker는 CommandKey 단위로 생성된다. 같은 서비스를 호출하는 로직이면 키를 똑같에 만들어서 같이 통계를 내고 서킷브레이크 되게 만든다.
“동일한 Dependency를 갖는 Hystrix Command를 동일한 CommandKey로 묶는것을 고려해야함”
hystrix:
command:
productInfo: # command key. use 'default' for global setting.
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
circuitBreaker:
requestVolumeThreshold: 20 # Minimum number of request to calculate circuit breaker's health. default 20
errorThresholdPercentage: 50 # Error percentage to open circuit. default 50
sleepWindowInMilliseconds: 5
10초간 20개 이상의 호출이 발생한경우 50% 이상의 에러가 발생하면 5초간 circuit open
@Override
@HystrixCommand(commandKey = "productInfo", fallbackMethod = "getProductInfoFallback")
public String getProductInfo(String productId) {
return this.restTemplate.getForObject(url + productId, String.class);
}
public String getProductInfoFallback(String productId, Throwable t) {
System.out.println("t = " + t);
return "[ this product is sold out ]";
}
3) 실패한 경우(exception) 사용자가 제공한 메소드를 대신 실행한다 -Fallback
ex) 추천상품 뻑나면 고정상품 보여주기
Fallback으로 지정된 메소드는 다음의 경우에 원본 메소드 대신 실행된다
-Circuit Open
-Any Exception(HystrixBadRequestException 제외)
-Semaphore/ ThreadPoolRejection(나중 Isolation에서 설명)
-Timeout
써킷이 실행되야 실행되는거 x
fallback을 잘못사용하면 우리 장애나 비지니스로직의 에러를 감추게된다
익셉션이 fallback으로 감쳐짐.
MSA는 모노리틱보다 빠를순 없다.
사용자가 잘못넘긴 데이터는 illigalArgu...이런 익셉션 말고 HystrixBadRequestException 로 던져라!!!
“사용자의 코드에서 HystrixBadRequestException을 발생시키면
이오류는 Fallback을 실행하지 않으며 Circuit breaker를위한 통계에도 집계되지 않는다.
Method Caller의 실수(ex)잘못된 파라미터 전달)의 경우임.
HystrixBadRequestException을 Throw하게 작성할 필요가 있다.
만약 Caller의 실수를 다른 Exception으로 던지면
-Circuit Breaker의 통계에 집계되어 Caller의 잘못으로 Circuit이 Open
-Fallback이 실행되어 개발과정에 오류를 인지하지 못할 수 있다.
4) 특정시간 동안 메소드가 종료되지 않은 경우 Exception을 발생시킨다 -timeout
jdbc 타입아웃,소켓타임아웃은 언제 타임아웃될지 몰라서 서비스레이어에 이런 타임아웃두기 적당함
Hystrix에서는 Circuit Breaker 단위로 (CommandKey 단위로) Timeout을 설정할 수 있다.
hystrix.command.<commandKey>.
execution.isolation.thread.timeoutInMilliseconds -default 1초
-semaphore Isolation인 경우 - 제 시간에 Timeout이 발생하지 않는 경우가 대부분이다.
-default 값이 매우 짧다 1초
2. Ribbon
Netflix가 만든 Solfware Load Balancer를 내장한 RPC(REST) Library
-Client Load Balancer with HTTP Client
Server(caller)(Ribbon) ->server1, server2,server3…
Spring Cloud 에서는 Ribbon 클라이언트를 사용자가 직접 사용하지 않음
-Spring cloud의 HTTP 통신이 필요한 요소에 내장되어 있음
* Zuul API Gateway
* RestTemplate(@LoadBalanced)
* Spring Cloud Feign- 선언적 http Client
Ribbon이 기존 Load Balancer와 다른점
Ribbon은 대부분의 동작은 Programmable함! 기존 하드웨어 로드밸런싱 갈증해소
Spring Cloud에서는 아래와 같은 BeanType으로
IRule- 주어진 서버 목록에서 어떤 서버를 선택할 것인가(1/n..트래픽..)
Iping -각 서버가 살아있는가 검사
ServerList<Server>-대상 서버 목록 제공
ServerListFilter<Server> -대상 서버들 중 호출할 대상 filter
ServerListUpdater
IClientConfig
ILoadBalancer
3. Eureka
Netflix가 만든 Dynamic Service Discovery
-등록 : 서버가 자신의 서비스 이름(종류)와 IP주소, 포트를 등록
-조회: 서비스 이름(종류)를 갖고 서버 목록을 조회
Eureka Server
ServiceA: ip1:8081 <———등록————Service A (Eureka Client)
ServiceB: ip2:8080 ip3:8080— 조회——> Service B(Eureka Client)
ServiceC: ip4:8081 ip5:8080 ip6:8080
ServiceD: ip7:8081
Eureka가 Enable 된 Spring Cloud Application은
-Server 시작 시 Eureka 서버에 자동으로 자신의 상태 등록(UP)
-주기적 HeartBeat으로 Eureka Server 자신이 살아 있음을 알림
-Server 종료시 Eureka 서버에 자신의 상태 변경(DOWN) 혹은 자신의 목록 삭제
-Eureka 상에 등록된 이름은 ’spring.application.name’
Eureka+Ribbon in Spring Cloud
하나의 서버에 Eureka Client와 Riboon Client가 함께 설정되면 Spring cloud는 다음의 Ribbon Bean을 대체
1.ServerList<Server>
-기본 : ConfigurationBasedServerList
-변경:DiscoveryEnabledNIWSServerList
2.IPing
-기본 : DummyPing
-변경: NIWSDiscoverPing
서버의 목록을 설정으로 명시하는 대신 Eureka를 통해서 Look up해오는 구현
4. Spring Cloud Zuul
API Gateway
MSA 환경에서 API Gateway의 필요성
-Single Endpoint 제공
*API 를 사용할 Client들은 API Gateway 주소만 인지
-API의 공통 로직 구현
*Logging,Authentication,Authorization
-Traffic Control
*API Quota, Throttling
Spring Cloud Zuul은 API Routing을 Hystrix,Ribbon, Eureka를 통해서 구현
-Spring Cloud와 가장 잘 Intergration 되어있는 API Gateway
Spring Cloud Zuul
Product——>Product Api Server(API Server,Api Server…)
Display——>Display Api Server(API Server,Api Server…)
Member——>Member Api Server(API Server,Api Server…)
zuul을 사용하면 알아서 엔드포인트 매칭 관리해준다
“API 요청들은 각각 HystrixCommand를 통해서 실행되며 각 API 의 Routing은, Ribbon&Eureka의 조합으로 수행”
Hystricx Command->Ribbon Client->Eureka Client, Http Client
-Hystrix Circuit Breaker는 ComandKey 이름 단위로 동작하는 반면
Spring Cloud Zuul에서 Hystrix CommandKey는 각 서버군 이름(Zuul용어로 Service Id, Eureka에 등록된 서버군 이름)이 사용됨
앞선 그림의 예를 들면 3개의 commandKey가 사용
hystrix.command.[product|display|member].xxxx
Hystrix 는 Isolation 기본이 Thread Isolation모드가 기본인반면 Spring Cloud Zuul에서 Hystrix Isolation은 -Semaphore Isolation을 기본으로 한다. 그러면 단점이 타임아웃을 컨트롤할 수 없다
so Spring Cloud Zuul에서 Hystrix Isolation을 Thread Isolation으로 변경하는 방법
zuul:
ribbon-isolation-strategy: thread
이것만하면 서버전체 한개의 Thread Pool이 생겨버림.
so 하단 추가해야 서비스별로 zuul 쓰레드 풀 생김(11번가 요청으로 수정됨)
zuul:
thread-pool:
use-separate-thread-pools: true
thread-pool-key-prefix: zuul-
Server to Server 호출 in MSA
“MSA 플랫폼 내부의 API Server 간의 호출은 어떻게 할 것인가?”
일반적으로 MSA 플랫폼 외부의 호출은 API Gateway를 단일 창구로 사용.but api gateway에 심각한 의존(single point of failure)
api서버들끼리 직접호춟 방식
“Ribbon +Eureka 조합으로 Peer to Peer 호출을 하기로 결정”
Spring Cloud 에서는 다음의 Ribbon+Eureka 기반 Http호출 방법을 제공
-@LoadBalanced RestTemplate
*@LoadBalanced 주석을 붙이는 경우 RestTemplate이 Ribbon+Eureka 기능을 갖게 됨
*RestTemplate이 Bean으로 선언된 것만 적용가능
-Spring Cloud Feign
5. Feign
Declarative Http Client
Java Interface+Spring MVC Annotaion 선언으로 Http 호출이 가능한 Spring Bean을 자동생성
-OpenFeign 기반의 Spring Cloud 확장
-Hystrix+Ribbon+Eureka와 연동되어 있음
//Ribbon+Eureka 없이 사용하기 -url 직접명시
@FeignClient(name = "product", url = "http://localhost:8082/")
public interface FeignProductRemoteService {
@RequestMapping(path = "/products/{productId}")
String getProductInfo(@PathVariable("productId") String productId);
}
//Ribbon+Eureka연동 -url 생략
@FeignClient(name = "product", fallbackFactory = FeignProductRemoteServiceFallbackFactory.class)
public interface FeignProductRemoteService {
@RequestMapping(path = "/products/{productId}")
String getProductInfo(@PathVariable("productId") String productId);
}
요기서 name은 내 Client이름인 동시에 내가 찌를 서버의 이름임.
interface로 만드는게 대세
Spring Cloud Feign with Hystrix
Hystrix 연동하기
-Hystrix가 Classpath에 존재
-feign.hystrix.enabled=true
Spring Cloud Feign with Feign, with Hystrix,Ribbon,Eureka
-호출하는 모든 메소드는 Hystrix Command로 실행
*Circuit Breaker, Timeout,Isolation,Faalback 적용
-호출할 서버는 Eureka를 통해 얻어서, Ribbon으로 Load Balancing되어 호출
Hystricx Command->Ribbon Client->Eureka Client, Http Client
6.장애 유형별 동작 예
서버군을(3개) 구축했는데 한개 인스턴스가 장애난경우
1)특정 API서버의 인스턴스가 한개 down된 경우
EUREKA-Heartbeat송신이 중단됨으로 일정 시간 후 목록에서 사라짐
(4단계거침. 파라미터 옵션값 조정으로 사라지는 시간 설정가능.기본 사라지는데 60~90초. out of service 명령으로 즉시 뺄수도 있음)
Ribbon- IOException이 발생한 경우 다른 인스턴스로 Retry함(같은 서버찌를건지,다른서버 찌를건지 선택가능)
Hystrix- Circuit은 오픈되지 않음(Error=33%이기에) Fallback,Timeout은 동작
2) 특정 APi가 비정상 동작하는 경우(지연,에러)
Hystrix-해당 API를 호출하는 Circuit Breaker 오픈 Fallback,Timeout 동작
7. 11st with Spring Cloud
Spring Cloud Zuul(Hystrix+Ribbon+Eureka)+ EurekaServer+Spring Cloud Config Server
—>전체 Api server
Api server <—>Api server
Api server 는 Spring Cloud Feign+Hystrix+Ribbon+Eureka client
모든 MSA Platform 내의 서버는 Eureka Client를 탑재
API Server들간의 호출도 Spring Cloud Feign을 통해 Hystrix+Ribbon+Eureka client조합으로 호출
Spring Cloud Config
Git 기반의 Config 관리
플랫폼 내의 모든 Server들은 Config Client를 탑재
서버 시작시 Config 서버가 제공하는 Config들이 PropertySource로 등록됨
Spring Cloud Config Server —Clone & fetch—>Git Repo(config file)
Spring Cloud Config Server <—모든 Api Server, Eureka,Zuul (3개에 Spring Cloud Config Client 전부 설치)
Git Repository내의 Config 파일들은 다양하게 구성 가능
-전체 서버 공통 Config
- 서버군용 Config
- 특정 서버용 Config
but 이걸 사용하면 system property보다 더 높은 우선순위 갖기에 콘솔에서 -D로 띄워도 변경불가함.(근데 이 두개 우선순위 조정가능함 system prop높게 설정해라)
git으로 올라가다보니 watch해서 property 실수를 예방할 수 있다.
8. MSA 운영 환경을 위한 전용 모니터링 도구들
-Zipkin, Turbine, Spring Boot Admin
분산 Tracing에서 서버간 trace 정보의 전달
서버간의 trace 정보의 전달은 사용 Portocol의 헤더를 통해 전달 필요
ex) HTTP Header
대표적인 서비스는 트위터의 Zipkin
but
In Process 에서 Trace 정보의 전달 문제
다양한 Library에 의한 Thread 변경으로 인한 Trace 정보 전달이 어려움
-단순한 Thread Local에 저장하는 방식을 사용하기 어렵다
-Hystrix,RxJava, @Async….
Spring Cloud Sleuth
Spring Cloud 에서 제공하는 Distributed Tracing 솔루션
-대부분의 내외부 호출 구간에서 Trace정보를 생성 및 전달
-Log에 남기거나 수집 서버(zipkin)에 전송하여 검색/시각화
Spring Cloud Sleuth가 지원되는 Component?
-Zuul,Servelt,RestTemplate,Hystrix,Feign,RxJava
디펜던씨 한줄이면 Application 로그에 Trace Id(UUID)가 함께 출력
서버이름,이 request의 UUID, uuid속에 소속된 단위 Id, 샘플링유무
Trace Id= 하나의 Request에 대해 서버 전체를 걸쳐 동일한 UUID
“로그 수집/검색 시스템이 있다면 동일 요청에 해당하는 전체 서버의 로그 분석 가능”
위 로그를 시각화하면 할수있는데 바로 zipkin을 사용하면됨
Spring Cloud Sleuth with Zipkin
Spring cloud Sleuth로는 DB 호출 구간은 표현안됨
Spring Aop를(Repository와 mybatis mapper에 aop걸고) 사용해서 Sleuth API로 DB 관련 trace 정보를 직접생성
모든 소스들은 pull request를 거치지 못하면 머지되지 못한다.
pull Request Reviewer들은 팀 전원을 넣는다.
zipkin은 모든 trace를 달지만 대쉬보드 보여주는건 샘플링 1~100% 기반으로 함.
크롬 확장프로그램 Zipkin Extenstion사용시 운영화면 열고 익스텐션 사용하면 샘플링되지 않은 트래픽등 전체 다 시각화해서 볼수있는데 개발에서 slow API 검수하는 목적으로도 많이쓰임.
Hystrix 모니터링 with Turbine
Success 성공횟수
Short0Circuieted 차단횟수
Bad Request 사용자 입력오류(콜러가 파라미터 잘못날려서 api호출한거등)
Timeout 시간초과(지연)
Rejected isolation초과(semaphore,Thread Pool 꽉차서)
Failure 일반오류
Error 전체 에러 비율
TPS도 확인가능
모든 서버와 서버간의 관계, 모든 서버와 서버간의 메소드 단위로 에러비율,TPS 확인가능
아쉬운건 real time이라는것 어제의 오류사항 볼수 없음
그걸 보완하기 위해 InfluxDB에 일주일치의 Hystrix Metrics 보관
Grafana를 통해 Dashboard를 구성
Spring Boot Admin
Eureka에 등록되어 있는 모든 서버의 정보를 표시/제어
spring boot Actuator를 호출
Open Source를 사용한다는것
버그 부실 -> source code가 주어졌기에 무엇이든지 할 수 있다는 자신감
-bug report, 수정과 문서의 보강은 사용자의 몫
정확한 동작원리 알 수 있음..
Vine Admin
-운영시 필요한 추가 기능 구현
-Eureka Server 상태변경
-Zuul 내부 Eureka/Ribbon상태 확인 &강제변경
zuul - 오픈소스 jar 가져온게 아니라 소스 복사해 사용
eureka -eureka위에 스프링의 많은 기능 더 추가함
hystrix- jar그대로 쓰고 있음.
git에 config 변경했으니 애플리케이션에 가져가라고 refresh하는 기능이 있다.
스프링의 싱글톤이란 스콥말고 refresh라는 스콥이 하나 더 있다.
리프레시하면 내부적으로 빈 새로 만든걸 갈아낀다. 그러나 위험이 있어서 서버 재가동 없이 동적재가동 안한다.
MSA 트랜잭션 관리 불가 방안
api 에러는 DB에 update insert했는지 모른다는거다. DB업데이트 후 네트워크에러일수도 있다.
1. update가 필요한 api는 put으로 멱등성 있게 작성해서 최대한 retry하게 하라
1) 여러번 update 상관x
2) one insert <---Request에 대한 처리여부를 비지니스처리와 함께 저장
2. 무조건 보상 api를 함께 작성해라.
api 업데이트할때 UUID 함께 넘겨서 에러코드가 발생했다면 DB삽입후 발생했는지 삽입전 발생했는지 상관하지 말고 200이 아니면 보상을 호출하게 해서 서버 DB 상태를 원래대로 회복시킬 수 있게 한다.
3. 사용자 응답 필요없는 update는 스프링 카프카로 이벤트기반으로 처리한다
'프로그래밍 > Spring' 카테고리의 다른 글
Spring webflux (0) | 2022.07.19 |
---|---|
Spring batch 요약 (0) | 2020.10.25 |
@TransactionalEventListener (0) | 2020.10.22 |
Spring Kafka Basic (0) | 2020.08.25 |
ObjectMapper & OrikaMapper basic (0) | 2020.08.24 |