Hello, I’m Xiao Dai.

A man who wants to be a big talk about architecture! If you also want to be the person I want to be, or point a concern to be a companion, let small dish no longer lonely!

This article mainly introduces the SpringCloud service Gateway Gateway

If necessary, you can refer to it

If helpful, do not forget thumb up pervious

WeChat public account has been opened, XiaoDai Liang remember, did not pay attention to the students remember to pay attention!

Some time ago, I chatted with some friends about the current situation of their company. Recently and in the future, the company will fully transition from single service to micro-service structure. Here we hear the key word: micro-services. At first, it sounds reasonable. The Internet is constantly developing. It is not only the development of the industry, but also the development of the system architecture. Now the architecture in the market has gone through these stages:

Is that a good thing? It’s a good thing, no doubt. Because do not keep up with the tide of The Times, will always be shot dead on the beach. But is it all good? B: Not really.

We need to understand what problems do microservices solve? In large part, it should be at the application level and the human level

  • Application level: The architecture of a single service is very simple, and the low cost of project development and maintenance is its undisputed advantage. But the bloated coupling puts too much burden on the infrastructure. If one application processing resource consumes a large amount of CPU, other processing resources will starve to death, increasing system latency and directly affecting system availability.
  • Level:independent,Multilingual ecologyIt’s also a label for a micro-service. In a single service, the more human resources invested in it, the more efficient it is, and the more likely it is to make mistakes. However, micro-services are different, each service is independent, and teams can more easily cooperate in development, or even a set of systems, multiple services, multiple languages, without conflict.

But let us not be blinded by good in any way. The downside of microservices is always there:

  • The issue of fault tolerance between services needs to be considered
  • Data consistency needs to be considered
  • Distributed transactions need to be considered
  • .

Many people believe that micro services are at their core micro. The finer the service is, the better. It’s like writing code without considering a single principle, but using it in service splitting. This is where the core concept needs to be understood: the key to a micro service is not the micro, but the right size

This one sounds simple, but what is the right size? It may vary from team to team, from project to project. The right size may depend on fewer code repositories, fewer deployment queues, fewer languages… There is no one final word here!

Microservices can become a drag on your project if you can’t make them the right size and split them mindlessly. So, sometimes it’s not a good thing to make a complete shift to microservices, do you think?

The topic is getting a little far, let’s try to get it back. Now that microservices have become mainstream, it’s up to us to design them, not just to argue with people about how to refuse to use microservices. In this article, we will talk about the SpringCloud service Gateway

SpringCloud’s service Gateway Gateway

First, know the gateway

What is a Service Gateway? Don’t hit yourself in the head. Let’s rephrase the question, why do we need a service gateway?

A service gateway is a single unified access point across one or more service nodes

Its role is not optional, but essential. We can do routing and forwarding and filter implementation in the service gateway. The advantages are summarized as follows:

  • Prevent internal service concerns from being exposed to external clients
  • Added an additional layer of security for our internal multiple services
  • Reduce the complexity of accessing microservices

According to the content in the figure, we can get the following information:

  • User access entry, unified access to other micro-service nodes through the gateway
  • The functions of a service gateway areRouting forwarding.API monitoring,Access control,Current limiting

And that’s what a service gateway is for!

1) Zuul comparison

SpringCloud Gateway is a new SpringCloud project that aims to replace Netflix Zuul. It is based on Spring5.0 + SpringBoot2.0 + WebFlux and other technologies. Its performance is higher than that of Zuul. According to official information, its performance is 1.6 times that of Zuul, and it is intended to provide a simple and effective unified API routing management method for micro-service architecture.

SpringCloud Gateway not only provides a unified routing method (reverse proxy), but also provides basic Gateway functions based on Filter chain (defining Filter to Filter requests), such as authentication, flow control, fusing, path rewriting, log monitoring, etc.

In fact, when it comes to Netflix Zuul, those of you who are using or planning to use the microservice architecture should be familiar with it. After all, Netflix is an established open-source microservice provider. Rookie and the old contention, if the rookie does not point hard strength, how to make people feel at ease transition!

Here we can take a look at WeFlux by the way. WebFlux fills the gap in Spring’s responsive programming.

There may be many friends who do not know WebFlux. Dish will explain WebFlux in the following part, which is really delicious!

WebFlux responsive programming is not only a change in programming style, but also provides responsive access development packages for a number of well-known frameworks, such as Netty, Redis (if you don’t know Netty’s power, you can think about why Nginx can carry so much concurrency, The bottom layer is based on Netty.)

So what does all this have to do with Zuul? We can look at Zuul’s IO model

The integrated version of Zuul in SpringCloud uses the Tomcat container and the traditional Servlet IO processing model. The Servlet lifecycle is managed by the Servlet Container.

The problem is that a Servlet is a simple network IO model. When a request enters a ServletContainer, it is bound to a thread. This model is fine in low concurrency scenarios, but once it is concurrency, the number of threads increases. The problem is that context switching is frequent, memory consumption is heavy, and the processing time of the request becomes longer. Is the so-called pull a hair and move the whole body!

SriingCloud Zuul is based on a blocking processing model on servlets, that is, Spring implements a servlet (DispatcherServlet) that handles all requests and blocks the processing by this servlet. Although SpringCloud Zuul 2.0 started with Netty as a concurrent IO framework, there are no plans to integrate with this version.

Note: The use of Gateway depends on the project

Three, master the gateway

1. The Gateway

The most critical step is to introduce gateway dependencies

<! - gateway gateway - > < the dependency > < groupId > org. Springframework. Cloud < / groupId > <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
2. Project structure

Here I simply created a micro-service project, which has a store-gateway service gateway and a store-order service. Because this article only explains the role of the service gateway, we don’t need too many service providers and consumers!

There is only one controller in the store-order order service, the OrderController, and there is only one ridiculously simple API in it

@RestController @RequestMapping("order") public class OrderController { @GetMapping("/{id:.+}") public String Detail (@pathvariable String id) {return stringutils. join(" get item with id ", "id "); }}

We start the two services separately and then access the API of the order service:

The result must be in line with expectations, not to roll over. 8001 is the interface of the order service. At this time, we can understand that each service of the micro-service architecture is started independently and can be accessed independently, which is equivalent to the traditional single service.

Let’s see, if we use ports to distinguish each service, can we also achieve the effect of micro-services? In theory that might be fine, but what about hundreds or thousands of services? Port explosion, maintenance explosion, governance explosion… Say nothing else, the state of mind directly exploded! At this point, we thought how great it would be if we only used the same port to access each service. Consistent ports and inconsistent route prefixes, which distinguish services by route prefixes, bring us into the service gateway scenario. Yes, that’s one of the functions of the service gateway — routing and forwarding.

3. Gateway appears

If we’re going to use a gateway, one of the services we created above is the store-gateway! How does it work? Let’s make a simple change to the configuration file:

spring:
  application:
    name: store-gateway
  cloud:
    gateway:
      routes: 
        - id: store-order 
          uri: http://localhost:8001 
          order: 1
          predicates:
            - Path=/store-order/** 
          filters:
            - StripPrefix=1

Few crap, we directly start the gateway, through visit http://localhost:8000/store-order/order/123 to see if we can get orders?

Very smoothly, we successfully got the goods with the ID of 123!

Let’s look at the composition of the URL:

Access to our service means the gateway configuration is in effect. Let’s take a look at this configuration item!

Spring. Cloud. Gateway This is the configuration prefix for the service gateway gateway.

Routes is the plural form, so we can be sure that this configuration item is an array, so it means that we can route multiple routes to which microservice when the request meets certain criteria.

  • Id:Currently routedThe onlylogo
  • URI: The address to which the request is forwarded
  • Order: The priority of the route, the lower the number, the higher the level
  • Predicates:The condition that the route needs to satisfy is also an array (in this caseorThe relationship between)
  • Filters: Filters through which the request can be modified as it passes

After understanding the necessary parameters, we were also happy to deploy and use, but the good times did not last long, we ushered in a new problem. The 8001 port used by my order service was used by other service due to some reasons. At this time, the small head is big again. In this case, the result of marrying the wrong bridal sedan chair will certainly not appear!

Let’s think about how to solve a problem like this. Since all use micro service, then we can use the service name of the way to jump access, so that no matter how the port change, will not affect our normal business! If we use the service mode, we need a registry, so that the service we started can be synchronized to the registry, so that the gateway can find the service in the registry according to the service name to conduct the route jump! Then we need a registry, and here we use NACOS as the registry.

about
NacosThe understanding can be airborne
Micro service rookie Nacos, see will, I said!

We have configured the following files in the service gateway and the order service respectively:

After starting the two services, we can see the two services in the list of console services in Nacos:

We can see that the service name of the order service is store-order, so we can make the following changes in the gateway configuration file:

One of the configuration differences from the above is that HTTP is replaced by LB (LB refers to getting the microservice by name from NaCos and following a load balancing policy), and the other port is replaced by the service name

So let’s continue to visit the above URL to see if we can successfully access the order service:

The result still did not roll over! In this way, no matter how the port of the order service changes, as long as our service name remains the same, we can always access our corresponding service!

Day by day the past ~ service is also a little bit of increase! Finally one day bored, because every time increasing service have to go to the configuration file a configuration of routes, although is only the operation of the CV, but which day dishes accidentally hand a shake, so ~ ~ ~ come on come on, look what we can be lazy writing, finally not dishes, found a kind of simplified version! The configuration is as follows:

Is this it? Yes, that’s it! No matter how much your service, I don’t need to modify the configuration file. The purpose of this configuration is to request unified access to the gateway address: gateway port/service name/interface name. Visit the page again and it still works!

But convenient to convenient, convenient at the same time also limits a lot of extension functions, so use need to think twice! Don’t be lazy!

Four, master the core

The above has said the simple use of the gateway, read the small partners must have been able to get started! Let’s continue to strike while the iron is hot and get to the heart of the Gateway. If nothing else, routing and forwarding must be the core of the gateway! We have already seen a specific routing information carrier, which mainly defines the following information (recall) :

  • Id: The unique identity of a Route, distinct from other routes
  • URI: The route points to the destination URI, which is the microservice to which the client request is ultimately forwarded
  • Order: Sort between routes. The smaller the number, the higher the order, and the higher the matching priority
  • Predicate: Used for conditional determination, the actual route is not executed until the assertions all return true
  • Filter: Filters are used to modify request and response information

Here is the access process:

This diagram clearly describes the invocation process of the service gateway.

  1. The GatewayClient issues a request to the GatewayServer
  2. The request is first retrieved by the HttpWebHandlerAdapter and turned into the gateway context
  3. The context of the gateway then passed to the DispatcherHandler, it is responsible for will be distributed to RoutePredicateHandlerMapping request
  4. RoutePredicateHandlerMapping is responsible for routing lookup, routing assertion judgment and more routing is available
  5. If the assertion is successful, the FilteringWebHandler creates the filter chain and calls it
  6. The request passes through the PreFilter -> micro-service -> PostFilter method at a time, and finally returns the response

Process to understand, we extract the key! Assertions and Filters

1. The assertion

Predicate, also known as assertions, is primarily used to make conditional judgments, and only if the assertions all return true will the route actually be performed

1) Assertion factory

There are a number of assertion factories built into the SpringCloud Gateway, all of which match different properties of HTTP requests, as follows.

  • Assertion factory based on type Datetime

This type of assertion factory makes decisions based on time

1, AfterRoutePredicateFactory: receive a date parameters, to determine whether a request date later than the specified date

2, BeforeRoutePredicateFactory: receive a date parameter, to determine whether a request date before the specified date

3, BetweenRoutePredicateFactory: receiving date of two parameters, judge whether the request date within a specified period of time

  • Based on the remote address of the assertion RemoteAddrRoutePredicateFactory factory

This type of assertion factory takes a parameter, the IP address side, and determines whether the requested host address is in the address segment. (eq: -remoteAddr =192.168.1.1/24)

  • Based on the assertion Cookie factory CookieRoutePredicateFactory

This type of assertion factory takes two parameters, the Cookie name and a regular expression, and determines whether the requested Cookie has the given name and the value matches the regular expression. (eq: -cookie =cbuc)

  • Based on the Header of assertion HeaderRoutePredicateFactory factory

The assertion factory of this type takes two parameters, the title name and the regular expression. Determines whether the request Header has the given name and the value matches the regular expression. (eq: -header = X-request)

  • Based on the Host’s assertion HostRoutePredicateFactory factory

This type of assertion factory receives a parameter, the hostname pattern. Determines whether the requested host meets the matching rule. (eq: -host =**.cbuc.cn)

  • Based on the Method of assertion factory MethodRoutePredicateFactory Method request

The assertion factory of this type receives a parameter to determine whether the request type matches the specified type. (eq: -method =GET)

  • Based on the Path that request Path PathRoutePredicateFactory factory

This type of assertion factory receives a parameter to determine whether the URI part of the request satisfies the path rule. (-eq: -path =/order/)

  • Based on the Query request parameters QueryRoutePredicateFactory assertion factory

This type of assertion factory takes two parameters, a request for Param and a regular expression. Determines whether the request parameter has the given name and the value matches the regular expression. (eq: -query =cbuc)

  • Based on the routing weight WeightRoutePredicateFactory assertion factory

This type of assertion factory receives a [group name, weight] and forwards it according to weight for routes within the same group

2) use

There are so many assertion factories that we won’t use them all here, but we will combine them with several assertion factories.

As usual, we don’t talk too much and go straight to the code:

CustomPredicateRouteFactory

The configuration file

The test results

success

fail

Amazing at the same time, don’t worry about looking down, let’s return to the code, see, why one can access successfully, but the access failed. Two aspects: 1. What are the different URLs accessed by the two. 2

Develop independent thinking first, then see the solution

When you finish thinking, some students may have the result, then let’s continue to look down! First is a CustomRoutePredicateFactory class, this class is a bit like interceptors, when doing the forward requests for interception, we request can make a breakpoint:

As you can see, it is really the function of the interceptor to intercept each request as it is initiated. RoutePredicateFactory is used to handle URL processing, and the apply method is used to retrieve the ServerHttpRequest object via Exchange.getRequest (). In this way, you can get the request parameters, request mode, request and other information. The shortcutFieldOrder() method is also one of the keys to this rewrite. We need to return the attributes defined in our entity class before we can receive the attributes we assign in the apply() method!

Note: If there are multiple attributes in the custom entity that need to be determined,
shortcutFieldOrder()The order in the method should be the same as the order of the parameters in the configuration file

So when we write this assertion factory, how do we make it work? The @Component annotation is definitely necessary for Spring container management. So how does a registered assertion factory claim its use? Back to the configuration file!

We’ll focus on the predicates configuration. There are three configurations, one of which is Path. The other two are unfamiliar, but the Custom configuration is familiar. Yes, it looks like we’ve defined an assertion factory called CustomRoutePredicate, which is similar, but not quite so much. Then I’ll give you another hint:

Let’s take a look at some of the self-implementing classes of the abstract assertion factory! Among them are PathRoutePredicateFactory, yes, it is you want to! Is there a kind of tear through the rain and fog to see the feeling of blue sky! The key of our configuration file is declared with the prefix of the class name, which means that the format of the Assertion Factory class must be: Custom Name + RoutePredicateFactory suffix, and then declared in the configuration file. – Before: limit the request time Before XXX.

-custom =cbuc; -custom =cbuc; -custom =cbuc; If you have multiple parameters, you can separate them by, in the same order that shortcutFieldOrder() returns them in the assertion factory!

If you encounter any obstacles in customizing your assertion factory, take a look at how the built-in assertion factory is implemented.
Look at the source code is always right!

Filter 2.

Next comes the second core, which is the filter. The role of this core is quite simple, which is to do a series of manipulation to the request and response during the transmission of the request. In case you need to go back to see the request process is too troublesome, Dish considerate posted the flow chart again:

Gateway filters can be divided into local filters and global filters. The name tells you what it does. Local is for one route, global is for all routes. However, both local and global lifecycles are divided into pre and post.

  • Pre: Invoked before routing to the microservice. We can use this filter for authentication, selecting requested microservices in the cluster, logging debugging records, and so on
  • POST: Executes after routing to the micro-service. We can use this filter to add standard HTTP headers to the response, collect statistics and metrics, and send the response from the micro-service to the client.
1) Local filter

Local filters are filters that are specific to a single route. There are also many filters built into the Gateway

We choose a few commonly used filters to illustrate :(The following filter omits the suffix GaewayFilterFactory, and the full name is prefix + suffix)

Filter prefix role parameter
StripPrefix The path used to truncate the original request Use a number to indicate the number of paths to truncate
AddRequestHeader Add the Header to the original request The name and value of the Header
AddRequestParameter Add request parameters to the original request Parameter names and values
Retry Retry for different responses RETIES, STATUSES, METHODS, SERIES
RequestSize Sets the size of the maximum request packet that is allowed to be received Request packet size, per byte, default 5M
SetPath Modify the path of the original request Modified path
RewritePath Overwrite the original request path The original path regular expression and the rewritten path regular expression
PrefixPath Prefix the original request path The prefix path
RequestRateLimiter For request flow limiting, the flow limiting algorithm is token bucket KeyResolver, Retelimiter, StatusCode, DenyEmptyKey

The built-in filter allows you to try it yourself. If you have any questions, please ask me!

Let’s move on to how to customize filter factories. Don’t say so much, let’s go to code

CustomGatewayFilterFactory

The configuration file

When we turn on request counting, we can see that the console counts the number of requests:

So we can easily implement local filters in this way

2) Global filters

Global filters apply to all routes and do not require configuration. Through the global filter can realize the unified verification of permissions, security verification and other functions

As usual, let’s first look at what global filters exist in the Gateway:

Compared to local filters, global filters have fewer constraints on their naming because they do not need to be configured in a configuration file.

Let’s familiarize ourselves with the classic global filter

Filter name role
ForwardPathFilter / ForwardRoutingFilter The path forwards the relevant filter
LoadBalanceerClientFilter Load Balancing Client Related Filters
NettyRoutingFilter / NettyWriteResponseFilter HTTP client-related filters
RouteToRequestUrlFilter Routing URL-related filters
WebClientHttpRoutingFilter / WebClientWriteResponseFilter The request WebClient client forwards the real URL of the request and writes the response to the current request response
WebsocketRoutingFilter WebSocket related filters

Once you understand the built-in filters, let’s look at how to define a global filter!

CustomerGlobalFilter

For the global filter, we do not need to configure it in the configuration file because it applies to all routes

The test results

success

fail

As you can see, we use the global filter to authenticate, and if we do not carry the token, we cannot access it!


So far we have seen routing and forwarding of the service gateway, permission checking and even crude API monitoring and traffic limiting based on assertions and filters

But there are already better components in the SpringCloud to do both API monitoring and flow limiting. After all, the single principle, the more you do, the more you make mistakes!

Stay tuned for more articles on SpringCloud components in the future!

It’s up to us to decide what’s good and what’s bad about the microservice framework. But no matter what is good or bad, in the face of a new technology, the most we need to do is to accept it, tolerate it, and then use it well, is a mule or a horse, their walk to know.

Don’t talk, don’t be lazy, and dishes together to do a blowing cattle X architecture program ape bar ~ point a concern to do a companion, let dishes no longer lonely. See you later!

Today you work harder, tomorrow you will be able to say less words for people!

I am small dish, a strong man with you. 💋

WeChat public account has been opened, XiaoDai Liang remember, did not pay attention to the students remember to pay attention!