This is the fourteenth article in the Spring Cloud column, and knowing the first thirteen will help you understand it better:

  1. Spring Cloud first article | Spring Cloud preface introduces an overview and its commonly used components

  2. The second Spring Cloud | use and understand Eureka registry

  3. Spring Cloud third | build a high availability Eureka registry

  4. Spring Cloud fourth article | client side load balancing Ribbon

  5. The fifth canto of Spring Cloud fusing Hystrix | service

  6. Spring Cloud article 6 | Hystrix Dashboard monitoring Hystrix Dashboard

  7. Spring Cloud seventh article | declarative service invocation Feign

  8. Spring Cloud the eighth article | Hystrix cluster monitoring Turbin

  9. Spring Cloud 9 article | distributed service tracking Sleuth

  10. Spring Cloud center Config the tenth article | distributed configuration

  11. Spring Cloud article 11 | distributed configuration center high availability

  12. Spring Cloud article 12 | message Bus Bus

  13. Spring Cloud the thirteenth article | Spring Boot Admin service monitoring

I. Gateway classification

Open Api

OpenApi (openApi) enterprises need to open their own data and capabilities as development platforms, which are usually provided in the way of rest. The best examples are taobao open platform, Tencent QQ development platform and wechat open platform. Open API An Open platform is bound to involve customer application access, API permission management, call times management, and so on. There must be a unified portal for management, which is exactly when API gateway can play a role.

Microservice Gateway

The concept of microservices was first proposed in 2012, and with the strong promotion of Martin Fowler, microservices have been greatly developed after 2014. One component that can be said to be essential in the microservices architecture is the microservices gateway, which handles load balancing, caching, routing, access control, service proxy, monitoring, logging, and so on. API gateway exists as microservice gateway in microservice architecture.

API service management platform

The above microservice architecture may be difficult for enterprises to implement, because enterprises have many legacy systems, and it is too costly for enterprises to extract all of them into microservers. However, because there are a large number of API services calling each other between different systems, it is necessary to manage inter-system service calls, clearly see the relationship between system calls, and monitor inter-system calls. API gateway can solve these problems, we can think of microservice gateway as enterprise API service management platform if there is no large-scale implementation of microservice architecture.

Second, gateway design

Open API interface

1. For the API gateway used by OpenAPI, general partners need to access OpenAPI platform in the form of applications, and partners need to apply for applications on OpenAPI platform. Therefore, in addition to OpenAPI gateway, there needs to be a partner-oriented platform for partners to use, which requires OpenAPI gateway to provide API for the user platform to access. The architecture is as follows:

Of course, in a simple scenario, there may not be a need to provide a partner-facing portal, just a company’s operations staff directly adding partner application ids/keys, etc., in which case there is no need for a partner portal subsystem.

Intranet API interface

2. The API gateway on the Intranet can be regarded as a micro-service gateway or an API service governance platform on the Intranet. When an enterprise manages all its applications using a microservices architecture, the API gateway acts as a microservices gateway. However, when the enterprise only uses REST API to access the calls between systems, the API gateway manages the calls, and then the API gateway plays the role of API service governance. The framework reference is as follows:

3. For internal public network applications (such as APP and company website), if the management is careful, it is possible to use an independent API gateway to deal with these internal public network applications in terms of architecture. For simple processing, partner oriented API gateway can also be used. If you use a separate API gateway, there are the following benefits:

The priorities of services for partners and corporate entities are different, and different API gateways can isolate the impact of services.

The management process used by the internal API may not be the same as the partner-oriented management process.

The internal API generally has more requirements on function extension than the OpenAPI.

Based on the above analysis, if the company is capable, it is recommended to use the partner OPEN API gateway and the internal public network application gateway separately.

Gateway framework

  • Tyk: Tyk is an open source API gateway that is fast, extensible, and modern. Tyk provides an API management platform, including AN API gateway, API analysis, developer portal, and AN API management panel. Try is a gateway service implemented based on Go. https://tyk.io

  • Kong: Kong is an extensible open source API Layer(also known as API gateway or API middleware). Kong runs in front of any RESTful API, provides additional functionality and services beyond the core platform through plug-in extensions, and is a secondary development solution based on Nginx+Lua. https://konghq.com

  • Orange: Orange is a similar API gateway program based on OpenResty, developed by Chinese. http://orange.sumory.com

  • Netflix Zuul: Zuul is an open source service from Netflix that provides dynamic routing, monitoring, elasticity, security, and other edge services. Zuul, Netflix’s JVM-based routing and server-side load balancer, has been integrated with Spring Cloud in the Netflix project. https://github.com/Netflix/zuul

  • GateWay: GateWay is a subproject of Spring Cloud, built on Spring5+ and based on Spring Boot 2.x’s responsive, non-blocking API. https://spring.io/projects/spring-cloud-gateway

4. Gateway functions

The gateway implements load balancing, routing and forwarding, logging, permission control, and monitoring.

5. Differences between gateways and filters

The gateway intercepts all server requests for control

Filters block a single server request for control

Nginx and Zuul

Nginx uses server load balancing for forwarding

Zuul relies on the Ribbon and Eureka to implement local load balancing forwarding. Nginx is more powerful than Zuul. It can integrate other languages such as Lua scripts to achieve powerful functions.

Seven, gateway

Zuul is Spring Cloud recommend a component: https://github.com/Netflix/zuul

1. Use Zuul to implement reverse proxy

1-1. Add dependencies in the Spring Cloud-Zuul module

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

1-2. The content of the application.yml configuration file is as follows:

spring:
  application:
    name: springcloud-zuul
server:
  port: 9999
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8700/eureka
    The client updates the service information from Eureka service every 30 seconds
    registry-fetch-interval-seconds: 30
    I need to register my service with Eureka
    register-with-eureka: true
    # Need a retrieval service
    fetch-registry: true
  Heartbeat detection detection and renewal time
  instance:
    # tell the server that if I do not send you a heartbeat within 10 seconds, it means THAT I am faulty. Delete me
    #Eureka Specifies the maximum time the server must wait after receiving the last heartbeat, in seconds.
    lease-expiration-duration-in-seconds: 10
    Send a heartbeat to the server every 2 seconds to prove that the server is still alive. Default is 30 seconds
    #Eureka Interval in seconds for the client to send the heartbeat to the server (the client tells the server it will follow this rule)
    lease-renewal-interval-in-seconds: 2
Requests beginning with /api-a/ are forwarded to the SpringCloud-service-consumer service
Requests that begin with /api-b/ are forwarded to the SpringCloud-service-feign service
zuul:
  routes:
    api-a:
      path: /api-a/**
      serviceId: springcloud-service-consumer
    api-b:
      path: /api-b/**
      serviceId: springcloud-service-feignCopy the code

1-3. Add annotations to the main class

@enablezuulproxy // enable Zuul support @enableeurekaclient // EnableEurekaClient supportCopy the code

After completing the above operations, we can start the corresponding services as follows:

Then access the interface in the SpringCloud-service-Consumer service: http://localhost:9999/api-a/consumer/hello, Similarly springcloud – service – feign service interface so http://localhost:9999/api-b/feign/hello API in a path – a, and API – b respectively be routed to the response of the service, You can also configure to ignore apI-a,api-b, and so on

2. Zuul support for Ribbon and Hystrix

Zuul relies on the Ribbon and Hystrix, so Zuul has thread isolation, circuit breaker self-protection, and client-side load balancing for service calls, but only in combination with Path and serviceId

zuul.routes.<route>.path
zuul.routes.<route>.serviceIdCopy the code

The combination of path and URL is not supported

zuul.routes.<route>.path
zuul.routes.<route>.urlCopy the code

3. Use Zuul filter

Micro service quantity, each for our services and security check and access control, is very troublesome, this is not an option, it will increase the system maintenance of the late, because the every system of various validation logic in many cases the same or similar, then the non-business logic code scattered to the service, The resulting redundant code is something we do not want to see, so it is common practice to do this non-business validation through gateway services.

3-1. Life cycle of Filter

The Filter has four life cycles, namely “PRE”, “ROUTING”, “POST”, and “ERROR”. The whole life cycle can be shown in the following figure

Zuul implements most of its functionality through filters that correspond to the typical lifecycle of a request.

  • PRE: This filter is invoked before the request is routed. We can use this filter to authenticate, select requested microservices in the cluster, log debugging information, and so on.

  • ROUTING: This filter routes the request to the microservice. This filter is used to build requests sent to microservices and request microservices using Apache HttpClient or Netfilx Ribbon.

  • POST: This filter is executed after routing to the microservice. Such filters can be used to add standard HTTP headers to responses, collect statistics and metrics, send responses from microservices to clients, and so on.

  • ERROR: This filter is executed when errors occur in other phases.

In Zuul Gateway, we need to define a class that inherits the ZuulFilter abstract class and implements the four corresponding abstract methods.

A simple example to verify that the request has a userToken parameter:

@Component Public class TokenFilter extends ZuulFilter {// Filter type pre intercepts before requesting @Override public StringfilterType() {
        return "pre"; } // Filter execution order. When a request has multiple filters in one phase, @Override public int is executed one by one based on the return value of the methodfilterOrder() {
        return0; } @override public Boolean specifies whether the filter takes effectshouldFilter() {
        return true; } @override public Object run() throws ZuulException {RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); String userToken = request.getParameter("userToken");
        if (StringUtils.isEmpty(userToken)) {
            //setSendZuulResponse(false) make zuul filtering the request, not routed currentContext. SetSendZuulResponse (false); / / set the returned error code currentContext. SetResponseStatusCode (401); currentContext.setResponseBody("userToken is null");
            returnnull; } // Otherwise, execute the service logic.....returnnull; }}Copy the code

3-2. Restart springCloud-Zuul service, visit:

http://localhost:9999/api-b/feign/hello returns: userToken is null

http://localhost:9999/api-b/feign/hello?userToken= “” return: spring cloud provider – 01 hello world

In the filter code implemented above, we implement our custom filter by inheriting the ZuulFilter abstract class and rewriting the following four methods. The four methods define:

  • FilterType () : The type of filter that determines in which lifecycle of the request the filter is executed. This is defined as pre, which means that the request will be executed before it is routed.

  • FilterOrder () : filter execution order. When requests have multiple filters in a phase, they need to be executed sequentially based on the value returned by this method. The value is specified by a number. A larger number indicates a lower priority.

  • ShouldFilter () : Check whether this filter needs to be executed. Here we return true directly, so the filter will apply to all requests. In practice, we can use this function to specify the effective range of the filter.

  • Run () : specifies the logic of the filter. . Here we through currentContext setSendZuulResponse (false) make Zuul filtering the request, does not carry on the route, Then through currentContext. SetResponseStatusCode (401) set up the return error code, of course we can also further optimize our return, such as, Through currentContext. SetResponseBody (body) to return to the body content editing, etc.

4. Zuul routing rules

4-1. Default routing rules

When Zuul introduces the Eureka gateway, it creates a default routing rule for each service. By default, the instance name is used as the prefix of the request, so that services that are not open to the outside world can also be accessed. We can control which services are created for the routing rule.

zuul.ignored-services: *Copy the code

* indicates that default routing rules are not created for all services. Therefore, you need to configure routing rules.

4-2. Customize routing rules

For different versions compatible with the client, sometimes we need to cooperate with each other for a group of micro service to make it easier to define a version identification management, their version of the relationship, according to the logo we can easily know these services need to be used up and together, such as our service is used to release this way of naming, such as: Consumer – v1, consumer – v2 version of access services, we can use the custom routing rules, injection PatternServiceRouteMapper object can automatically build similar/v1 / consumer / * * routing rules

@Bean
public PatternServiceRouteMapper patternServiceRouteMapper() {return new PatternServiceRouteMapper("(? 
       
        ^.+)-(? 
        
         v.+$)"
        
       ."${version}/${name}");
}Copy the code

PatternServiceRouteMapper object can be through the regular expression from the custom service and route mapping relationship. Of the constructor

The first argument: a regular expression that matches whether the service name matches the custom rule,

The second argument: defines the path expression rules that are converted based on what is defined in the service name.

When developers PatternServiceRouteMapper of implementations are defined in the API gateway, should accord with the first parameter defines the service name of rules, the build will be preferred to use the path expression, if there is no matching service will use the default route mapping rules, A path expression prefixed with the full service name.

5. Path matching

In the above example, we saw that wildcards were used as matching paths. There are three types of wildcards, as follows:

The wildcard Wildcard meaning
? Matches a single character, such as /consumer/a, /consumer/b
* Matches any number of characters, such as /consumer/ ABC, /consumer/def
** Matches any number of characters and supports multiple paths, such as /consumer/ ABC /def, /consumer/ghi/ GKL

When we use it, for example, our consumer service routing path is: /consumer/**, the routing rule is /consumer/ext/**, since ** matches the multi-level directory, we need to distinguish these service paths. The properties configuration cannot guarantee the loading order of the configuration. However, in the YML configuration file we can use /consumer/ext/** before /consumer/** to ensure proper routing of the consumer-ext service

6. Ignore expressions

zuul.ignored-patterns: /**/hello/**Copy the code

This configuration ignores the path containing Hello

7. Route prefix

zuul.prefix: /api
zuul.strip-prefix: trueCopy the code

Prefix: the prefix that is brokered when the request matches the prefix

Strip-prefix: The proxy prefix is removed from the request path by default (true). It can be set to false to disable the removal of the proxy prefix, or zuul.routes.<route>. Strip-prefix =false to disable the removal of the proxy prefix for the specified route.

However, it was pointed out in Spring Cloud Micro-service Field that there were bugs in Brixton.SR7 and Camden.SR3, and the case version was Finchley

8. Zuul safety and Header

Sensitive Header Settings. Generally, headers are shared between services on the same system, but Zuul prevents some sensitive headers from leaking out and passing them to downstream servers. If we need to pass cookies, set-cookies,Authorization, etc., We can do that

Set zuul.sensitive-headers to nullCopy the code

Zuul.routes.<route>. SensitiveHeaders:' '
zuul.routes.<route>.custom-sensitive-headers: trueCopy the code

9. Ignore the Header

Use the zuul.ignoredHeaders attribute to discard some headers so that cookies are not propagated to other microservices

zuul.ignored-headers: CookieCopy the code

10. Disable the specified Filter

zuul.<SimpleClassName>.<filterType>.disable=trueCopy the code

For detailed configuration, please refer to the official website of Spring: https://cloud.spring.io/spring-cloud-static/Finchley.SR4/single/spring-cloud.html#_router_and_filter_zuul

Dynamic routing of Zuul

Zuul serves as a unified gateway for services. Traditionally, routing rules are configured in the configuration file. If the routing rules are changed, the server needs to be restarted, which stops services to the outside world. We combine SpringCloud Config distributed configuration center “Spring Cloud the tenth article | Config” distributed configuration center for dynamic routing rules, here no longer show message Bus Bus “Spring Cloud article 12 | message Bus Bus”.

1. Configure the central server

1-1. In order to ensure the cleanliness of the previous configuration center server module (Springcloud-Zuul-config-server), create a new configuration center server module (Springcloud-Zuul-config-server) 1-2 and add dependencies

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>Copy the code

1-3. Configure the application.yml file

spring:
  application:
    name: springcloud-zuul-config-server
  cloud:
    config:
      server:
        git:
          Git repository
          uri: https://gitee.com/coding-farmer/config-center
          Configure the repository path
          search-paths: "{profile}"
          Git repository user name
          username:
          Git repository password
          password:
          The configuration center uses Git to access remote Git repositories. Sometimes the local copy is contaminated.
          If force-pull=true is set, the remote repository will be forced to update the local repository
          force-pull: true
          C:/Users/< current user >/AppData/Local/Temp
          #basedir:
server:
  port: 8888
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8700/eureka
    The client updates the service information from Eureka service every 30 seconds
    registry-fetch-interval-seconds: 30
    I need to register my service with Eureka
    register-with-eureka: true
    # Need a retrieval service
    fetch-registry: true
  Heartbeat detection detection and renewal time
  instance:
    # tell the server that if I do not send you a heartbeat within 10 seconds, it means THAT I am faulty. Delete me
    #Eureka Specifies the maximum time the server must wait after receiving the last heartbeat, in seconds.
    lease-expiration-duration-in-seconds: 10
    Send a heartbeat to the server every 2 seconds to prove that the server is still alive. Default is 30 seconds
    #Eureka Interval in seconds for the client to send the heartbeat to the server (the client tells the server it will follow this rule)
    lease-renewal-interval-in-seconds: 2
    So that what you see in the registry list is rendered as IP + port
    prefer-ip-address: true
    # instance name last render address: IP :2002
    instance-id: ${spring.cloud.client.ip-address}:${server.port}Copy the code

1-4. Add annotations to the startup class

@EnableConfigServer
@EnableEurekaClientCopy the code

The server is set up in the configuration center

2. Modify zuul service module

2-1. Add configuration center client dependencies

​<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-client</artifactId>
</dependency>Copy the code

Yml file to application-bak.yml(for application-. yml file) and configure bootstrap.yml file

server:
  port: 9999
spring:
  application:
    name: springcloud-zuul
  cloud:
    config:
      #uri indicates the address of the configuration center
      #uri: http://localhost:8888
      {application} fetch spring.cloud.config.name {application} fetch spring.cloud.config.name
      #spring.application. Name; otherwise, get the value of spring.cloud.config.name.
      #1), when there is no spring.cloud.config.name, the client obtains the git library file corresponding to spring.application
      Get a file,
      #2) When a project needs to fetch multiple files, use the spring.cloud.config.name attribute, separated by commas
      name: configzuul
      profile: dev
      #label corresponds to the label section
      label: master
# username:
# password:
      discovery:
        # indicates that access to config-server by service name is enabled
        enabled: true
        # indicates the service name of config-server
        service-id: springcloud-zuul-config-server
      # Fail fast response
      fail-fast: true
      retry:
        Set the number of retries. Default is 6
        max-attempts: 6
        Initial retry interval, default: 1000ms
        initial-interval: 1000
        # Interval multiplier, default 1.1Multiplier: 1.1# Maximum interval, default 2000ms
        max-interval: 2000
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8700/eureka
    The client updates the service information from Eureka service every 30 seconds
    registry-fetch-interval-seconds: 30
    I need to register my service with Eureka
    register-with-eureka: true
    # Need a retrieval service
    fetch-registry: true
  Heartbeat detection detection and renewal time
  instance:
    # tell the server that if I do not send you a heartbeat within 10 seconds, it means THAT I am faulty. Delete me
    #Eureka Specifies the maximum time the server must wait after receiving the last heartbeat, in seconds.
    lease-expiration-duration-in-seconds: 10
    Send a heartbeat to the server every 2 seconds to prove that the server is still alive. Default is 30 seconds
    #Eureka Interval in seconds for the client to send the heartbeat to the server (the client tells the server it will follow this rule)
    lease-renewal-interval-in-seconds: 2
    So that what you see in the registry list is rendered as IP + port
    prefer-ip-address: true
    # instance name last render address: IP :2002
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
management:
  endpoints:
    web:
      exposure:
        include: ["info"."health"."refresh"]Copy the code

2-3. Configure the refresh class

@Configuration
public class Config {
​
    @RefreshScope
    @ConfigurationProperties("zuul")
    public ZuulProperties zuulProperties() {
        returnnew ZuulProperties(); }}Copy the code

Add configZuul-dev. Yml file to repository

4. Start related services

Eureka Service (Spring Cloud-Eureka-Server), Zuul’s configuration center service (Springcloud-Zuul-config-server), provider service (Springcloud-service-provider), consumer service (Springcloud-service-consumer), zuul Service (springcloud – zuul)

Access to customer service: http://localhost:9999/api-a/consumer/hello? userToken=””

Access configuration center server: http://localhost:8888/configzuul-dev.yml, view the configuration result is shown in figure:

Modify the warehouse config – center configzuul – dev. Yml configured to API – c then warehouse configuration results in the center of the access to the configuration, http://localhost:8888/configzuul-dev.yml, pay attention to the API – a key not to modify

Then send a post request zuul refresh endpoints configured refresh http://localhost:9999/actuator/refresh

Then you will find at http://localhost:9999/api-a/consumer/hello? UserToken = ‘ ‘path access impassability, visit http://localhost:9999/api-c/consumer/hello? UserToken = “As shown in the figure, the page is displayed as

Zuul dynamic refresh to complete here, dynamic refresh is to use the function of the center of the configuration here, don’t understand you can refer to the Spring Cloud the tenth | distributed configuration center Config”

Detailed reference case source: gitee.com/coding-farm…