Hello everyone, I’m Xiao CAI.

A man who wants to be a man who talks architecture! If you also want to be the person I want to be, or point a concern to do a companion, let small dishes no longer lonely!

This article mainly introduces the service Gateway of SpringCloud

Refer to it if necessary

If it is helpful, do not forget the Sunday

Wechat public number has been opened, xiao CAI Liang, did not pay attention to the students remember to pay attention to oh!

Some time ago, I talked with my friends about the current situation of their company. Recently and in the future, the company will fully transition from single service to micro service architecture. Here we hear the key word – microservices. That sounds reasonable to me, too. The Internet is constantly developing, which is not only the development of the industry, but also the development of the system architecture. Today, the architecture on the market generally goes through these stages:

Is that a good thing? It’s a good thing, no doubt about it. They die on the beach because they don’t keep up with The Times. But is it all a good thing? Not really.

First, we need to understand what problems microservices solve. In a big way, it’s an application level and a human level

  • Application level: The architecture of individual services is very simple, and the low cost of project development and maintenance is its undisputed advantage. But bloated coupling places an undue burden on the infrastructure. If an application consumes a large number of CPU processing resources, other processing resources will starve to death, resulting in higher system latency, which directly affects system availability.

  • The human dimension: Independent, multilingual ecology is also the label of microservices. In individual services, more human resources are not necessarily more efficient, but more prone to error. However, microservices are different. Each service is independent, and teams can more easily collaborate in development. Even a set of systems, multiple services, multiple languages, without conflict.

But we must not be blinded by benefits. The downsides of microservices have always been there:

  • You need to consider fault tolerance between services
  • Data consistency needs to be considered
  • Distributed transactions need to be considered
  • .

Many people think that the core of microservices is micro. The finer the service, the better. It’s like a single principle that you don’t even think about when you write code. Here’s a core concept to understand: microservices aren’t about being small, they’re about being the right size

It sounds simple, but how big is the right size? This may vary from team to team, project to project. The right size may depend on fewer code repositories, fewer deployment queues, fewer languages… Here more can’t hammer it out!

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

We’ve gone a bit far. Let’s try to get back to it. Now that micro-services have become mainstream, how we design micro-services is what we should be doing, not just arguing with people about how to reject micro-services. So in this article we are going to talk about SpringCloud’s service Gateway Gateway

SpringCloud’s service Gateway Gateway

First, know the gateway

What is a service gateway? Don’t hit yourself in the head. Let’s ask another 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 vital. We can do routing forwarding and filter implementation in the service gateway. The advantages are summarized as follows:

  • Prevents internal service concerns from being exposed to external clients
  • Added an additional layer of security for our internal services
  • Reduce the complexity of microservice access

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

  • Users can access other micro-service nodes through the gateway
  • The functions of the service gateway areRouting forwarding.API monitoring,Access control,Current limiting

That’s what a service gateway is all about!

1) Zuul comparison

SpringCloud Gateway is a new project from SpringCloud that aims to replace Netflix Zuul. It is based on Spring5.0 + SpringBoot2.0 + WebFlux and other technologies, the performance is higher than Zuul, according to the official information, the performance is 1.6 times Zuul, intended to provide a simple and effective unified API routing management for microservices architecture.

SpringCloud Gateway not only provides a unified routing mode (reverse proxy), but also provides basic Gateway functions based on Filter chains (defining filters to Filter requests), such as authentication, traffic control, fusing, path rewriting, and log monitoring.

In fact, when it comes to Netflix Zuul, those who are using or preparing to use micro-service architecture should be familiar with it. After all, Netflix is an old-line micro-service open source. The competition between the rookie and the old guard, if the rookie has no hard power, how to let people feel at ease transition!

Here we can take a look at Weflux by the way. Webflux has filled the gap in Spring’s responsive programming.

There may be a lot of friends do not know Webflux, small dish next will also give an explanation about Webflux, actually really sweet!

Responsive programming for Webflux is not just a change in programming style, but a development kit that provides responsive access to a number of well-known frameworks, such as Netty, Redis, etc. (If you don’t know the power of Netty, consider why Nginx can support 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

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

The problem is that servlets are 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 concurrency occurs, the number of threads increases. The problem with that is frequent context switches, heavy memory consumption, and longer processing times for requests. Is the so-called touch the whole body!

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

Note: This is not intended to promote Gateway, the specific use depends on the project

Three, master the gateway

1. The Gateway

The most critical step is to introduce gateway dependencies

<! - gateway gateway - >
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
Copy the code
2. Project structure

I have simply created a microservice project with a store-gateway service gateway and a store-Order order service. Since this article only illustrates the role of a service gateway, we don’t need many service providers and consumers!

There is only one controller in the Store-Order order service, OrderController, and there is only one outrageously simple API in it

@RestController
@RequestMapping("order")
public class OrderController {
    
    @GetMapping("/{id:.+}")
    public String detail(@PathVariable String id) {
        return StringUtils.join("Obtained ID as", id, "Goods"); }}Copy the code

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

The results must be in line with expectations and not tip over. 8001 is the interface of order service. At this time, we can know that each service in the original microservice architecture can be independently started and accessed, which is equivalent to the traditional single service.

Let’s think about it. If we use ports to differentiate each service, can we also achieve the effect of microservices? In theory, yes, but what about hundreds or thousands of services? Port explosion, maintenance explosion, treatment explosion… If nothing else, the mentality exploded directly! At this point we thought how nice it would be if we only used one unified port to access each service. Consistent ports and inconsistent route prefixes, which distinguish services by route prefixes, bring us to the service gateway scenario. Yes, this is one of the functions of the service gateway – routing and forwarding.

3. The gateway is displayed

Since you need a gateway, one of the services we created above, store-gateway, comes in handy! 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
Copy the code

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 order of goods with ID 123!

Let’s look at the composition of the URL:

If you can access our service, the gateway configuration is in effect. Let’s see how this configuration item works.

Spring.cloud. gateway is the service gateway configuration prefix, there is nothing to say, you need to remember it.

Routes is a plural form, so we can be sure that this configuration item is in the form of an array. Therefore, it means that we can configure multiple routes and forward the request to which micro-service when the request meets certain conditions.

  • Id:Currently routedThe onlylogo
  • Uri: Address to which the request is forwarded
  • Order: indicates the priority of a route. The smaller the number, the higher the priority
  • Predicates:The condition that the route needs to satisfy is also an array (here it isorThe relationship between)
  • Filters: through which requests can be modified as they are passed

Knowing the necessary parameters, we were happy to deploy and use them, but it didn’t last long, and we had a new problem. The port 8001 used by my order service was used by other services due to some reasons. At this time, my small head is big again. This situation will definitely not result in the wrong bridal sedan car marrying the right man!

Let’s think about how to solve this kind of problem. Since we have adopted micro-service, can we use the way of service name to jump access, so that no matter how the port changes, it will not affect our normal business! That if use the service way, need a registry, so that we start the service can be synchronized to the registry in the registry, so that the gateway can according to the service name to find services in the registry for routing jump! Then we need a registry, and Nacos is used as the registry.

To learn more about Nacos, you can parachute in the micro-services rookie Nacos, which will, I said!

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

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

The order service name is “store-order”, so we can make the following changes in the gateway configuration file:

The configuration here differs from one of the above differences by replacing HTTP with LB (which refers to getting microservices by name from NACOS and following a load balancing policy) and the second port with the service name

Let’s continue with the above URL to see if we can successfully access the order service:

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

Day by day ~ service is also increasing bit by bit! 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 many services you provide, I don’t need to change my profile. The purpose of this configuration is to request unified gateway address: gateway port/service name/interface name access mode. Visit the page again and it still works!

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

Four, master the core

The above has said that the simple use of the gateway, after watching the small friends must already be able to use! Let’s continue to strike while the iron is hot and look at the core of the Gateway Gateway. If nothing else, routing and forwarding must be at the heart of the gateway! We have learned from the above a specific routing information carrier, mainly defined the following information (recall) :

  • Id: unique identifier of a Route, which is different from other routes

  • Uri: The route points to the destination URI, which is the microservice to which the client request is ultimately forwarded

  • Order: Used to sort multiple routes. The smaller the value is, the higher the order is and the higher the matching priority is

  • Predicate: Used to determine conditions. The route is executed only when both assertions return true

  • Filter: Modifies the request and response information

Here’s a look at the access process:

This diagram clearly describes the invocation flow of the service gateway (blind confidence)

  1. The GatewayClient sends a request to the GatewayServer
  2. The request is first fetched by an 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 succeeds, the filter chain is created and called by FilteringWebHandler
  6. The request goes through the PreFilter -> Microservice -> PostFilter method once and finally returns the response

Process understood, let’s extract the key! Assertions and filters

1. The assertion

Predicate is an assertion that is used to determine conditions. A route is executed only when both assertions return true

1) Assertion factory

There are many assertion factories built into the SpringCloud Gateway, all of which match the different attributes of the HTTP request as follows;

  • Assertion factory based on Datetime type

This type of assertion factory makes judgments based on time

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

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

BetweenRoutePredicateFactory: 3, * * * * 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

The assertion factory of this type receives a parameter, the IP address side, to determine whether the requested host address is in the address segment. (eq: -remoteaddr =192.168.1.1/24)

  • Based on the assertion Cookie factory CookieRoutePredicateFactory

The assertion factory of this type 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 accepts two parameters, a title name and a 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

The assertion factory of this type accepts one parameter, the host name schema. Check 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 for this type takes a parameter to determine whether the request type matches the specified type. (eq: -method =GET)

  • Based on the Path that request Path PathRoutePredicateFactory factory

The assertion factory of this type takes a parameter to determine whether the URI portion of the request satisfies the path rule. (-eq: -path =/order/)

  • Based on the Query request parameters QueryRoutePredicateFactory assertion factory

The assertion factory of this type takes two parameters, requesting 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

The assertion factory of this type receives a [group name, weight] and then forwards the routes based on the weight for the routes within the same group

2) use

So many assertion factories, here is not a demonstration, we combine the use of several assertion factories to demonstrate.

As usual, we don’t talk nonsense, directly on the code:

CustomPredicateRouteFactory

The configuration file

The test results

success

fail

And while you’re at it, don’t worry, let’s go back to the code and see why one access succeeds and one access fails. Two aspects: 1. What are the differences between the urls accessed by the two? 2

Develop independent thinking before looking at solutions

When you finish thinking, maybe some of the students have a result, that let us continue to look! 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 indeed the interceptor’s function to intercept each request as it is initiated. The URL processing is done in RoutePredicateFactory. In the apply method, the ServerHttpRequest object can be obtained by using exchange.getrequest (). Thus, we can obtain the request parameters, request mode, request and other information. The shortcutFieldOrder() method is also one of the keys to overwriting. We need to return the attributes defined in our entity class before we can receive the attributes we assigned in apply()!

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

So once we’ve written the assertion factory, how do we make it work? The @component annotation is definitely needed for Spring container management. So how does a registered assertion factory claim usage? That’s back to the configuration file!

Here we focus on the predicates configuration item, there are three configurations respectively, one is the Path we are familiar with, the other two are a little strange, but here we look at the Custom is not familiar. Yeah, I think we’ve defined an assertion factory called CustomRoutePredicate, which is kind of similar, but kind of similar. I’ll give you one more hint:

Let’s take a look at the self-implementing classes of the abstract assertion factory! Among them are PathRoutePredicateFactory, yes, it is you want to! There is a sense of clearing the rain and fog to see the blue sky! The key of the configuration file is declared with the prefix of the class name, that is, the format of the assertion factory class must be: custom name + RoutePredicateFactory suffix, and then declared in the configuration file. Before limits requests to a time Before XXX.

-custom =cbuc, cbuc is our rule, only the name of the user cbuc request success. If there are multiple arguments, separate them with, in the same order as the arguments returned by shortcutFieldOrder() in the assertion factory!

If you’re having trouble customizing an assertion factory, take a look at how the built-in assertion factory is implemented. Read the source code always right!

Filter 2.

Next comes the second core, the filter. The core’s role is simple enough to manipulate requests and responses in the process of request delivery. In order to prevent you from rowing back to see the request process is too troublesome, xiao CAI is close to paste a flow chart again:

Gateway filters can be divided into local filters and global filters. It is used locally on a route and globally on all routes. But whether it’s local or global, the life cycle is pre and Post.

  • Pre: used before routing to the microservice. We can use this filter for authentication, selecting requested microservices in the cluster, logging debug logs, and so on
  • Post: executed after routing to the microservice. This filter can be used in response to adding standard HTTP headers, collecting statistics and metrics, and sending responses from microservices to clients.
1) Local filter

A local filter is a filter for a single route. Also, Gateway already has many filters built in

The following filters omit the suffix GaewayFilterFactory. The full name is prefix + suffix.

Filter prefix role parameter
StripPrefix The path used to truncate the original request Use numbers to indicate the number of paths to truncate
AddRequestHeader Add the Header for the original request Header name and value
AddRequestParameter Add request parameters to the original request Parameter name and value
Retry Retry for different responses Reties, Statuses, Methods, series
RequestSize Sets the maximum size of a request packet that can be received Request packet size, in bytes, default 5M
SetPath Modifies the path of the original request Modified path
RewritePath Override the original request path The original path regular expression and the rewritten path regular expression
PrefixPath Prefixes the original request path The prefix path
RequestRateLimiter For request traffic limiting, the traffic limiting algorithm is token bucket KeyResolver, reteLimiter, statusCode, and denyEmptyKey

Built-in filter partners can try their own, have a question welcome to ask!

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

CustomGatewayFilterFactory

The configuration file

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

So we can easily implement local filters in this way

2) Global filters

The global filter applies to all routes and does not need to be configured. Global filters can be used to verify permissions and security

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

In contrast to local filters, the naming of global filters is less restrictive and does not need to be configured in a configuration file.

Let’s get familiar with the classic global filter

Filter name role
ForwardPathFilter / ForwardRoutingFilter Path forwarding related filters
LoadBalanceerClientFilter Filters related to load balancing clients
NettyRoutingFilter / NettyWriteResponseFilter Http client-related filters
RouteToRequestUrlFilter Route URL related filter
WebClientHttpRoutingFilter / WebClientWriteResponseFilter Request WebClient The WebClient forwards the request for the real URL and writes the response to the current request response
WebsocketRoutingFilter Websocket related filter

Now that we know about the built-in filters, let’s look at how to define global filters!

CustomerGlobalFilter

For global filters, we do not need to configure them in the configuration file because they apply to all routes

The test results

success

fail

As you can see, we use the global filter for authentication processing, if you do not carry a token will not be able to access!


So far we have seen service gateway routing and forwarding, permission verification and even rough API monitoring and limiting based on assertions and filters

But for API monitoring and flow limiting, there are better components in SpringCloud that do both. After all, the more you do, the more you get wrong!

Stay tuned for more articles on SpringCloud components!

It’s up to us to decide what’s good or bad about the microservices framework. But no matter what is good or bad, in the face of the emergence of a new technology, what we need to do is to accept it, tolerate it, and then make good use of it. Whether it is a mule or a horse, you will know by yourself.

Don’t talk, don’t be lazy, and xiao CAI do a blowing bull X do architecture of the program ape ~ point a concern to do a companion, let xiao CAI no longer lonely. See you later!

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

I am xiao CAI, a man who grows stronger with you. 💋

Wechat public number has been opened, xiao CAI Liang, did not pay attention to the students remember to pay attention to oh!