Spring cloud Netflix

2021. 5. 13. 10:41·IT/API Gateway

https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.1.2.RELEASE/single/spring-cloud-netflix.html

 

Spring Cloud Netflix

Ribbon is a client-side load balancer that gives you a lot of control over the behavior of HTTP and TCP clients. Feign already uses Ribbon, so, if you use @FeignClient, this section also applies. A central concept in Ribbon is that of the named client. Eac

cloud.spring.io

[써킷브레이커]

https://netflixtechblog.com/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a

 

Fault Tolerance in a High Volume, Distributed System

How our API and other systems isolate failure, shed load and remain resilient to failures

netflixtechblog.com

 

https://blog.naver.com/pollra32/221589005337

 

Spring Cloud(Netflix OSS) - Hystrix

아래의 포스팅은 다음의 강의를 보고 까먹지 않게 기록한 것입니다. https://youtu.be/iHHuYGdG_Yk ...

blog.naver.com

[Hystrix]

Hystrix

Netflix OSS 에 포함된 도구중 하나로서 AWS 안의 여러 컴포넌트와 자동화 도구를 사용하며 파악한 패턴과 해결법을 블로그, 오픈소스로 공개한 것들 중 하나입니다.

​

어떨때 사용?

MSA 환경 에서는 A 서버에서 B 서버에 요청을 날렸을때 네트워크 문제 혹은 서버 자체의 에러 등 여러가지 문제때문에 서버에 대한 Request 를 100% 받는다는 보장을 할 수 없게됩니다.

이 경우에 사용할 수 있는 기능이 바로 Hystrix 입니다.

​

기능 간단 설명

한 서버가 특정 요청을 받았는데 주어진 시간내에 요청을 처리하지 못 할 경우 Hystrix 는 들어온 요청의 갯수, 요청의 성공여부, 요청의 실패 여부를 기록하여 통계를 냅니다.

내부적으로 Hystrix 은 인터셉터를 만들어서 사용자의 요청을 계산합니다.

10초(기본 설정값)동안 20개(기본 설정값)의 요청이 들어왔을 때 50%(기본 설정값)이상의 호출에서 에러가 날 경우 Circuit Open 을 진행하게됩니다. 이 값은 수정될 수 있으며 아래에서 수정하는 방법이 나와있습니다.

​

Circuit Open?

Circuit Open 이란, 주어진 시간동안 호출이 제한되며 즉시 에러를 반환하는 기능을 말합니다. 장점은, 시스템에 대한 연동을 조기에 차단(Fail Fast) 시킴으로서 시스템을 보호하게됩니다.

Circuit Open 된 경우 Fallback 메소드를 통해 에러를 반환합니다.

​

사용방법 jdk 1.8 기준의 코드입니다.

Hystrix 의존성 추가

compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix')

Hystrix 의 Circuit Breaker 를 사용할 앱의 @SrpingBootApplication 아래에 @EnableCircuitBreaker 애노테이션 추가

@SpringBootApplication @EnableCircuitBreaker public class DisplayApplication { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DisplayApplication.class); } }

Hystrix 이 통계를 낼 서비스에게 다음의 애노테이션을 추가.

@HystrixCommand(fallbackMethod = "getProductInfoFallback") public String getProductInfo(String productId) { return restTemplate.getForObject(URL +productId, String.class); } public String getProductInfoFallback(String productId, Throwable throwable){ System.out.println("throwable: "+ throwable); return "[This Product is sold out]"; }

설정 변경

hystrix: #hytrix 설정의 command: #command 의 default: #default (모든설정)을 execution: isolation: thread: # thread 로 분리해서 요청을 보내는데 timeoutInMilliseconds: 3000 # 타임아웃 값을 3000(3초)로 지정 circuitBreaker: # 서킷 브레이커의 설정 requestVolumeThreshold: 1 # 서킷 브레이커가 상태를 계산하는 최소 요청 횟수. default : 20 errorThresholdPercentage: 100 # 오류율이 이 이상이 된다면 circuit open. default : 50

예제

먼저 서버 A와 서버 B 가 있어야 합니다.

A 서버에서 받은 데이터를 기준으로 B 서버가 데이터를 정렬해서 화면에 뿌리는 예제입니다.

다음의 문제가 발생할 수 있습니다.

1. A 서버에서 Exception 발생. 그로인해 B 서버에서 요청처리가 원활하지못함.

2. A 서버에서 요청처리시간이 오래걸림. 그로인해 B서버에서 요청을 처리하지 못하고 대기함.

 

[Ribbon]

Netflix OSS 에서 클라이언트 사이드 로드벨런싱을 가능하게 해주는 소프트웨어

​

데이터를 가져오는 서버에서 다음의 디펜던시와 코드, 설정을 입력해주면 Ribbon 설정이 완료 된다.

​

사용방법 java 1.8 버전 기준 코드

디펜던시 추가

compile('org.springframework.cloud:spring-cloud-starter-netflix-ribbon')

컨트롤러의 RestTemplate 에 @LoadBalanced 추가

@SpringBootApplication @EnableCircuitBreaker public class DisplayApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DisplayApplication.class); } }

RestTemplate 은 다른 서버의 REST API 에 요청을 보내거나 받을 수 있다.

​

다른 서버에서 데이터를 가져와야 할 때 요청하는 주소를 코드에 직접 기입하지 않고 application.yaml 에 이관함으로서 코드의 품질을 높임

application.yml ( .yaml 과 .yml 은 같은동작을 함 )에 다음의 설정을 추가. 추가된 주소들중 하나로 요청을 날린다.

product: ribbon: listOfServers: localhost:8082

코드 내부에서 사용하던 http://localhost:8082/ 주소를 모두 http://product/ 로 변경

// private final String url = "http://localhost:8082/products/"; private final String url = "http://product/products/";

Ribbon 는 서버 실행 시 인터셉터를 하나 추가하여 @LoadBalanced 애노테이션을 붙인 객체에서 사용하는 http://product 의 product 를 위의 application.yaml 에서 설정한 값인 localhost:8082 로 바꿔서 요청을 시도합니다.

​

만약 application.yaml 의 listOfServers 에 기입해놓은 서버에서 요청이 수행되지 않았을 경우 Ribbon Retry 를 이용해 지정된 횟수만큼 재시도 할 수 있습니다.

아래의 디펜던시를 추가합니다.

complie('org.springframework.retry:spring-retry:1.2.2.RELEASE')

그리고 위의 application.yaml 의 설정을 추가합니다.

product: ribbon: listOfServers: localhost:8082, localhost:7777 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1 # 첫번째로 기입한 서버의 요청이 # 네트워크 혹은 서버 자체의 문제로 실패했을 경우 # listOfServers 에 적혀있는 서버 목록을 순차적으로 돌아가며 # 시도하게 되는데 이 때 요청을 바꿔서 실행 할 횟수

MaxAutoRetriesNextServer

첫번째로 기입한 서버의 요청이 네트워크 혹은 서버 자체의 문제로 실패했을 경우 listOfServers 에 적혀있는 서버 목록을 순차적으로 돌아가며 요청을 시도하게 되는데 이 때 요청 URI 을 바꿔서 실행 할 횟수

 

 

[Eureka]

Eureka

Ribbon 에서는 서버 목록을 직접 yml 에 적는 과정이 필요했다.

하지만 서버의 목록을 직접 적게 되면 MSA 에서 IP주소를 관리하기 힘들어지고 동적으로 사용할 수 없기때문에 이를 해결하고싶던 넷플릭스는 Eureka 라는 프로젝트를 만들게된다.

클라우드 네이티브 한 환경을 구성하기위해 사용되며 다른말로 '클라우드의 전화번호부' 이다.

​

Eureka Server

Ribbon 은 Eureka Server 에 저장되어있는 Client 서버 정보를 가지고 통신을 진행한다.

​

Eureka Client

서버 시작 시 Eureka Server (Registry) 에 자동으로 자신의 상태를 등록한다.

eureka.client.register-with-eureka: true (default)

주기적 HeartBeat 으로 Eureka Server 에 자신이 살아있음을 알린다.

eureka.instance.lease-renewal-interval-in-seconds: 30(default)

서버 종료 시 Eureka Server 에 자신의 상태를 변경(DOWN) 혹은 자신의 목록 삭제

​

Eureka 상에 등록된 이름은 'spring.application.name'


Eureka Server 만들기

​

Eureka Server

디펜던시 추가

서버로 사용될 Spring 프로젝트에 다음의 디펜던시 추가

compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-server')

어노테이션 추가

메인 메소드가 있는 클래스에 다음 어노테이션 추가

@EnableEurekaServer

두가지만 해주면 Eureka 의 셋팅이 끝납니다(놀라움..)

​

에플리케이션을 실행시키고 http://localhost:8761로 접속하면 유레카 대시보드가 보이게됩니다.


Eureka Client

Eureka Server 에 주기적으로 신호를 보내며 자신의 IP 를 등록하고자 하는 애플리케이션에 다음의 셋팅을 진행하여 Eureka Client 로 등록합니다.

디펜던시 셋팅

compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')

어노테이션 추가

메인 메소드가 있는 클래스에 다음의 어노테이션 추가

@EnableEurekaClient

설정 추가

application.yml 에 다음의 설정 추가

OS에서 제공하는 hostname 대신 자신의 ip address 를 사용하여 Eureka Server 에 등록

eureka: instance: prefer-ip-address: true

리본 설정 변경

리본의 application.yml 에서 listOfServers 로 명시해놓은 서버의 목록을 제거한다.

제거했을 경우 Ribbon 은 Eureka 를 통해서 서버의 리스트를 가져온다.

product: ribbon: # listOfServers: localhost:8082, localhost:7777 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1

Eureka Client 에서 Eureka Server 주소 명시 설정 제거

만약, 서버의 주소를 명시하고싶다면 application.yml 에 다음의 설정을 추가한다.

eureka: client: service-url: defaultZone: http://127.0.0.1:8761/eureka # default address


+

Eureka 서버 에러

위 글을 따라서 Eureka 서버를 셋팅하다보면 다음과 같은 문제가 발생할 수 있습니다.

java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not present org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat

다음의 종속성을 입력해주면 해결할 수 있습니다.

compile('javax.xml.bind:jaxb-api:2.3.0') compile('javax.activation:activation:1.1') compile('org.glassfish.jaxb:jaxb-runtime:2.3.0')


+

같은 서버 포트 다르게 열기 (intelliJ)

포트를 다르게 할 서버를 선택 후 -> 왼쪽 위의 Copy Configureation 선택

이름을 바꾸고 -> Environment 클릭 -> VM options 에 설정 입력 ->

-Dserver.port=8083

Apply 후 OK 를 누르면 창이 닫히며 아래처럼 목록에 자신이 추가한 설정의 애플리케이션이 떠있는것을 볼 수 있습니다.

선택 후 오른쪽의 Run 버튼으로 실행

Eureka Server 에서 결과 확인

정상적으로 localhost:product:8083 이 올라온것을 확인할 수 있습니다.

 

[Feign]

 

관심사의 분리를 위해 사용한다.

서비스의 관심사는 다른 리소스, 외부 서비스 호출과 리턴값이며 관심사가 아닌것은 어떤 URL 을 사용하고 어떻게 파싱할것인가 이다. 테스트가 어렵다는 단점도 있음

Spring Cloud 에서 Open-Feign 기반으로 Wrapping 한것이 Spring Cloud Feign


사용법

디펜던시 추가

compile('org.springframework.cloud:spring-cloud-starter-openfeign')

메인 메소드가 있는 클래스에 어노테이션 추가

@EnableFeignClients

인터페이스 선언

name 는 Ribbon 에서 지정해놓은 이름으로 쓰면 된다.

@FeignClient(name="dp", url="http://localhost:8080/") public interfaceProductResource{ @RequestMapping(value="/query/{itemId}", method=RequestMethod.GET) String getItemDetail(@PathVariable(value="itemId")String itemId); }

사용

@Autowired ProductResource productResource;


Feign Client

Feign Client 는 내부적으로 Ribbon 을 사용하며 Ribbon + Eureka + Hystrix 와 통합하여 사용할 수 있다.

만약 위 코드처럼 셋팅을 했다면 위에서 생성한 인터페이스에서 @FeignClient(name="dp", url="http://localhost:8080/") 이부분에서 URL 을 삭제하면 Ribbon 에 셋팅되어있는 주소를 따라가서 데이터를 가져오며, Eureka 와 함께 사용중일경우 Feign -> Ribbon -> Eureka 의 순서대로 주소데이터를 가져와서 사용하게 되는 식이다.

하지만 URL 을 쓰면 Ribbon, Eureka, Hystrix 을 사용하지 않음을 뜻한다.

​

+

Feign + Hystrix ( 추천하지않는 셋팅 : 에러의 위치를 알 수 없음. 하지만 방법은 명시해둠.)

application.yml 에 다음의 설정을 추가

feign: hystrix: enabled: true

위의 설정을 추가하면 Feign 의 메소드 하나 하나가 Hystrix Command 로서 호출됨

​

Fallback 작성

먼저 Fallback 을 처리하기 위한 클래스 작성

@Component public class ProductRemoteFallback implements FeignProductRemoteService { @Override public String getProductInfo(String productId) { return "default value"; } }

Fallback 처리를 위한 인터페이스의 어노테이션에 Fallback 클래스를 명시

@FeignClient(name = "product", fallback = ProductRemoteFallback.class)


+

FallbackFactory 를 사용한 Hystrix 사용

application.yml 에 다음의 설정을 추가

feign: hystrix: enabled: true

위의 설정을 추가하면 Feign 의 메소드 하나 하나가 Hystrix Command 로서 호출됨

FallbackFactory 작성

Fallback 을 처리하기 위한 FallbackFactory 를 생성

@Component public class ProductRemoteFallbackFactory implements FallbackFactory<FeignProductRemoteService> { @Override public FeignProductRemoteService create(Throwable cause) { System.out.println("t = "+cause); return productId -> "[ this product is sold out ]"; } }

FeignProductRemoteService 의 @FeignClient 어노테이션의 fallback 을 fallbackFactory 로 변경하고 새로 만든 FallbackFactory 를 입력

@FeignClient(name = "product", fallbackFactory = ProductRemoteFallbackFactory.class) public interface FeignProductRemoteService { @GetMapping("/products/{productId}") String getProductInfo(@PathVariable("productId") String productId); }

설정 완료

​

테스트를 위해 데이터를 가져오는 Controller 에 sleep 을 2000으로 걸고 위의 fallbackFactory 가 명시된 프로젝트의 설정에서 아래와 같이 timeout 에 1000을 걸고 테스트

hystrix: command: FeignProductRemoteService#getProductInfo(String): execution: isolation: thread: timeoutInMilliseconds: 1000 # default 1000ms circuitBreaker: requestVolumeThreadhold: 1 errorThresholdPercentage: 50

FeignProductRemoteService#getProductInfo(String): 이부분 오타나면 안됩니다!

 

API Gateway

클라이언트와 백엔드 서버 사이의 출입문

라우팅 ( 라우팅, 필터링, API 변환, 클라이언트 어댑터 API, 서비스 프록시)

횡단 관심사

* 보안, 인증(authentication), 인가(authorization)

* 일정량 이상의 요청 제한(rate limiting)

* 계측(metering)

​

Netflix API Gateway 인 Zuul 은 Hystrix, Ribbon, Eureka 가 포함되어있다.

​

1. Zuul 의 모든 API 요청은 HystrixCommand 로 구성되어 전달된다.

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

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

- CircuitBreaker / ThreadPool 의 다양한 속성을 통해 서비스 별 속성에 맞는설정가능

2. API를 전달할 서버의 목록을 갖고 Ribbon 을 통해 LoadBalancing 을 수행한다.

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

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

3. Eureka Client 를 사용하여 주어진 URL 의 호출을 전달할 '서버 리스트'를 찾는다.

- Zuul 에는 Eureka Client 가 내장

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

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

4. Eureka + Ribbon 에 의해서 결정된 Server 주소로 HTTP 요청

- Apache Http Client 가 기본 사용

- OKHttp Client 사용 가능

5. 선택된 첫번째 서버로의 호출이 실패할 경우 Ribbon에 의해서 자동으로 Retry 수행

- Retry 수행 조건

* Http Client 에서 Exception 발생 (IOException)

* 설정된 HTTP 응답 코드 반환 (ex 503)


사용법

디펜던시 추가

compile('org.springframework.cloud:spring-cloud-starter-netflix-zuul') compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client') compile('org.springframework.retry:spring-retry:1.2.2.RELEASE')

Main Class 어노테이션 추가

@EnableZuulProxy @EnableDiscoveryClient // EurekaClient 대신 사용

application.yml 설정

spring: application: name: zuul server: port: 8765 zuul: routes: product: path: /products/** serviceId: product stripPrefix: false display: path: /displays/** serviceId: display stripPrefix: false ribbon-isolation-strategy: thread thread-pool: use-separate-thread-pools: true thread-pool-key-prefix: zuul- eureka: instance: non-secure-port: ${server.port} prefer-ip-address: true client: serviceUrl: defaultZone: http://localhost:8761/eureka/

스레드풀 설정 (application.yml)

spring-cloud-zuul 의 기본 Isolation 은 SEMAPHORE 입니다. (Netflix Zuul 은 threadpool)

# 스레드풀 설정하는 방법 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 1000 product: execution: isolation: thread: timeoutInMilliseconds: 10000 threadpool: zuul-product: coreSize: 30 maximumSize: 100 allowMaximumSizeToDivergeFromCoreSize: true zuul-display: coreSize: 30 maximumSize: 100 allowMaximumSizeToDivergeFromCoreSize: true

리본 타임아웃 지정 설정(application.yml)

# 리본에 타임아웃 지정 product: ribbon: MaxAutoRetriesNextServer: 1 ReadTimeout: 3000 ConnectTimeout: 1000 MaxTotalConnections: 300 MaxConnectionsPerHost: 100 display: ribbon: MaxAutoRetriesNextServer: 1 ReadTimeout: 3000 ConnectTimeout: 1000 MaxTotalConnections: 300 MaxConnectionsPerHost: 100

결과

zuul 서버에서 product 요청

zuul 서버에서 display 요청

[출처] Spring Cloud(Netflix OSS) - Zuul|작성자 푸르잼

'IT/API Gateway' 카테고리의 다른 글
  • coredns
  • An Example of Load Balancing with Zuul and Eureka
티티알
티티알
IT/DT 기술, 주식투자에 대한 관심을 기록하는 티티알의 공간 입니다
  • 티티알
    티티알로그
    티티알
  • 전체
    오늘
    어제
    • 분류 전체보기 (187)
      • IT (125)
        • UNIX (22)
        • NETWORK (4)
        • EAI (0)
        • SOA (1)
        • ORACLE (3)
        • Ubuntu (18)
        • WMQ_WMB (8)
        • Java (44)
        • Windows (2)
        • ESB (1)
        • VirtualBox (2)
        • Apache (1)
        • Tomcat (0)
        • Eclipse (0)
        • WebtoB (0)
        • Tmax (0)
        • Jeus (0)
        • Spring (0)
        • Thinkpad (0)
        • MQTT (0)
        • Odroid (1)
        • Drupal (0)
        • Hackintosh (0)
        • Cloud (6)
        • ELK(R) (0)
        • ScouterX (0)
        • API Gateway (3)
        • MSA (0)
        • Envoy + Istio (2)
        • Nginx (5)
        • Python (1)
        • Kafka (0)
        • Elasticsearch (0)
      • Fly Fishing (21)
        • Log (3)
        • Tying (10)
        • My Photo (0)
        • Video (1)
        • Casting (5)
        • News (1)
        • Tuning (0)
      • Fishing (0)
        • Fishing log (0)
        • etc... (0)
      • Android (3)
        • Build (1)
        • Programming TIP (0)
        • Custom ROM (0)
        • Start (2)
        • SGN2 (0)
        • Knowhow (0)
      • 주식 (34)
        • 종목 (0)
        • 기법 (1)
        • 테마 (2)
        • 경제지식 (1)
        • 찌라시 (0)
        • 섹터분석 (0)
        • 종목분석 (0)
        • 그루터기 (0)
        • 관심종목 (0)
        • 시황 (4)
        • 자동매매프로그램만들기 (0)
        • 챠트분석 (26)
      • Blockchain (2)
        • Minning (2)
      • GoldenGlove (0)
        • Movie (0)
        • World Class (0)
      • etc (1)
      • 여행 (0)
        • 이탈리아 (0)
      • Coffee (0)
        • 원두 (0)
      • GitHub (0)
        • Page (0)
      • Game (0)
        • SevenKnights (0)
      • AquaStory (0)
        • Guppy (0)
        • 물 공부 (0)
  • 블로그 메뉴

    • 홈
    • IT
    • Android
    • Fly Fishing
    • 빨간저금통(주식)
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

    • 섬소년 성훈의 홈페이지 - 흐르는 강물처럼
    • 24년 경력 짝퉁바늘님의 명품훅 쇼핑몰
    • sunyzero님의 IT관련 블로그
    • 네이버(NHN) 개발자 블로그
    • 카르텔
  • 공지사항

  • 인기 글

  • 태그

    323230
    Anaconda
    apigateway
    CDBC
    DMS
    DMZ
    fishband #cramber #CR-HM06 #알리바란 #가성비베이트릴 #BFS #가벼운루어
    gateway
    guppy
    HSD엔진
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
티티알
Spring cloud Netflix
상단으로

티스토리툴바