Сервисный шлюз Spring Cloud Zuul

Spring Cloud

Spring Cloud Zuul

среда разработки

  • idea 2019.1.2
  • jdk1.8.0_201
  • Spring Boot 2.1.9.RELEASE
  • Spring Cloud Greenwich SR3

Представляем Зуул

Zuul — это служба шлюза, разработанная Netflix, которая обеспечивает динамическую маршрутизацию, мониторинг, эластичность и безопасность.Его можно использовать с Eureka, Ribbon, Hystrix и другими компонентами. Вы также можете обеспечить поддержку фильтрации проверки, создав фильтры, чтобы приложения микрослужб могли больше сосредоточиться на разработке бизнес-логики.

Преимущество использования службы шлюза Zuul заключается в предоставлении REST API внешней системе унифицированным образом, а также в дополнительных функциях, таких как контроль разрешений и балансировка нагрузки, и эти функции извлекаются из исходной службы и существуют независимо.

Zuul предоставляет различные типы фильтров для обработки запросов, эти фильтры позволяют нам выполнять следующие функции.

  • Контроль доступа и безопасность: может идентифицировать информацию, необходимую для аутентификации, и отклонять запросы, которые не соответствуют условиям.
  • Монитор: мониторинг информации о запросе
  • Динамическая маршрутизация: динамическая маршрутизация запросов к различным сервисным кластерам в фоновом режиме по мере необходимости.
  • Стресс-тест: постепенно увеличивайте трафик к кластеру для оценки производительности.
  • Балансировка нагрузки: выделяйте ресурсы для каждого типа запросов и отбрасывайте запросы, превышающие квоту.
  • Ограничение
  • Фильтрация черного и белого списков
  • Обработка статических ресурсов: обработка ответов статических ресурсов непосредственно в zuul без пересылки этих запросов во внутренний кластер.

фильтр

ZuulFilter — это базовый абстрактный класс, который определяет некоторые абстрактные методы.

  • Метод filterType: тип фильтра, есть "pre", "route", "post", "error", "static"

    • pre: выполняется до маршрутизации запроса
    • маршрут: выполняется, когда запрос маршрутизируется
    • post: выполняется после маршрутизации запроса
    • error: Выполняется при возникновении ошибки в запросе
    • static: можно увидеть специальный фильтр StaticResponseFilter, который позволяет генерировать ответы от самого Zuul вместо пересылки запросов к источнику
  • Метод filterOrder: приоритет, чем выше уровень, тем быстрее он будет выполняться (чем меньше значение, тем выше уровень)

  • Метод shouldFilter: переключатель, если это правда, метод запуска будет выполнен, иначе он не будет выполнен

  • метод запуска: логическая операция, выполняемая фильтром

Код

1. Создайте сервисный реестр

Создайте проект zuul-eureka-server и введите зависимость eureka-server Полный исходный код проекта можно просмотреть:Образец исходного кода Spring Cloud Zuul

Вот некоторые ключевые фрагменты кода

pom добавить зависимости

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

Добавьте аннотацию @EnableEurekaServer в класс запуска.

@EnableEurekaServer
@SpringBootApplication
public class ZuulEurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulEurekaServerApplication.class, args);
    }
}

YML-конфигурация

server:
  port: 8761

spring:
  application:
    name: zuul-eureka-server

eureka:
  instance:
    hostname: localhost   # eureka 实例名称
  client:
    register-with-eureka: false # 不向注册中心注册自己
    fetch-registry: false       # 是否检索服务
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/  # 注册中心访问地址

2. Создайте поставщика услуг 1

Создайте проект zuul-server-provider и введите зависимость eureka-client Полный исходный код проекта можно просмотреть:Образец исходного кода Spring Cloud Zuul

Вот некоторые ключевые фрагменты кода

pom добавить зависимости

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

Напишите службу HelloController

@RestController
@Slf4j
public class HelloController {

    @RequestMapping("/hello")
    public String index(@RequestParam String name) {
        log.info("request one  name is " + name);
        return "hello " + name + ",this is first messge";
    }
}

Добавьте аннотацию @EnableDiscoveryClient в класс запуска.

@SpringBootApplication
@EnableDiscoveryClient
public class ZuulServerProviderApplication {

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

YML-конфигурация

spring:
  application:
    name: zuul-server-provider
server:
  port: 9000
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

3. Создайте поставщика услуг 2

Создайте проект zuul-server-provider2, введите зависимость eureka-client и другие проекты с тем же поставщиком услуг 1. Полный исходный код проекта можно просмотреть:Образец исходного кода Spring Cloud Zuul

Код разницы размещен ниже

Напишите службу, здесь, чтобы выполнить тест на деградацию службы, установите сверхдлительное время ожидания для текущего потока.

@RestController
@Slf4j
public class HelloController {
    @RequestMapping("/hello")
    public String index(@RequestParam String name) {
        log.info("request two name is " + name);
        try{
            //为做服务降级测试,设置一个超长休眠时间,故意导致该服务访问超时
            Thread.sleep(1000000);  
        }catch ( Exception e){
            log.error(" hello two error",e);
        }
        return "hello " + name + ",this is two messge";
    }
}

4. Создайте сервисный шлюз zuul

Создайте проект zuul-server-gateway, введите зависимости netflix-zuul и eureka-client, полный исходный код проекта можно просмотреть:Образец исходного кода Spring Cloud Zuul

Вот некоторые ключевые фрагменты кода

конфигурация pom.xml

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

Создать фильтр TokenFilter.java

package com.easy.zuulServerGateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;

@Slf4j
public class TokenFilter extends ZuulFilter {

    @Override
    public String filterType() {
        //可以在请求被路由之前调用
        return "pre";
    }

    @Override
    public int filterOrder() {
        //filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        //是否执行该过滤器,此处为true,说明需要过滤
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        log.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());

        //获取请求的参数
        String token = request.getParameter("token");

        if (StringUtils.isNotBlank(token)) {
            //对请求进行路由
            ctx.setSendZuulResponse(true);
            ctx.setResponseStatusCode(200);
            ctx.set("isSuccess", true);
            return null;
        } else {
            //不对其进行路由
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(400);
            ctx.setResponseBody("token is empty");
            ctx.set("isSuccess", false);
            return null;
        }
    }
}

Создайте прерыватель цепи, соответствующий сервису zuul-server-provider (здесь может быть перегоревшим весь сервис или один сервисный интерфейс), ProviderFallback.java

package com.easy.zuulServerGateway.fallback;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

@Slf4j
@Component
public class ProviderFallback implements FallbackProvider {

    @Override
    public String getRoute() {
        return "zuul-server-provider";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        if (cause != null) {
            String reason =cause.getMessage();
            log.info("Excption {}", reason);
        }
        return fallbackResponse();
    }

    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() {
                return 200;
            }

            @Override
            public String getStatusText(){
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() {
                return new ByteArrayInputStream("The service is unavailable.".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

YML-конфигурация

spring:
  application:
    name: zuul-service-gateway
server:
  port: 8888

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

  #是否开启重试功能
zuul:
  retryable: true
  #对当前服务的重试次数
ribbon:
  MaxAutoRetries: 2
  #切换相同Server的次数
  MaxAutoRetriesNextServer: 0

Добавьте аннотацию @EnableZuulProxy в класс запуска, чтобы запустить шлюз службы. ZuulServerGatewayApplication.java

package com.easy.zuulServerGateway;

import com.easy.zuulServerGateway.filter.TokenFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy
public class ZuulServerGatewayApplication {

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

    @Bean
    public TokenFilter tokenFilter() {
        return new TokenFilter();
    }
}

Выше созданы четыре службы из примера, затем запустите пример, чтобы увидеть эффект.

использовать

Четыре существующих проекта:

zuul-eureka-server: реестр служб, имя службы: zuul-eureka-server, порт: 8761 zuul-server-provider: поставщик услуг 1, имя службы: zuul-server-provider, порт: 9000 zuul-server-provider2: поставщик услуг, имя службы: zuul-server-provider, порт: 9001 zuul-server-gateway: сервисный шлюз, имя сервиса: zuul-server-gateway, порт: 8888

запустить тест

Запустите три службы zuul-eureka-server, zuul-server-gateway и zuul-server-provider соответственно.

Запустите zuul-server-provider2

  • Посетите http://localhost:8888/zuul-server-provider/hello?name=yuntian&token=xx несколько раз, и в это время он будет возвращаться поочередно.
hello yuntian,this is first messge
The service is unavailable
...

Из возвращенных результатов видно, что проект zuul-server-provider2 включил прерыватель цепи и возвращает: Служба недоступна.

материал