This is the 29th day of my participation in the August Wenwen Challenge.More challenges in August
🌈 Column Introduction
Thank you for reading, I hope to help you, if there is a flaw in the blog, please leave a message in the comment area or add my private chat in the home page, thank you for every little partner generous advice. I am XiaoLin, a boy who can both write bugs and sing rap. This column mainly introduces the most mainstream micro services solution, SpringCloudAlibaba, which will be introduced in groups. Column address: SpringCloudAlibaba
- 6️ Sentinel (suggested collection)
- 5️ retail Feign
- 4️ Ribbon (suggested collection)
- 3️ Nacos (suggested collection)
- 2️ retail (suggested collection)
- 1️ retail (suggested collection)
Ix. Service Gateway: Gateway
9.1 Introduction to gateway
Everyone knows that in microservices architecture, a system is broken up into many microservices. So how do you call so many microservices as a client? If there is no gateway, we can only record the address of each microservice on the client side and call it separately.
There are many problems with such an architecture:
- The client requests different microservices multiple times, adding complexity to client code or configuration authoring.
- Authentication is complex and each service requires independent authentication.
- Cross-domain requests exist and are complicated to process in certain scenarios.
Gateways are designed to solve these problems. The so-called API gateway is the unified entrance of the system, which encapsulates the internal structure of the application program and provides unified services for the client. Some common logic unrelated to the business function can be realized here, such as authentication, authentication, monitoring, routing and forwarding, etc.
9.2 Common gateways
9.2.1, Ngnix + lua
Nginx reverse proxy and load balancing can realize load balancing and high availability of API server.
Lua is a scripting language for writing simple logic, and Nginx supports Lua scripting
9.2.2, Kong
Based on Nginx+Lua development, high performance, stable, there are multiple available plug-ins (current limiting, authentication, etc.) can be used out of the box.
His faults:
- Only Http is supported.
- Secondary development, free expansion is difficult.
- Provide management API, lack of easy to use control, configuration.
9.2.3, Zuul
Netflix open source gateway, rich functions, the use of JAVA development, easy secondary development.
His faults:
- Lack of control, cannot dynamically configure.
- There are many dependent components.
- Processing Http requests relies on the Web container, which is not as powerful as Nginx.
9.2.4、Spring Cloud Gateway
Spring company developed the Gateway service to replace Zuul, but SpringCloud Alibaba technology stack does not provide its own Gateway, so we can use SpringCloud Gateway as the Gateway
9.3 Introduction to Gateway
Spring Cloud Gateway is a Gateway developed by Spring company based on Spring 5.0, Spring Boot 2.0 and Project Reactor technology. It aims to provide a simple and effective unified API route management method for microservice architecture. It aims to replace Netflix Zuul, which not only provides a unified routing mode, but also provides basic gateway functions based on Filter chain, such as security, monitoring and traffic limiting.
Its main functions are:
- The forwarding redirection is performed.
- At the beginning, all classes need to do initialization.
- Perform network isolation.
9.4. Quick Start
Requirements: Access the API gateway through a browser and forward the request to the commodity microservice through the gateway.
9.4.1 basic Edition
Create an API-Gateway module and import the following dependencies.
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Shop-parent</artifactId>
<groupId>cn.linstudy</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<! - gateway gateway - >
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
Copy the code
Writing configuration files
server:
port: 9000 Specify the port for the gateway service
spring:
application:
name: api-gateway
cloud:
gateway:
routes: Routing specifies which microservice to refer to when a request meets any criteria.
- id: product_route The current route must be unique
uri: http://localhost:8081 Request the address to forward to
order: 1 # Priority of the route. The smaller the number, the higher the priority
predicates: # assertion (which is the condition to be satisfied by routing and forwarding)
- Path=/product-serv/** Route forwarding is performed only when the requested Path satisfies the rule specified by Path
filters: The request can be modified as it passes through the filter
- StripPrefix=1 Delete layer 1 path before forwarding
Copy the code
test
9.4.2. Updated version
We found a big problem with the upgrade, that is, the address of the forwarding path is written in the configuration file, we need to get the address in the registry.
Add nacOS dependencies
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Shop-parent</artifactId>
<groupId>cn.linstudy</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<! - gateway gateway - >
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<! -- NacOS client -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
Copy the code
Add annotations to the main class
@SpringBootApplication
@EnableDiscoveryClient
public class GateWayServerApp {
public static void main(String[] args) { SpringApplication.run(GateWayServerApp.class,args); }}Copy the code
Modifying a Configuration File
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0. 01.: 8848
gateway:
discovery:
locator:
enabled: true Enable the Gateway to discover microservices in NACOS
routes:
- id: product_route # The name of the route
uri: lb://product-service # LB refers to getting microservices by name from NACOS and following a load balancing policy
predicates:
- Path=/product-serv/** # 1 forward only if this rule is met
filters:
- StripPrefix=1 Remove the first layer
Copy the code
We can also customize multiple routing rules.
spring:
application:
gateway:
routes:
- id: product_route
uri: lb://product-service
predicates:
- Path=/product-serv/**
filters:
- StripPrefix=1
- id: order_route
uri: lb://order-service
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
Copy the code
9.4.3 abbreviated version
Our configuration file does not need to be as complex as 1 to implement functions, there is a shortened version.
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true Enable the Gateway to discover microservices in NACOS
Copy the code
We found, as long as the gateway address/microservice name/interface format to access, we can get a successful response.
9.5 Gateway core architecture
9.5.1 Basic Concepts
A Route is one of the most basic components of a Gateway. It represents a specific routing information carrier. It mainly defines the following information:
- Id: indicates the Route identifier, which is different from other routes.
- Uri: The destination URI to which the route points, that 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: Predicate is used to determine conditions. A route is executed only when both assertions return true.
- Filter: Modifies the request and response information.
- Predicate: Predicate, used to determine conditions. A route is executed only when both assertions return true.
9.5.2 Implementation Principle
- The request is received by the user, the request handler is handed to the processor mapper, and the chain of execution is returned.
- The request handler invokes the Web handler and processes our path 1 in the Web handler. Hypothesis 1 our path is: http://localhost:9000/product-serv/get? If the id is 1, search for the service information locally based on the configured routing rule. The host IP address of product-service is 192.168.10.130.
- Select a node based on the load balancing policy of 1Ribbon, and then join the node. Replace the path with 192.168.10.130:8081. If filter is configured, the node will also use filter.
- By default Gateway removes the first layer for you if you do not have a custom route. Gateway port from this one
/
Let’s go to number two/
Let’s do the first level.
9.6. Filters
The Gateway’s filter is used to manipulate requests and responses as they pass through.
The lifecycle of the Gateway’s filter:
- 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.
- 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.
The Filter of Gateway can be divided into two types: GatewayFilter and GlobalFilter:
- GatewayFilter: Applies to a single route or a group of routes.
- GlobalFilter: Applies to all routes.
9.6.1 Local filters
A local filter is a filter for a single route. There are built-in filters and custom filters.
9.6.1.1 Built-in filter
There are many different types of Gateway routing filters built into the SpringCloud Gateway.
9.6.1.1.1 Local filter content
Filter plant | role | parameter |
---|---|---|
AddRequestHeader | Add the Header for the original request | Header name and value |
AddRequestParameter | Add request parameters to the original request | Parameter name and value |
AddResponseHeader | Add the Header for the original response | Header name and value |
DedupeResponseHeader | Removes duplicate values from the response header | The name of the Header to be deleted and the deduplication policy |
Hystrix | Introduce Hystrix circuit breaker protection for routes | The name of the HystrixCommand |
FallbackHeaders | Add specific exception information to the request header of the fallbackUri | The name of the Header |
PrefixPath | Prefixes the original request path | The prefix path |
PreserveHostHeader | Add a preserveHostHeader=true attribute to the request, which the routing filter checks to determine whether to send the original Host | There is no |
RequestRateLimiter | It is used to limit the traffic of requests. The traffic limiting algorithm is token bucket | KeyResolver, RateLimiter, StatusCode, DenyEmptyKey, emptyKeyStatus |
RedirectTo | Redirects the original request to the specified URL | HTTP status code and redirected URL |
RemoveHopByHopHeadersFilter | Removes a set of headers specified by the IETF organization for the original request | This is enabled by default, and you can specify which headers to delete only |
RemoveRequestHeader | Delete a Header for the original request | The Header name |
RemoveResponseHeader | Remove a Header for the original response | The Header name |
RewritePath | Override the original request path | The original path regular expression and the rewritten path regular expression |
RewriteResponseHeader | Overrides a Header in the original response | The Header name, the regular expression for the value, and the overridden value |
SaveSession | Enforce the request before forwarding itWebSession::save operation |
There is no |
secureHeaders | Add a series of response headers for security purposes to the original response | None. You can modify the values of the security response headers |
SetPath | Modifies the original request path | Modified path |
SetResponseHeader | Modify the value of a Header in the original response | Header name, modified value |
SetStatus | Modifies the status code of the original response | The HTTP status code can be a number or a string |
StripPrefix | The path used to truncate the original request | Use numbers to indicate the number of paths to truncate |
Retry | Retry for different responses | Retries, Statuses, Methods, series |
RequestSize | Sets the maximum size of a request packet that can be received. If the size of the request packet exceeds the specified value, 413 Payload Too Large is returned | Request packet size, in bytes. The default value is 5M |
ModifyRequestBody | Modify the original request body content before forwarding the request | Modified request body content |
ModifyResponseBody | Modify the contents of the original response body | Modified response body content |
9.6.1.1.2 Use of local filters
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0. 01.: 8848
gateway:
discovery:
locator:
enabled: true Enable the Gateway to discover microservices in NACOS
routes:
- id: product_route # The name of the route
uri: lb://product-service # LB refers to getting microservices by name from NACOS and following a load balancing policy
predicates:
- Path=/product-serv/** # 1 forward only if this rule is met
filters:
- StripPrefix=1 Remove the first layer
- SetStatus=2000 # Use the built-in filter here to modify the return state
Copy the code
9.6.1.2. Customize local filters
Most of the time, the built-in filter does not meet our needs, this time must customize the local filter. Let’s assume that one requirement is to count the order service invocation time.
Write a class that implements the logic
The name is in a fixed format xxxGatewayFilterFactory
@Component
public class TimeGatewayFilterFactory extends AbstractGatewayFilterFactory<TimeGatewayFilterFactory.Config> {
private static final String BEGIN_TIME = "beginTime";
// constructor
public TimeGatewayFilterFactory(a) {
super(TimeGatewayFilterFactory.Config.class);
}
// Assign parameters from the configuration file to the configuration class
@Override
public List<String> shortcutFieldOrder(a) {
return Arrays.asList("show");
}
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if(! config.show){// If the value of show in the configuration class is false, the system permits the configuration
return chain.filter(exchange);
}
exchange.getAttributes().put(BEGIN_TIME, System.currentTimeMillis());
/ * * *, the logic of the pre * chain in the filter (). Then (Mono) fromRunable (() - > {* post logic *})) * /
return chain.filter(exchange).then(Mono.fromRunnable(()->{
Long startTime = exchange.getAttribute(BEGIN_TIME);
if(startTime ! =null) {
System.out.println(exchange.getRequest().getURI() + Request Time: + (System.currentTimeMillis() - startTime) + "ms"); }})); }}; }@Setter
@Getter
static class Config{
private booleanshow; }}Copy the code
Write application. XML
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0. 01.: 8848
gateway:
discovery:
locator:
enabled: true Enable the Gateway to discover microservices in NACOS
routes:
- id: product_route # The name of the route
uri: lb://product-service # LB refers to getting microservices by name from NACOS and following a load balancing policy
predicates:
- Path=/product-serv/** # 1 forward only if this rule is met
filters:
- StripPrefix=1 Remove the first layer
- id: order_route
uri: lb://order-service
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
- Time=true
Copy the code
Access path: http://localhost:9000/order-serv/getById? o=1&pid=1
9.6.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. The SpringCloud Gateway also handles the entire route forwarding internally through a set of built-in global filters.
Authentication logic under development:
- When the client first requests the service, the server authenticates the user’s information (login).
- If the authentication succeeds, the user information is encrypted to form a token and returned to the client as a login certificate.
- After each request, the client carries the authenticated token.
- The server decrypts the token to check whether it is valid.
Let’s simulate a requirement: to implement the unified authentication function, we need to determine whether the request contains token in the gateway and, if not, do not forward the route. If yes, the normal logic will be executed.
Writing global filters
@Component
public class AuthGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (StringUtils.isBlank(token)) {
System.out.println("Authentication failed");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
returnchain.filter(exchange); }}Copy the code
9.6.3. Gateway Traffic limiting
The gateway is the common entrance of all requests, so traffic limiting can be carried out at the gateway, and there are many ways to limit traffic. In this case, the Sentinel component learned in the previous section is used to achieve traffic limiting of the gateway. Sentinel supports traffic limiting for mainstream gateways such as SpringCloud Gateway and Zuul.
Starting from version 1.6.0, Sentinel provides an adaptation module of the SpringCloud Gateway, which can provide flow limiting of two resource dimensions:
- Route dimension: the route entry configured in the Spring configuration file with the corresponding routeId resource name
- Custom API dimensions: Users can customize some API groups using the API provided by Sentinel
9.6.3.1 Gateway integration Sentinel
Add the dependent
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
Copy the code
Write configuration classes for traffic limiting
The essence of configuration classes is to substitute code for NACOS graphical interface limiting.
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider
> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer)
{
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
// Configure the exception handler for limiting traffic
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(a) {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
// Initialize a stream limiting filter
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter(a) {
return new SentinelGatewayFilter();
}
// Add traffic limiting for commodity microservices
@PostConstruct
private void initGatewayRules(a) {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("product_route")
.setCount(3) / / three times
.setIntervalSec(1) // 1 second, which means 1 per second will limit the current if it exceeds 3 times); GatewayRuleManager.loadRules(rules); }}Copy the code
Modify the default return format of stream limiting
If we do not want to return the default error when limiting the flow, we need to customize the error and specify a custom return format. We just need to add a configuration section to the class.
@PostConstruct
public void initBlockHandlers(a) {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Map map = new HashMap<>();
map.put("code".0);
map.put("message"."The interface is restricted.");
returnServerResponse.status(HttpStatus.OK). contentType(MediaType.APPLICATION_JSON). body(BodyInserters.fromValue(map)); }}; GatewayCallbackManager.setBlockHandler(blockRequestHandler); }Copy the code
test
9.6.3.2. Customize API grouping
We can see that the above definition, limiting the flow of the entire service, is not fine-grained. Custom API grouping is a more fine-grained definition of traffic limiting rules that can implement fine-grained traffic limiting for a method.
Add ApiController in the shop-order-server project
@RestController
@RequestMapping("/api")
public class ApiController {
@RequestMapping("/hello")
public String api1(a){
return "api"; }}Copy the code
Add the configuration in GatewayConfiguration
@PostConstruct
private void initCustomizedApis(a) {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("order_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/order-serv/api/**"). setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
@PostConstruct
private void initGatewayRules(a) {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("product_route")
.setCount(3)
.setIntervalSec(1)); rules.add(new GatewayFlowRule("order_api").
setCount(1).
setIntervalSec(1));
GatewayRuleManager.loadRules(rules);
}
Copy the code
test
Current limiting, direct access to the http://localhost:8082/api/hello would not have happened to http://localhost:9000/order-serv/api/hello will appear the current limit.