Tiven Wang
Wang Tiven January 19, 2018
425 favorite favorites
bookmark bookmark
share share

Zuul 是来自 NetFlix 的 Microservice 产品家族的 API Gateway 服务或者说是 edge 服务。 Zuul 为开发者构建微服务架构提供了 Routing,Monitoring,Managing resiliency,Security等功能。简单来说,Zuul 可以被看作是一个反向代理,在服务实例间 Zuul 代理内部使用 Eureka server 作为 service discovery,使用Ribbon 作为 load balancing 。

Zuul is the front door for all requests from devices and web sites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency and security.
https://github.com/Netflix/zuul/wiki

Spring Cloud

首先来看一下 Spring Cloud 这个工具包,它为 Cloud 开发提供了很多实用便利的工具集,方便了在 Spring Frameworks 基础上实现 Cloud 功能开发。

Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). Coordination of distributed systems leads to boiler plate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns. They will work well in any distributed environment, including the developer’s own laptop, bare metal data centres, and managed platforms such as Cloud Foundry.

Spring Cloud features:

  • Distributed/versioned configuration
  • Service registration and discovery
  • Routing
  • Service-to-service calls
  • Load balancing
  • Circuit Breakers
  • Global locks
  • Leadership election and cluster state
  • Distributed messaging

Spring Cloud Netflix

Spring Cloud Netflix provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common patterns inside your application and build large distributed systems with battle-tested Netflix components. The patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix), Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon)…

Spring Cloud Netflix features:

  • Service Discovery: Eureka instances can be registered and clients can discover the instances using Spring-managed beans
  • Service Discovery: an embedded Eureka server can be created with declarative Java configuration
  • Circuit Breaker: Hystrix clients can be built with a simple annotation-driven method decorator
  • Circuit Breaker: embedded Hystrix dashboard with declarative Java configuration
  • Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations
  • Client Side Load Balancer: Ribbon
  • External Configuration: a bridge from the Spring Environment to Archaius (enables native configuration of Netflix components using Spring Boot conventions)
  • Router and Filter: automatic regsitration of Zuul filters, and a simple convention over configuration approach to reverse proxy creation

Backend Service

在 Microservices 中首先我们要有一个后端服务,然后才能为其创建 API Gateway 服务。为了测试方便,我们创建一个最简单的 Web 应用程序,假如我们有一个书籍管理服务叫 book service 。

因为只需要最简单的 Restful API 所以只需要 spring-boot-starter-web 依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

和两个简单的 Restful API

@RestController
@SpringBootApplication
public class BookApplication {

  @RequestMapping(value = "/available")
  public String available() {
    return "Microservices in Action";
  }

  @RequestMapping(value = "/checked-out")
  public String checkedOut() {
    return "Spring Microservices in Action";
  }

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

book 服务的端口号设置为

spring:
  application:
    name: book

server:
  port: 8090

Setting up Zuul

Dependencies

Spring Cloud 提供了 POM 方便依赖包的管理,其中就包含 netflix-zuul 依赖包。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

添加 netflix-zuul 依赖

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

Spring Boot Actuator 提供了生产可用性的功能,当你的应用程序部署到生产环境上时,它会帮助你监控和管理应用程序。为了更好地了解我们开发的程序,所以加入 Spring Boot Actuator 依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Zuul API Gateway

Spring Cloud 为你创建了一个 Zuul 代理,以满足常见的在 UI 应用开发中调用多个后端服务的需要。Zuul proxy 为你的后端服务们提供了诸如管理 CORS 和 独立身份认证的能力。

使用 @EnableZuulProxy 打开 Zuul proxy 功能。

@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {

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

@EnableZuulProxy 会为我们建立一个路由器,但我们还要告诉他应该怎么路由进来的请求,转发给哪个服务接口。

通过属性 zuul.routes 为 Zuul proxy 配置路由表,例如配置 books 服务的路由如下

zuul:
  routes:
    books:
      url: http://localhost:8090

这样 Zuul proxy 会转发路径为 /books/* 的请求到此服务接口上,如地址为 http://localhost:8080/books/available 的请求会转发给地址 http://localhost:8090/available

Spring Cloud Netflix Zuul 是使用 Netflix’s Ribbon 执行 client-side load balancing,但 Ribbon 默认使用 Netflix Eureka 做 service discovery 。因为我们这里指定了 service url ,所以需要把 Eureka 自动服务发现功能关掉,如下

ribbon:
  eureka:
    enabled: false

Add a filter

Zuul 除了路由请求功能,还有过滤请求功能。Zuul 有四种标准的过滤器类型: pre, route, post, error 顾名思义。

Image: Zuul Request Lifecycle

继承 com.netflix.zuul.ZuulFilter@Bean 都会被 Spring Cloud Netflix 识别,成为 Zuul 的 Filter 。例如我们创建一个 pre filter

wang.tiven.microservices.apigateway.zuul.filters.pre.SimpleFilter.java

package wang.tiven.microservices.apigateway.zuul.filters.pre;

import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.ZuulFilter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SimpleFilter extends ZuulFilter {

    private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);

    @Override
    public String filterType() {
      return "pre";
    }

    @Override
    public int filterOrder() {
      return 1;
    }

    @Override
    public boolean shouldFilter() {
      return true;
    }

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

      log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));

      return null;
    }
  }

重启并调用接口便会在后台看到 pre filter 的日志输出。

Management Endpoints

如果你在项目中使用 @EnableZuulProxy 并且加入了 Spring Boot Actuator ,那么默认情况下就会有两个 endpoints 用来查看 Zuul 配置情况

  • Routes /routes 查看路由表
  • Filters /filters 查看过滤器们

本篇完整代码可下载自 Github

Asynchronous and Non-Blocking

Zuul 在 2 版本增加非阻塞异步解决方案,也就是会拥抱响应式 Reactive 编程方式。

Zuul [1] was originally a blocking and synchronous solution. The new effort called Zuul 2 is a non-blocking and asynchronous solution. The major architectural difference between Zuul 2 and Zuul 1 is that Zuul 2 is running on an asynchronous and non-blocking framework, using Netty. Instead of relying on multiple threads to provide increased throughput in Zuul, the Netty framework relies on an event loop and callbacks to do the same for Zuul 2.
Netflix Zuul Gets a Makeover to a Asynchronous and Non-Blocking Architecture

Conclusion

本文介绍了使用 Zuul 为 Microservices 创建反向代理服务,并且自定义了过滤器。虽然本本篇没有讲到但 Zuul 还具有服务发现能力,负载平衡能力。同时我们也看到在 Zuul 书写过滤器路由器是多么笨拙,虽然我们可以使用过滤器做任何事情,但它不适合编写调和服务接口的逻辑。所以接下来我们有兴趣介绍一下另外一个出自 Spring 的 API Gateway 产品 Spring Cloud Gateway 。

References

Similar Posts

  • Microservices - Inter-Process Communication The kernal of Microservices Architecture is inter-process communication
  • Microservices - API Gateway : Spring Cloud Gateway Spring Cloud Gateway 是一个新的基于 Spring Framework 5, Project Reactor and Spring Boot 2.0 的 API Gateway 产品
  • Microservices - Transactions
  • Try Cloud Foundry 13 - Logs Loggregator is the next generation system for aggregating and streaming logs and metrics from all of the user apps and system components in an Elastic Runtime deployment. Loggregator uses Google's protocol buffers along with gRPC to deliver logs.
  • Try Cloud Foundry 12 - Config Server Config Server for Pivotal Cloud Foundry (PCF) is an externalized application configuration service, which gives you a central place to manage an application’s external properties across all environments.
  • Microservices - API Gateway Implement an API gateway that is the single entry point for all clients. The API gateway handles requests in one of two ways. Some requests are simply proxied/routed to the appropriate service. It handles other requests by fanning out to multiple services.

Comments

Back to Top