This is the 23rd day of my participation in the Gwen Challenge.

An overview,

Zuul is a back door for all requests from devices and networks to back-end applications, providing configurable external URL-to-service mapping for internal services, and a jVM-based back-end router. It has the following functions:

  • Authentication and Authorization
  • Pressure test
  • Canary test
  • Dynamic routing
  • Load reduction
  • Static corresponding processing
  • Active Traffic management

The bottom layer is servlet-based, which is essentially a chain of responsibilities formed by a series of filters

Ii. Introduction cases

2.1 Creating a parent POM Project

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.3. RELEASE</version>
        <relativePath/> <! -- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.cloud-version>Hoxton.SR3</spring.cloud-version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <! -- springboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <! -- Use undertow without Tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
            <groupId>io.undertow</groupId>
            <artifactId>undertow-servlet</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
Copy the code

2.2 Creating the Eureka Server

 	<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
Copy the code

Start the class

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

The configuration file

server:
  port: 8671
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Copy the code

2.3 Creating Zuul Server

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

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
Copy the code

Create the startup class with the @enableZuulProxy annotation to start Zuul

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ZuulServerApplication {

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

The configuration file

spring:
  application:
    name: zuul-server
server:
  port: 88
eureka:
  client:
    serviceUrl:
      defaultZone: http:/ / ${eureka. Host: 127.0.0.1} : ${eureka. Port: 8671} / eureka
  instance:
    prefer-ip-address: true
zuul:
  routes:
    service-a:
      path: /client/** serviceId: client-aCopy the code

2.4 Creating a Common Service

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

Start the class

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceAApplication {

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

controller

@RestController
public class TestController {

	@GetMapping("/add")
	public Integer add(Integer a, Integer b){
		returna + b; }}Copy the code

The configuration file

server:
  port: 8080
spring:
  application:
    name: service-a
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka. Host: 127.0.0.1} : ${eureka. Port: 8671} / eureka
  instance:
    prefer-ip-address: true
Copy the code

Run Eureka Server, Zuul Server, and Service A

Visit separately:

http://localhost:8080/add?a=1&b=2

http://localhost:88/client/add?a=1&b=2

The same result is returned by the controller of service-a, port 8080 is service-A, port 88 is Zuul Server. Zuul successfully forwarded the request to service-a.

Typical configuration of Zuul

3.1 Route Configuration

1. Simplify and rule routing configuration

(1) Single-instance serviceId mapping, as shown below, is a mapping rule from /client/** to service client-a. There’s also a simplified way of writing it

zuul:
  routes:
    service-a:
      path: /client/**
      serviceId: client-a
Copy the code

Simplified writing:

zuul:
  routes:
    client-a: /client/** 
Copy the code

A more simplified way of writing:

zuul:
  routes:
    client-a:
Copy the code

Is equivalent to:

zuul:
  routes:
    service-a:
      path: /client-a/**
      serviceId: client-a
Copy the code

(2) Single instance URL mapping

You can route to physical addresses as well as services. Replace the serviceId with a URL

zuul:
  routes:
    service-a:
      path: /client-a/**
      url: http://localhost:8080 # address of client-a
Copy the code

(3) Multi-instance routing

By default, Zuul uses the Ribbon baseload balancing function integrated with Eureka. If you want to use the Ribbon load balancing function, you need to specify a serviceId. This operation disables the Ribbon from using Eureka. The following is a load balancing policy that uses the Ribbon without Eureka. If you use Eureka as the registry, you don’t need the following configuration because Eureka already integrates the Ribbon’s polling load balancing policy by default.

# # # # # # # # # # # # # # # # # # # # # # # # # # from eureka let zuul ribbon to realize routing load balanced with # # # # # # # # # # # # # # # # # # # # # # # # # #

zuul:
  routes:
    ribbon-route:
      path: /ribbon/**
      serviceId: ribbon-route

ribbon:
  eureka:
    enabled: false  # Ban Ribbon from using Eureka

ribbon-route:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule     #Ribbon LB Strategy
    listOfServers: localhost:7070,localhost:7071     #client services for Ribbon LB
Copy the code

(4) Forward Indicates the local forward

Sometimes we do some logic in Zuul and write an interface in the gateway

@RestController
public class TestController {

	@GetMapping("/forward")
	public Integer add(Integer a, Integer b){
		return "Jump"+a + b; }}Copy the code

Jump to this method when accessing the /client interface, so local jump needs to be configured in Zuul

zuul:
  routes:
    service-a:
      path: /client-a/**
      serviceId: forward:/forward
Copy the code

(5) Loading rules of the same path

There is a special case where multiple Serviceids are specified for a mapping path, which service should it load

zuul:
  routes:
    service-a:
      path: /client/**
      serviceId: client-a
    service-b: 
      path: /client/**
      serviceId: client-b
Copy the code

In the configuration above, it will always route to the next service, which is client-B. When the YML parser works, if the same mapping path corresponds to multiple services, the mapping rule loaded at the end overwrites the previous mapping rule according to the loading order.

2. Route wildcard

The rules explain The sample
/ * * Matches any number of paths and characters /order/add, /order/query, /order/detail/1
/ * Matches any number of characters / order/add, / order/query
/? Matching a single character /order/a, /order/b, /order/c

3.2 Function Configuration

1. Route prefix

When configuring routing rules, you can configure a unified proxy prefix.

zuul:
  prefix: /api Use API to specify prefixes
  routes:
    client-a:
      path: /client/**
      serviceId: client-a 
Copy the code

For example, to access the interface of the client-a service, prefix/API with/API /client/add. This feature can also be turned off with stripPrefix=false. So that when requesting the interface of the client-a service, the/API is not required

zuul:
  prefix: /api Use API to specify prefixes
  routes:
    client-a:
      path: /client/**
      serviceId: client-a 
      stripPrefix: false
Copy the code

2. Service and path filtering

Sometimes you can shield certain services or paths from intrusion. With ignore-service and ignore-Patterns, Zuul ignores client-b services and /**/div/** interfaces when it pulls down the list of services and creates mapping rules.

zuul:
  ignored-service: client-b   # Ignore services to prevent service intrusion
  ignored-patterns: /**/div/** Ignore the interface, mask the interface
  routes:
    client-a:
      path: /client/**
      serviceId: client-a
Copy the code

3. Sensitive headers

When building the system, it is convenient to use HTTP headers to pass values. Some authentication information of the protocol, such as token and cookies, is also contained in the headers by default. Zuul’s configuration allows you to specify a sensitive header that cuts off its interaction with the underlying service.

zuul:
  routes:
    client-a:
      path: /client/**
      serviceId: client-a
      sensitiveHeaders: Cookie,Set-Cookie,Authorization
Copy the code

4. Redirection problems

When accessing the authentication service through the gateway, the authentication service returns a redirection address, and the host redirects to the address of the authentication service, which will cause the address of the authentication service to be exposed, which is obviously not what we want. Anything that needs to be set up for redirection can be done in the configuration file.

zuul:
  add-host-header: true
  routes:
    client-a:
      path: /client/**
      serviceId: client-a
Copy the code

5. Retry mechanism

In a production environment, a request may fail by accident for a variety of reasons, and a retry mechanism is needed when the user experience cannot be triggered by a conscious operation. The retry function should be enabled in the configuration, and should be used sparingly. Some interfaces should be idempotent.

zuul:
  retryable: true
 ribbon:
   MaxAutoRetries: 1 Number of retries for the same service (excluding the first)
   MaxAutoRetriesNextServer: 1 # Switch the same number of services
Copy the code