Cloud

Zuul

Jungsoomin :) 2020. 12. 7. 17:59

일체형이 아닌 마이크로 서비스 환경에서 많은 API 들이 연계되어 Client의 요청을 처리한다. 발생하는 이슈는 이와 같다.

  • UI에서 여러가지 서비스를 직접 호출
  • Auto scaling 으로 host, port 동적변화
  • API 서비스 들이 각자 인증 CORS 이슈에 엮임
  • API 프로토콜이 일치하지 않을 수 있음
  • API 들이 언제든 합쳐지거나 쪼개질 수 있음.

Zuul Filter, Zuul Routing Service 를 이용하면 해당 이슈들을 해결할 수 있게 된다.

 

MS 와 UI 사이에 존재하는 GATE WAY

Zuul 은 API GateWay 또는 Edge Service 이다.

  • Front End 로 부터 모든 Request 를 받아 내부 Ms 에게 전달하게 되어 똑같은 종단 점을 가지게 한다.
  • CORS , 인증, 보안 등의 공통 설정은 Zuul 에서 처리하면 된다.
  • Request 를 서비스로 라우팅 하거나 필터를 적용하여 Header 에 정보를 추가하는 것도 가능하다.

기능

라우팅 규칙

  • Front End 로 들어온 Request 를 path 에 따라 -> 특정 service 로 Routing 시키는 규칙을 정의한다.
zuul:
routes:
   users:
     path: /myusers/**
     	url: http://example.com/users_service

 

Filter

  • Client의 Request 를 Routing 하기 전, 후, 응답을 받았을 때, 에러가 났을때 필요한 작업을 수행시킴.

 

  • Authentication and Security API 서비스들에 대한 인증을 적용하여 접근을 제한 할 수 있음

  • Insights and Monitoring 접점에서의 의미있는 데이터를 취합하여 분석에 활용할 수 있음

  • Dynamic Routing 비즈니스 로직에 따른 동적인 라우팅 적용이 가능

  • Stress Testing 트래픽 양을 조절하며 성능 테스트 가능

  • Load Shedding 요청 별 처리량을 제한하여 제한을 넘는 요청들은 drop 함

  • Static Response handling 특정 요청에 대하여 미리 정의된 값을 바로 return 할 수 있음

  • Multiregion Resiliency 서로 다른 AWS regions 으로도 요청을 라우팅 할 수 있음


필요의존

  • org.springframework.cloud:spring-cloud-starter-netflix-eureka-client
  • 스프링부트 2.4.0 버전대 부터는 안되는 듯..
  • org.springframework.cloud:spring-cloud-starter-netfix-zuul
  • 의존관리 : org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}
plugins {
    id 'org.springframework.boot' version '2.3.6.RELEASE'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

ext {
    set('springCloudVersion', "Hoxton.SR9")
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

test {
    useJUnitPlatform()
}

 


application.yml 설정

spring:
  application:
    name: zuul

zuul:
  ignored-services: '*' # routes 에 맵핑되지 않는 모든 요청 무시
  sensitive-headers:    # 헤더정보 그냥 통과
  routes:               # 경로에 따른 서비스라우팅 맵핑시 사용
    producer:           # 맵핑 Id
      path: /employee/** # 요청경로 ANT 패턴
      serviceId: EMPLOYEE-PRODUCER # 엮어줄 서비스
      strip-prefix: false # true 일시 path 제거 후 각 서비스 포워딩


# zuul 도 유레카에 등록되어야 함
eureka:
  client:
    service-url:
      defaultZone: ${EUREKA_SERVER_LIST:http://localhost:8761/eureka/}

server:
  port: 8999

@Configuration 클래스에 @EnableZuulProxy 선언 + Eureka 서비스 등록을 위한 @EnableDiscoveryClient 선언.

 

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

 

이후 활성화되어 있는 어느 서비스 포트던 해당 URL 로 요청하면 Zuul에 의해 라우팅 되는 것을 확인 가능함.

 


Filter

  • 모든 필터들은 ZuulFilter 를 상속하여 만들어야한다. 또한 Spring Bean 이여야한다.
  • filterType() = 필터의 타입으로 pre, post, routing, error 로 나뉜다.
  • filterOrder() = 필터 순번을 의미한다.
  • shouldFilter() = 필터 실행여부를 정한다.
  • run() = shouldFilter() 결과 값에 따라 작동시킬 로직을 정의한다.
  • 여기서 RequestContext 는 com.netflix.zuul.context.RequestContext 를 의미한다.
// 필터는 모두 ZuulFilter를 상속받아 구현한다.
@Component
public class SampleFilter extends ZuulFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(SampleFilter.class);

    //pre, post, routing, error 로 필터 시점정의
    @Override
    public String filterType() {
        return "pre";
    }

    //필터 순번
    @Override
    public int filterOrder() {
        return 0;
    }

    //필터 실행여부
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //shouldFilter() 가 true 리턴시 실행할 필터 로직
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx= RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        LOGGER.warn("===========================================================================================");
        LOGGER.warn(String.format("%s Request to %s",request.getMethod(),request.getRequestURI().toString()));
        LOGGER.warn("===========================================================================================");

        return null;
    }
}

//로그
2020-12-07 17:45:01.147  WARN 12176 --- [nio-8999-exec-1] com.example.demo.filter.SampleFilter     : ===========================================================================================
2020-12-07 17:45:01.147  WARN 12176 --- [nio-8999-exec-1] com.example.demo.filter.SampleFilter     : GET Request to /employee
2020-12-07 17:45:01.147  WARN 12176 --- [nio-8999-exec-1] com.example.demo.filter.SampleFilter     : ===========================================================================================

RouteLocator

  • Zuul 설정에 등록된 route 정보를 확인하게 해준다.
  • SimpleRouteLocator 를 반드시 상속받아야 하며 Spring Bean 이여야한다.
  • 기본생성자는 없으니 SpringBoot 의 ServerProperties 와 Zuul 의 ZuulProperties 로 생성하자.
public class SimpleRouteLocator extends org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator {

    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRouteLocator.class);

    public SimpleRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
    }

    @Override
    protected ZuulProperties.ZuulRoute getZuulRoute(String adjustedPath) {
        ZuulProperties.ZuulRoute zuulRoute = super.getZuulRoute(adjustedPath);
        LOGGER.warn("==================================>"+zuulRoute.toString());
        return zuulRoute;
    }
}

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class DemoApplication {

    @Autowired
    private ServerProperties serverProperties;

    @Autowired
    private ZuulProperties zuulProperties;

    @Bean
    public SimpleRouteLocator simpleRouteLocator(){
        return new SimpleRouteLocator(serverProperties.getServlet().getContextPath(),zuulProperties);
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}


//로그
 ==================================>ZuulRoute{id='producer', path='/employee/**', serviceId='EMPLOYEE-PRODUCER', url='null', stripPrefix=false, retryable=null, sensitiveHeaders=[], customSensitiveHeaders=false, }

 

'Cloud' 카테고리의 다른 글

Feign  (0) 2020.12.08
Ribbon  (0) 2020.12.08
Eureka  (0) 2020.12.07
Netflix Component 설명  (0) 2020.12.07
Netflix Components  (0) 2020.12.07