[Spring Cloud Series] Spring Cloud-Gateway Zuul Detailed Explanation and Practice

Spring Cloud - Zuul gateway detailed explanation and practice

I. Overview

Spring Cloud Zuul is one of the core components of the Spring Cloud Netflix sub-project. It is an open source API Gateway server of Netflix. It essentially has a Web Servlet application that can be used as an API gateway in a microservice architecture and supports dynamic routing and filtering functions; The gateway provides a unified access entrance for microservices; the definition of gateway is similar to the facade pattern in design patterns, which is equivalent to the facade in microservices. Clients access microservices through it for routing and filtering. It provides request routing, load balancing, verification filtering, service fault tolerance, service aggregation and other functions.

2. Zuul functions and functions

Zuul can achieve the following functions by loading a dynamic filtering mechanism:

  • Authentication and security: Identify authentication requirements for various types of resources and reject requests that do not meet the requirements.
  • Review and Monitoring: Track meaningful data and statistical results at the edge to bring us accurate conclusions about production status.
  • Routing and forwarding: Dynamically route requests to different backend clusters as needed.
  • Stress test: Gradually increase load traffic directed to the cluster to calculate performance levels.
  • Load balancing: Allocate corresponding capacity to each load type and discard requests that exceed the limit.
  • Static response handling: Establish partial responses directly at the edge to avoid them flowing into the internal cluster.
  • Multi-region resiliency: Routing requests across AWS regions to diversify ELB usage and keep edge locations as close to users as possible.

In addition to the above functions, Netflix also uses Zuul's functions to achieve precise routing and stress testing through the canary version.

In Spring Cloud, you can quickly build a gateway by adding Zuul's dependencies and configuration files to facilitate unified management and maintenance of each microservice and achieve better service governance.

3. Working principle of Zuul gateway

3.1 Main components of the gateway:

Zuul gateway mainly consists of the following components:

  • Filter: Filter can add some processing logic before or after the request is routed.
  • Route: Routing, routing requests to different backend services.
  • Ribbon: Load balancer, Zuul uses Ribbon for load balancing by default.
  • Hystrix: A fault-tolerant processor that can implement current limiting and circuit breaker mechanisms.

Zuul's filter chain is the core part of the entire gateway. It is composed of multiple filters. Each filter is responsible for different processing logic, such as request authentication and forwarding. During the process of processing the request, the filter chain will execute these filters in sequence to realize the full life cycle management of the request. The specific process is shown in the figure below.

In the figure, we can see that the Filter Chain mainly consists of three parts: filters, generating routes and sending them to back-end services, and processing route responses. Below we will introduce the processing logic of each part in detail.

3.2 Zuul filter

Filter is one of the most important components in Zuul. It can intercept and modify the content of requests and responses to implement various functions. In Spring Cloud, all filters must inherit the abstract class ZuulFilterand implement four methods:

  • filterType() method: returns the filter type, including four types: pre, post, route and error.

  • filterOrder() method: Returns the order in which the filter is executed. The smaller the value, the earlier it is executed.

  • shouldFilter() method: determines whether the filter needs to be executed, and returns true by default, indicating that all filters need to be executed.

  • run() method: the main business logic of the filter, implementing specific filtering logic

Filter type

The execution logic core of different types of filters in Zuul is defined in the com.netflix.zuul.http.ZuulServlet class. The relevant code of this class is as follows:

@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
    
    
    try {
    
    
        init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
        // Marks this request as having passed through the "Zuul engine", as opposed to servlets
        // explicitly bound in web.xml, for which requests will not have the same data attached
        RequestContext context = RequestContext.getCurrentContext();
        context.setZuulEngineRan();
        try {
    
    
            preRoute();
        } catch (ZuulException e) {
    
    
            error(e);
            postRoute();
            return;
        }
        try {
    
    
            route();
        } catch (ZuulException e) {
    
    
            error(e);
            postRoute();
            return;
        }
        try {
    
    
            postRoute();
        } catch (ZuulException e) {
    
    
            error(e);
            return;
        }
    } catch (Throwable e) {
    
    
        error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
    } finally {
    
    
        RequestContext.getCurrentContext().unset();
    }
}

Insert image description here

There are some problems with this classic official flow chart. It is biased to enter the error Filter after the post Filter throws an error, and then enter the post Filter again. In fact, there are two situations when post Filter throws errors:

  1. Before the post Filter throws an error, the pre and route Filter do not throw an error. At this time, the logic of ZuulException will be entered, the stack information will be printed, and then the ERROR information with status = 500 will be returned.
  2. Before the post Filter throws an error, the pre and route Filters have already thrown errors. At this time, the stack information will not be printed and the ERROR information with status = 500 will be returned directly.

This provides a more intuitive description of Zuul's request life cycle regarding Filter. There are four types of Filters with different life cycles in Zuul, which are:

  1. pre : Executed before Zuul routes to lower-level services according to rules. If you need to preprocess requests, such as authentication, current limiting, etc., you should consider implementing this type of Filter.
  2. route : This type of Filter is the executor of Zuul routing actions. It is where Apache Http Client or Netflix Ribbon builds and sends original HTTP requests. Okhttp is currently supported.
  3. post : This type of Filter is executed after the source service returns results or exception information occurs. If you need to do some processing on the return information, it is processed in this type of Filter.
  4. error : If an exception occurs during the entire life cycle, it will enter the error Filter and can handle global exceptions.

In actual projects, it is necessary to implement the above types of Filters to process request links. According to business needs, select the Filter of the corresponding life cycle to achieve the purpose. Communication is carried out between Filters through the com.netflix.zuul.context.RequestContext class. ThreadLocal is used internally to save some information about each request, including request routing, error information, HttpServletRequest, and HttpServletResponse, which makes some operations very reliable. , which also extends ConcurrentHashMap in order to save any form of information during processing.

3.3 Generate routes and send them to the backend service

In Zuul, you can implement the routing and forwarding function by configuring ZuulProperties and RouteLocator. Among them, ZuulProperties is mainly used to configure some related properties of the Zuul service, such as cache time, URL prefix and suffix, etc.; while RouteLocator is used to define multiple routing rules to map requests to different back-end services.

When a request enters the Zuul gateway, it will first be processed by a series of filters, and then the request will be forwarded to the corresponding back-end service according to the routing rules, and the response result will finally be returned. When forwarding requests, Zuul can automatically select the corresponding server according to the load balancing policy to implement the load balancing function.

3.4 Processing routing responses

In Zuul, if the backend service responds with an exception or error, Zuul will encapsulate the exception into a ZuulException object and hand it over to other filters for processing. When all filters are executed, Zuul will return the corresponding response result based on the status code and error message in ZuulException.

4. Zuul gateway configuration process

In Spring Cloud, we can quickly create a Zuul gateway service by adding some dependencies and configuration files. Below we will explain in detail how to configure it.

4.1 Add pom.xml dependency

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

4.2 Create configuration class

Create a configuration class to configure related properties of the Zuul gateway service.

@Configuration
@EnableZuulProxy
public class ZuulConfig {
    
    
    // 配置 Zuul 网关服务的相关属性
}

The annotation @EnableZuulProxy means to enable Zuul's proxy function, which can automatically register to the Eureka service center and integrate components such as Ribbon and Hystrix.

4.3 Configure routing rules

Next we need to configure Zuul's routing rules to forward requests to different backend services.

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
    
    
    return builder.routes()
        .route("service-a", r -> r.path("/service-a/**")
            .filters(f -> f.stripPrefix(1))
            .uri("http://localhost:6060"))
        .route("service-b", r -> r.path("/service-b/**")
            .filters(f -> f.stripPrefix(1))
            .uri("http://localhost:6061"))
        .build();
}

In the above code, we define two routing rules to forward requests to http://localhost:8081the http://localhost:8082two addresses respectively. Which stripPrefix(1)means removing the content after the first slash in the URL.

4.4 Configure routing rules

Finally we can add some filters to achieve different functions.

@Bean
public MyFilter myFilter() {
    
    
    return new MyFilter();
}

Among them, MyFilter is our custom filter class, used to implement some specific functions.

4. Summary

This article introduces the relevant knowledge of Zuul gateway in detail from three aspects: its principle, usage scenarios and configuration process. It can be seen that Zuul's filter chain is the core part of the entire gateway. By adding different filters, different functions can be implemented, such as authentication, forwarding, current limiting, etc. At the same time, by properly configuring routing rules, requests can be quickly forwarded to the corresponding back-end services to achieve load balancing and service governance functions.

In actual development, we can flexibly use Zuul gateway services according to different needs to build a highly available and highly concurrency distributed application system.

Guess you like

Origin blog.csdn.net/songjianlong/article/details/133267519