Cloud-spring. IO /spring-clou…

Some module codes involved in the article are not given, but I have uploaded them to Github together, and the whole project can be cloned for debugging.

Address: github.com/stronglxp/s…

1. What is GateWay

1.1 concept

One of the most important components in the Cloud bucket is the gateway, which is the Zuul gateway used in 1.x. In the 2.x version, however, zuul’s upgrade was delayed, and SpringCloud eventually developed a gateway to replace zuul itself.

Gateway is an API Gateway service built on top of the Spring ecosystem, based on Spring 5, Spring Boot 2, and Project Reactor technologies.

Gateway is designed to provide a simple and efficient way to route apis, as well as powerful filter features such as fuses, traffic limiting, retry, and so on.

SpringCloud Gateway is a new Project of SpringCloud, which is developed based on Spring 5.0+Spring Boot 2.0 and Project Reactor technology. It aims to provide a simple and effective unified API route management approach for microservices architectures.

As a Gateway in the SpringCloud ecosystem, SpringCloud Gateway aims to replace Zuul. In SpringCloud 2.0 and above, there is no integration with the latest high-performance version of Zul 2.0 and above. The old version of the Zuul 1.x non-REACTOR schema is still used. In order to improve the performance of the Gateway, SpringCloud Gateway is implemented based on the WebFlux framework, while the bottom layer of the WebFlux framework uses the high performance Reactor model communication framework Netty.

The goal of the Spring Cloud Gateway is to provide unified routing and a Filter chaining approach to provide basic Gateway functions such as: security, monitoring/metrics, and traffic limiting.

1.2 role

  • The direction of the agent
  • authentication
  • Flow control
  • fusing
  • Log monitoring

1.3 Gateway location in microservices Architecture

GateWay non-blocking asynchronous model

2.1 Why Gateway?

Netflix is not very reliable, zuul2.0 has been delayed, delayed release.

  • On the one hand, Zuul1.0 is already in maintenance, and Gateway was developed by the SpringCloud team, which is a son product and reliable. And there are many features Zuul doesn’t use and it’s very easy to use.
  • Gateway is developed on an asynchronous, non-blocking model, and performance is not a concern. While Netflix has already released its latest Zuul 2.x, it appears that Spring Cloud has no plans to integrate. And Netflix related components are announced into the maintenance period; What are the prospects?
  • Gateway is an ideal Gateway choice considering many aspects.

The SpringCloud Gateway has the following features

  • It is constructed based on Spring Framework 5, Project Reactor and Spring Boot 2.0.
  • Dynamic routing: can match any request attribute;
  • You can specify Predicate and Filter for a route;
  • Integrated Circuit breaker function of Hystrix;
  • Integrate Spring Cloud service discovery;
  • Easy to write Predicate and Filter;
  • Request traffic limiting function;
  • Path rewriting is supported.

Differences between SpringCloud Gateway and Zuul

  • Prior to the official release of SpringCloud Finchley, the recommended gateway for SpringCloud was Zuul provided by Netflix.
  • Zuul 1.x is an API Gateway based on blocking I/O.
  • Zuul 1.x is based on Servlet 2.5 and uses a blocking architecture that does not support any long connections (such as WebSocket). Zuul’s design pattern is similar to that of Nginx. Each I/ WISE operation is performed by a worker thread and the request thread is blocked until the worker thread finishes. Zuul is implemented in Java, and the JVM itself suffers from slow load times, resulting in relatively poor Zuul performance.
  • Zuul 2.x is more advanced and wants to be Netty non-blocking and support long connections, but SpringCloud is not yet integrated. The performance of Zuul. X is significantly improved over that of Zuul 1.x. In terms of performance,Spring Cloud Gateway’s RPS(requests per second) is 1.6 times higher than Zuul’s, according to official benchmarks.
  • The Spring Cloud Gateway builds on Spring Framework 5, Project Reactor, and Spring Boot2 and uses a non-blocking API.
  • The Spring Cloud Gateway also supports WebSocket and is tightly integrated with Spring for a better development experience

2.2 Zuul1. X model

Zuul, which is integrated in Springcloud, uses the Tomcat container, using the traditional Serviet IO processing model.

The Servlet life cycle? Servlets are managed by Servlet Containers for their life cycles.

  • When container starts, it constructs a servlet object and calls servlet init() to initialize it.
  • The Container runtime accepts requests, allocates a thread to each request (typically from a thread pool) and then calls service.
  • The servlet destory() is called to destroy the servlet when the container is closed.

Disadvantages of the above model:

A Servlet is a simple network IO model that binds a thread to a request when it enters a Servlet Container. This model is useful in low-concurrency scenarios. However, once the high concurrency (such as Jmeter pressure), the number of threads will increase, and the cost of thread resources is expensive (on-line switching, large memory consumption) seriously affect the request processing time. The servlet model has no advantage in simple business scenarios where you don’t want to assign one thread to each request and only need one or more threads to handle extremely concurrent requests.

So Zuul 1.x is a blocking processing model based on servlets, meaning Spring implements a servlet (DispatcherServlet) that handles all request requests and is handled by that servlet blocking processing. So SpringCloud Zuul cannot get rid of the shortcomings of the servlet model.

2.3 the GateWay model

What is WebFlux? The official documentation

Traditional Web frameworks such as Struts2, SpringMVC, etc. are based on Servlet APl and Servlet container.

But asynchronous non-blocking support came with Servlet3.1. WebFlux is a typical non-blocking asynchronous framework, and its core is implemented based on Reactor API. Compared to traditional Web frameworks, it can run on containers such as Netty, Undertow, and Servlet3.1. Non-blocking + functional programming (Spring 5 must let you use Java 8).

Spring WebFlux is a new responsive framework introduced in Spring 5.0. Unlike Spring MVC, it does not rely on Servlet APl, is completely asynchronous and non-blocking, and is based on Reactor to implement the responsive flow specification.

Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. It does not work in a traditional Servlet Container or when built as a WAR.

3. GateWay workflow

3.1 Three core concepts

  • Route – A Route is the basic building block of a gateway. It consists of an ID, a target URI, a set of assertions, and filters that match the Route if the assertion is true.
  • Predicate (claim) – reference is Java8 Java. Util. The function. The Predicate, the developer can match all the content in the HTTP request (for example, request or request parameters), matching with the assertion if the request is routed;
  • Filter – Refers to an instance of GatewayFilter in the Spring framework, which allows you to modify a request before or after it is routed.

Web request, through some matching criteria, to locate the real service node. And before and after the forwarding process, some fine control.

Predicate is our matching condition; Fliter, on the other hand, can be understood as an omnipotent interceptor. With these two elements, plus the target URI, you can implement a concrete route.

3.2 GateWay workflow

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the Proxy Request is sent. All “pre” filter logic is executed. Then the proxy request is made Made, the “Post” filter logic is run.

The client makes a request to the Spring Cloud Gateway. The route matching the request is then found in the Gateway Handler Mapping and sent to the GatewayWeb Handler.

The Handler then sends the request through the specified filter chain to our actual service to perform the business logic, and then returns.

The filters are separated by dashed lines because the filter may perform business logic before (” pre “) or after (” POST “) the proxy request is sent.

Filter The Pre Filter performs parameter verification, permission verification, traffic monitoring, log output, and protocol conversion. The POST Filter performs response content and response header modification, log output, and traffic monitoring.

Core logic: routing and forwarding + execution filter chain.

4. Build the GateWay module

Create a new module: cloud-gateway

The pom.xml file is as follows


      
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.codeliu</groupId>
        <artifactId>springcloud-test</artifactId>
        <version>1.0 the SNAPSHOT</version>
    </parent>

    <artifactId>cloud-gateway</artifactId>

    <dependencies>
        <! Cloud-api-common -->
        <dependency>
            <groupId>com.codeliu</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
Copy the code

The application.yml file is as follows, registered to the Eureka server

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
    
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9001/eureka
Copy the code

The startup class is as follows

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class CloudGatewayApplication {
    public static void main(String[] args) { SpringApplication.run(CloudGatewayApplication.class, args); }}Copy the code

In the Provider module, we have the following interface

You can access this interface by configuring the gateway

spring:
  application:
    name: cloud-gateway
  # Gateway configuration
  cloud:
    gateway:
      routes:
        - id: provider-payment-route1  # route id, no fixed rule but unique, recommend with service name
          uri: http://localhost:8001   # Route address to provide service after match
          predicates:
            - Path=/payment/**         # assert that the path matches the route

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9001/eureka
Copy the code

Start the Eureka server, start the Provider service, and then start the Gateway service. Accessing the interface through the Provider is the same as accessing the interface through the Gateway.

5. GateWay Configures two routes

(1) Configuration through YML files, as in the previous chapter.

(2) The Bean injected into the RouteLocator code

The official sample

RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
    .maxTrustedIndex(1); . .route("direct-route",
    r -> r.remoteAddr("10.1.1.1"."10.10.1.1/24")
        .uri("https://downstream1")
.route("proxied-route",
    r -> r.remoteAddr(resolver, "10.10.1.1"."10.10.1.1/24")
        .uri("https://downstream2"))Copy the code

We can write a visit to Baidu news by ourselves

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

There are two ways to configure routes: 1. Use the configuration file. 2. Use the configuration class * to configure the route */
@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        // The first parameter is the unique id of the route
        // http://localhost:9527/guonei => http://news.baidu.com/guonei
        routes.route("path_route_baidu",
                        r -> r.path("/guonei")
                        .uri("http://news.baidu.com/guonei")).build();
        returnroutes.build(); }}Copy the code

The browser type http://localhost:9527/guonei, return news.baidu.com/guonei the same page.

6. Configure dynamic routes for the GateWay

By default, the Gateway creates dynamic routes based on the service list registered in the registry and the path of the microservice name on the registry for forwarding. This implements the dynamic routing function (without blocking an address).

Example Modify the YML file of the GateWay module

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
# Gateway configuration
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true   # enable the function of dynamically creating routes from registries using microservice names
      routes:
        - id: provider-payment-route1  # route id, no fixed rule but unique, recommend with service name
          # uri: http://localhost:8001 # Route address to provide service after matching
          uri: lb://provider-payment   The uri protocol is lb, which indicates that Gateway load balancing is enabled. Lb ://serviceName is the load balancing URI that spring Cloud Gateway automatically creates for us in microservices.
          predicates:
            - Path=/payment/**         # assert that the path matches the route

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9001/eureka
Copy the code

Start Eureka server, start two provider service, start the GateWay service, repeat visit http://localhost:9527/payment/1, will visit two polling service provider interface.

7. GateWay built Predicate

Document links

The Spring Cloud Gateway uses route matching as part of the Spring WebFlux HandlerMapping infrastructure.

The Spring Cloud Gateway includes a number of built-in Route Predicate factories. All of these predicates match different properties of the HTTP request. Multiple RoutePredicate factories can be combined.

When the Spring Cloud Gateway creates the Route object, the RoutePredicateFactory is used to create the Predicate object, which can be assigned to the Route. The Spring Cloud Gateway contains a number of built-in Route Predicate Factories.

All of these predicates match different attributes of the HTTP request. Multiple predicate factories can be combined through logical and.

Commonly used Route Predicate Factory

(1) The After Route Predicate Factory

(2) The Before Route Predicate Factory

(3) The Between Route Predicate Factory

(4) The Cookie Route Predicate Factory

(5) The Header Route Predicate Factory

(6) The Host Route Predicate Factory

(7) The Method Route Predicate Factory

(8) The Path Route Predicate Factory

(9) The Query Route Predicate Factory

(10) The RemoteAddr Route Predicate Factory

(11) The weight Route Predicate Factory

Try configuring some predicate in YML

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
# Gateway configuration
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true   # enable the function of dynamically creating routes from registries using microservice names
      routes:
        - id: provider-payment-route1  # route id, no fixed rule but unique, recommend with service name
          # uri: http://localhost:8001 # Route address to provide service after matching
          uri: lb://provider-payment   The uri protocol is lb, which indicates that Gateway load balancing is enabled. Lb ://serviceName is the load balancing URI that spring Cloud Gateway automatically creates for us in microservices.
          predicates:
            - Path=/payment/**         # assert that the path matches the route

        # gateway built-in route assertion: https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicate s-factories
        - id: after-route
          uri: https://example.org
          predicates:
            # if the same path is matched from top to bottom, the following rules will not take effect
            - Path=/example/**
            # This time will not take effect
            - After = 2021-07-08 T10: because. 760 + 08:00 Asia/Shanghai

        - id: between-route
          uri: https://example.org
          predicates:
            - Path=/example/**
            - Between T10: = 2021-07-08 and. 760 + 08:00 Asia/Shanghai, The T10:2021-07-09. At 760 + 08:00[Asia/Shanghai]

        - id: cookie-route
          uri: https://example.org
          predicates:
            - Path=/example/**
            - Cookie=chocolate, ch.p

        - id: header-route
          uri: https://example.org
          predicates:
            - Path=/example/**
            - Header=X-Request-Id, \d+

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9001/eureka
Copy the code

You can use ZonedDateTime to generate times in this format

// Timestamp format required to generate gateway built-in route assertion factory 2021-07-05T10:25:20.760+08:00[Asia/Shanghai]
ZonedDateTime zbj = ZonedDateTime.now();
System.out.println(zbj);
Copy the code

We have added four built-in assertions, After, Between, Cookie, and Header. The source URI is example.org and the matching URI is /example/**

Test with the request below

#This command is equivalent to issuing a GET request without a cookie
curl http://localhost:9527/example

#With a cookie
curl http://localhost:9527/example --cookie "chocolate=chip"

#CURL command with parameters specifying the request header
curl http://localhost:9527/example -H "X-Request-Id:123"
Copy the code

Test results: For the same path, matching rules from the top down, matching will not go down.

Summary: Predicate is a set of matching rules that allow the request to find a Route to process.

8. GateWay Filter

Document links

Routing filters can be used to modify incoming HTTP requests and returned HTTP responses. Routing filters can only be used by specified routes. The Spring Cloud Gateway has a variety of routing filters built in, all generated by the Factory class of GatewayFilter.

Spring Cloud Gateway的Filter:

  • Life cycle:
    • pre
    • post
  • Type (see official documents for details) :
    • GatewayFilter – There are 31 types
    • GlobalFilter – There are 10

If we want to customize a global GlobalFilter, we need to implement the GlobalFilter, Ordered interface.

For example, if we implement a Filter, all requests made through the gateway require a specific string

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

/** * here we define a GlobalFilter, implement the GlobalFilter and Ordered interface, all requests need to pass this GlobalFilter validation */
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter.Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("come in MyLogGatewayFilter: " + new Date());
        String name = exchange.getRequest().getQueryParams().getFirst("name");
        if (StringUtils.isBlank(name)) {
            log.info("Illegal user!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        // Proceed to the next filter
        return chain.filter(exchange);
    }

    @Override
    public int getOrder(a) {
        return 0; }}Copy the code

In the filter above we specify that all requests come with the name field and the value cannot be null.

Visit: http://localhost:9527/payment/1, spooled “illegal users!” , visit: http://localhost:9527/payment/1? Name =a, return the result.