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.
Action # 1.2
- The direction of the agent
- authentication
- Flow control
- fusing
- Log monitoring
- …
1.3 Gateway location in microservices Architecture #
2. GateWay non-blocking asynchronous model #
2.1 为什么选择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 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. GateWay module construction #
Create a new module: cloud-gateway
The pom.xml file is as follows
<? The XML version = "1.0" encoding = "utf-8"? > < 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 > < the parent > < groupId > com. Codeliu < / groupId > < artifactId > springcloud - test < / artifactId > <version> 1.0-snapshot </version> </parent> <artifactId> Cloud-gateway </artifactId> <dependencies> <! <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: routes: -id: Provider-payment-route1 # specifies the route id. Uri: http://localhost:8001 # Specifies the route id. Eureka: client: register-with-eureka: true fetch-registry: true service-url: -path =/payment/** # defaultZone: http://localhost:9001/eurekaCopy 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.
GateWay configures routes in two ways
(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); . The route (" direct - the route ", r - > r.r emoteAddr (" 10.1.1.1 ", Uri ("https://downstream1").route("proxied-route", r -> r.emoteaddr (resolver, "10.10.1.1", "10.10.1.1/24"). The 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. @configuration public class GatewayConfig {@bean public RouteLocator customerRouteLocator(RouteLocatorBuilder routeLocatorBuilder) { RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); / / the first parameter is the only id = > HTTP: / / http://news.baidu.com/guonei / / http://localhost:9527/guonei routing routes, the route (" path_route_baidu." r -> r.path("/guonei") .uri("http://news.baidu.com/guonei")).build(); return routes.build(); }}Copy the code
The browser type http://localhost:9527/guonei, return to the same page at http://news.baidu.com/guonei.
GateWay configure dynamic routing #
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: Discovery: locator: enabled: Route: -id: provider-payment-route1 route id: provider-payment-route1 route id: provider-payment-route1 http://localhost:8001 # Uri: lb://provider-payment # Note that the uri protocol is LB, indicating 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/** # Predicates: -path =/payment/** # true service-url: defaultZone: http://localhost:9001/eurekaCopy 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.
GateWay builds 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: Discovery: locator: enabled: Route: -id: provider-payment-route1 route id: provider-payment-route1 route id: provider-payment-route1 http://localhost:8001 # Uri: lb://provider-payment # Note that the uri protocol is LB, indicating 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/** # 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: # match the same path from top to bottom. -path =/example/** # -after =2021-07-08T10:25:20.760+08:00[Asia/Shanghai] -id: between-route uri: https://example.org predicates: - Path = / example / * * - Between T10: = 2021-07-08. At 760 + 08:00 Asia/Shanghai. 2021-07-09T10:25:20.760+08:00[Asia/Shanghai] - ID: cooky-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/eurekaCopy the code
You can use ZonedDateTime to generate times in this format
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. And didn't bring cookies curl http://localhost:9527/example # with cookies curl http://localhost:9527/example -- cookies = "chocolate chip" # The CURL command with the specified Request header parameters 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.
GateWay file #
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 is a GlobalFilter that implements the GlobalFilter and Ordered interfaces. @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(); } // continue next filter return chain.filter(exchange); } @Override public int getOrder() { 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.