1. Unified call entry
Zuul API gateway provides a unified external access interface for microservice applications. Zuul also provides a filter to provide unified request verification for all micro services.
1.1 new SP11 zuul project
1.2 add dependency
1.2.1 pom.xml
- Need to add SP01 commons dependency
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.tedu</groupId>
<artifactId>sp11-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sp11-zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>sp01-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.3 modification application.yml file
- Zuul routing configuration can be omitted, and the service ID is used as the access path by default
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
routes:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
1.4 main program addition@EnableZuulProxy
annotation
package cn.tedu.sp11;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class Sp11ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(Sp11ZuulApplication.class, args);
}
}
1.5 start up project
- http://eureka1:2001
- http://localhost:3001/item-service/35
- `http://localhost:3001/i
- tem-service/decreaseNumber`
Using postman, post sends data in the following formats:[{"id":1, "name":"abc", "number":23},{"id":2, "name":"def", "number":11}]
- http://localhost:3001/user-service/7
- http://localhost:3001/user-service/7/score?score=100
- http://localhost:3001/order-service/123abc
- http://localhost:3001/order-service/
2. Unified authority verification
The gateway adds a permission judgment code. The background service does not need to judge the permission any more. It only focuses on the business. Zuul can provide a filter, inherit the filter, and add permission judgment in the subclass
2.1 define filter, inherit zuulfilter and add @ Component annotation
New filter class in SP11 zuul project
package com.tedu.sp11.filter;
import cn.tedu.web.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class AccessFilter extends ZuulFilter {
//Filter types: pre, post, routing, error
@Override
public String filterType() {
//Return "pre"; // prefilter
return FilterConstants.PRE_TYPE;
}
//Position of filter insertion
@Override
public int filterOrder() {
Return 6; // put it in the sixth position
}
//Judge the user request and execute the filtering code
@Override
public boolean shouldFilter() {
//Only the item service call is filtered. If user service and order service are called, the filtering code is not executed
//Gets the ID of the calling service
RequestContext context=RequestContext.getCurrentContext();
String serviceId= (String) context.get(FilterConstants.SERVICE_ID_KEY);
return "item-service".equalsIgnoreCase(serviceId);
}
//Filter code
@Override
public Object run() throws ZuulException {
//Get the request object
RequestContext context=RequestContext.getCurrentContext();
HttpServletRequest request=context.getRequest();
//Token parameter received
String token=request.getParameter("token");
//If not, block access and return the response directly to the client
if (StringUtils.isBlank(token)){
//Prevent further access
context.setSendZuulResponse(false);
//Return the response jsonresult to the client{ code:401 , msg:not ,login, data:null } String json= JsonResult.err ().code( JsonResult.NOT_ LOGIN).msg("not login").toString();
context.addZuulResponseHeader("Content-Type","application/json;charset=UTF-8" );
context.setResponseBody(json);
}
Return null; // the return value has no effect
}
}
2.2 access test
- Access is not allowed without token parameter
http://localhost:3001/item-service/35 - There are token parameters to access
http://localhost:3001/item-service/35?token=1234
3. Zuul integrated ribbon
3.1 zuul + ribbon load balancing
Zuul has integrated ribbon, and load balancing has been realized by default
3.2 zuul + ribbon retrying
3.2.1 pom.xml Add spring retry dependency
- Spring retry dependency required
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
3.2.2 configure zuul to start retrying, and configure ribbon retrying parameters
- It needs to be turned on and tried again. It is not turned on by default zuul:retryable : true
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
retryable: true
# routes:
# item-service: /item-service/**
# user-service: /user-service/**
# order-service: /order-service/**
ribbon:
ConnectTimeout: 1000
ReadTimeout: 1000
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
4. Zuul integrates hystrix
0 configuration, hystrix has been enabled
4.1 zuul + hystrix
4.1.1 create degraded class
- Getroute() method specifies the service ID to apply this degraded class. Asterisk or null value can be used to configure all services
ItemServiceFallback
package com.tedu.sp11.fallback;
import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@Component
public class ItemFB implements FallbackProvider {
//Returns a service ID to demote the specified service
//Return "*" or null, and apply the degraded class to all services
@Override
public String getRoute() {
return "item-service";
}
//Demote the response and return a response object that encapsulates the response data
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
//JsonResult{ code:401 , MSG: failed to call commodity, data:null }
String json = JsonResult.err (). MSG ("call commodity failed"). Tostring();
return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
//content-Type:application/json;charset=UTF-8
HttpHeaders headers = new HttpHeaders();
headers.add("content-Type", "application/json;charset=UTF-8");
return headers;
}
};
}
}
OrderServiceFallback
package com.tedu.sp11.fallback;
import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@Component
public class OrderFB implements FallbackProvider {
//Returns a service ID to demote the specified service
//Return "*" or null, and apply the degraded class to all services
@Override
public String getRoute() {
return "order-service";
}
//Demote the response and return a response object that encapsulates the response data
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
//JsonResult{ code:401 , MSG: failed to call commodity, data:null }
String json = JsonResult.err (). MSG ("call order service failed"). Tostring();
return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
//content-Type:application/json;charset=UTF-8
HttpHeaders headers = new HttpHeaders();
headers.add("content-Type", "application/json;charset=UTF-8");
return headers;
}
};
}
}
4.2 reduce the hystrix timeout to test degradation
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
retryable: true
ribbon:
ConnectTimeout: 1000
ReadTimeout: 2000
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 500
4.3 start the service and test the degradation
http://localhost:3001/item-service/35
5. Zuul + hystrix data monitoring
5.1 exposure hystrix.stream Monitor endpoints
- Zuul already contains the actor dependency
management:
endpoints:
web:
exposure:
include: hystrix.stream
- Start the service and view the exposed monitoring endpoints
http://localhost:3001/actuator
http://localhost:3001/actuator/hystrix.stream
5.2 start monitoring
Start SP08 hystrix dashboard, fill in zuul’s monitoring endpoint path, and start monitoring
http://localhost:4001/hystrix
Fill in monitoring endpoint:
http://localhost:3001/actuator/hystrix.stream
It is necessary to access the background service through zuul gateway to monitor the data
- http://localhost:3001/item-service/35
http://localhost:3001/item-service/decreaseNumber
Using postman, post sends data in the following formats:[{"id":1, "name":"abc", "number":23},{"id":2, "name":"def", "number":11}]
- http://localhost:3001/user-service/7
- http://localhost:3001/user-service/7/score?score=100
- http://localhost:3001/order-service/123abc
- http://localhost:3001/order-service/
6. Zuul + turbo aggregation monitoring
6.1 modify the turbo project to aggregate zuul service instances
spring:
application:
name: turbin
server:
port: 5001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
turbine:
app-config: order-service, zuul
cluster-name-expression: new String("default")
- Using the hystrix dashboard to monitor the turbo monitoring endpoint, which aggregates the monitoring data of order service and Zull gateway service
http://localhost:5001/turbine.stream
6.2 fusing test
ab -n 20000 -c 50 http://localhost:3001/order-service/123abc
7. Zuul cookie filtering
Zuul filters sensitive HTTP protocol headers. By default, it filters the following protocol headers:
- Cookie
- Set-Cookie
- Authorization
You can set zuul not to filter these protocol headers
zuul:
sensitive-headers:
8. The difference between zuul and feign
- Call remote service
- Integrated ribbon
- Integrating hystrix
-
Zuul gateway, as an independent service, is deployed at the front of the system
- Enable retry is not recommended
- If you try again at the front, you will double the access pressure of all servers in the background
-
Feign – call between services within the business micro service system
- Enabling hystrix is not recommended
- It can cause chaos