Microservice Gateway Gateway Practice Summary

2022.09.05
Microservice Gateway Gateway Practice Summary
As the first layer in the microservice architecture system to receive requests, the Gateway gateway can define many strategies to protect the security of the system, such as current limiting of high-concurrency interfaces, third-party authorization verification, IP interception when maliciously attacked, etc. Try to intercept illegal requests in the gateway to ensure the security and stability of the system.

1. Introduction to Gateway

In the microservice architecture, the gateway service usually provides dynamic routing, as well as core capabilities such as flow control and request identification. In the previous chapters, I mentioned the use process of the Zuul component, but the current Gateway component is a more conventional choice, and the following will focus on the Gateway detailed analysis of the practice;

picture

From the perspective of the architectural model, no matter what technical components the gateway adopts, it provides a layer of interception and verification capabilities between the client and the business service. However, compared with Zuul, the Gateway provides more powerful functions and excellent performance. ;

Based on practical scenarios, functionally, the gateway focuses more on the requester's legal verification, traffic control, and IP-level interception. From an architectural perspective, it is usually necessary to provide flexible routing mechanisms, such as grayscale and load balancing strategies. etc., and based on the message mechanism, system-level security notification, etc.;

picture

The following focuses on the three nodes of the client, the gateway layer, and the facade service, and analyzes the usage details of the Gateway, that is, the client sends a request to the gateway, and the gateway is routed to the facade service for processing;

2. Dynamic Routing

1. Basic Concepts

Routing: As the core capability of the gateway, from the perspective of source code structure, it includes ID, request URI, assertion set, filter set, etc.;

public class RouteDefinition {
 private String id;
 private URI uri;
 private List<PredicateDefinition> predicates = new ArrayList<>();
 private List<FilterDefinition> filters = new ArrayList<>();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

Assertion + filtering: Usually, the matching rules of the request are defined in the assertion, and the processing action of the request is defined in the filtering. In terms of structure, it is a set of names and parameters, and supports shortcut configuration;

public class PredicateDefinition {
 private String name;
 private Map<String, String> args = new LinkedHashMap<>();
}

public class FilterDefinition {
 private String name;
 private Map<String, String> args = new LinkedHashMap<>();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

2. Configure routing

In the way of configuration, add the facade service route, in the way of path matching, if the request path is wrong, the assertion fails, StripPrefix is ​​set to 1, that is, the first /facade parameter is removed from the filter;

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
        - id: facade
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/facade/**
          filters:
            - StripPrefix=1
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

The execution principle is as follows:

picture

Here, the routing policy of the facade service is set in the form of a configuration file, in which the path mode is specified, and a variety of routing samples are provided in the Gateway document, such as: Header, Cookie, Method, Query, Host and other assertion methods;

3. Coding method

Manage routing policies based on coding. The Gateway document also provides a variety of reference examples. If routing services are few and fixed, the configuration method can be solved. If there are many routing services and need to be dynamically added, the library table-based method is more suitable. ;

@Configuration
public class GateConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("facade",r -> r.path("/facade/**").filters(f -> f.stripPrefix(1))
                .uri("http://127.0.0.1:8082")).build();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

4. Library table loading

In conventional applications, it is a common way to read the routing policy from the library table. Define the routing factory class and implement the RouteDefinitionRepository​ interface, involving three core methods of loading, adding, and deleting, and then read from the library based on the service class. The data can be converted into a RouteDefinition object;

picture

@Component
public class DefRouteFactory implements RouteDefinitionRepository {
    @Resource
    private ConfigRouteService routeService ;
    // 加载
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(routeService.getRouteDefinitions());
    }
    // 添加
    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(routeDefinition -> { routeService.saveRouter(routeDefinition);
            return Mono.empty();
        });
    }
    // 删除
    @Override
    public Mono<Void> delete(Mono<String> idMono) {
        return idMono.flatMap(routeId -> { routeService.removeRouter(routeId);
            return Mono.empty();
        });
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • twenty one.
  • twenty two.
  • twenty three.
  • twenty four.

The library table management method is adopted in the source code repository. More details of the code logic can be moved to Git for reference, and will not be pasted too much here;

3. Custom routing strategy

Custom assertion, inheriting the AbstractRoutePredicateFactory​class, note that the name ends with RoutePredicateFactory​, and rewrite the apply method to execute specific matching rules;

@Component
public class DefCheckRoutePredicateFactory extends AbstractRoutePredicateFactory<DefCheckRoutePredicateFactory.Config> {
    public DefCheckRoutePredicateFactory() {
        super(Config.class);
    }
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                log.info("DefCheckRoutePredicateFactory:" + config.getName());
                return StrUtil.equals("butte",config.getName());
            }
        };
    }
    @Data
    public static class Config { private String name; }
    @Override
    public List<String> shortcutFieldOrder() { return Collections.singletonList("name"); }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

Custom filtering, inheriting the AbstractNameValueGatewayFilterFactory​class, note that the name ends with GatewayFilterFactory​, rewrite the apply method, you can execute specific filtering rules;

@Component
public class DefHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(AbstractNameValueGatewayFilterFactory.NameValueConfig config) {
        return (exchange, chain) -> {
            log.info("DefHeaderGatewayFilterFactory:"+ config.getName() + "-" + config.getValue());
            return chain.filter(exchange);
        };
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

Configure the loading method. Here assertion and filtering are the fast configuration methods, so the naming convention should be followed by the Gateway;

spring:
  cloud:
    gateway:
      routes:
        - id: facade
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/facade/**
            - DefCheck=butte
          filters:
            - StripPrefix=1
            - DefHeader=cicada,smile
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

Generally speaking, policy customization for assertion and filtering is required in application-level systems to provide support at the business or architecture level, and to complete more detailed rule verification, especially when multiple versions of the same service are running in parallel, it can be better management routing strategy, so as to avoid the influence between branches;

Fourth, the global filter

The filtering used in routing is GatewayFilter​. In fact, the GlobalFilter global filter is also provided in the Gateway. Although it is very similar in structure, its responsibilities are fundamentally different;

Global Filter 1: Print Request ID

@Component
@Order(1)
public class DefOneGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("request-id:{}",exchange.getRequest().getId()) ;
        return chain.filter(exchange);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

Global Filter 2: Print Request URI

@Component
@Order(2)
public class DefTwoGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("request-uri:{}",exchange.getRequest().getURI()) ;
        return chain.filter(exchange);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

As the first layer in the microservice architecture system to receive requests, the Gateway gateway can define many strategies to protect the security of the system, such as current limiting of high-concurrency interfaces, third-party authorization verification, IP interception when maliciously attacked, etc. Try to intercept illegal requests in the gateway to ensure the security and stability of the system.

5. Reference source code

Application repository: https://gitee.com/cicadasmile/butte-flyer-parent

Component encapsulation: https://gitee.com/cicadasmile/butte-frame-parent