gateway nacos sentinel

introduce

Enterprise level microservice architecture( Source address )Gateway is one of the most important components

spring cloud gateway responsive gateway, dynamic gateway based on nacos, dynamic current limiting based on sentinel, data persistence based on nacos

Software architecture

Version No.: the version no. of gateway, nacos and sentinel refers to the parent project occo-parent

Installation tutorial

  1. Start the registration center and configuration center Nacos document address: Nacos documentation Download address: Nacos Download

  2. Start the current limiting service Sentinel document address: Sentinel documentation Download address: Sentinel Download

  3. Start gateway

  • Download occo gateway startup project
  • Start gateway
  • Create routing configuration in nacos:
Data ID: gateway_router
Group: default Ou group (default)
N ":" / SSO / * "}," name ":" path "}]," filters ": [{" name ":" stripprefix ", "Args": "{" [genkey]} ":" 1 "}]}] (JSON format)
Configuration field description:       
       ① id: the name of the route;
       ② uri: the address of the route. lb indicates the service going there. KB user center is the service name of the nacos registry;
       ③ order: 0, which is directly configured as 0. If 1 is the requested url, the service name will be brought;
       ④  predicates: 
            After route matching: match the request after the specified time: name=After, ﹐ genkey ﹐ 0 = 2020-01-20t17:42:47.789-07:00 [America / Denver]
            Before route matching: match the request before the specified time: name=Before, genkey_ = 2020-01-20t17:42:47.789-07:00 [America / Denver] 
            Between route matching: match the request in the specified time interval: name=Before, ﹐ genkey﹐ 0 = time one, time two (PS: two time comma separated)
            Cookie route matching: matching the value of the specified cookie matching request: name=Cookie, ﹐ genkey﹐ 0 = chocolate, ch.p (PS: matching the request whose cookie name is chocolate and whose value is ch.p)
            Header routing matching: matching the value of the specified header matching request: name=Header, ﹣ genkey ﹣ 0 = X-Request-Id, \ d + (PS: matching the value of header information X-Request-Id matching the regular expression of \ d +)
            Host route matching: the expression set for host matching: name=Host, ﹐ genkey ﹐ 0 = * *. Fuse.org 
            Method route matching: matching HttpMethod method request: name=Method, ﹐ genkey ﹐ 0 = get
            Path route matching: request for path matching setting expression: name=Path, 65104; genkey ﹐ 0 = / foo/{segment} (PS: request path matching path matching expression / foo/{segment})
            Path route matching: request for path matching set value: name=Path, 65104; genkey﹐ 0 = / foo / * * (PS: request path matching starts with / foo)
            Query route matching: requests whose parameters match the settings or expressions: name=Query, ﹣ genkey ﹣ 0 = baz (PS: request parameters include baz parameters)

4. Publish the gateway router configuration. Each time you restart the gateway, you need to republish the configuration to get the routing configuration from the gateway.
5. The configuration of "current limiting" in nacos is as follows:
Data ID: gateway-sentinel
Group: default Ou group (default)
Configuration content: [{"resource": "user server", "controlbehavior": 0, "count": 2, "grade": 1, "limitapp": "default", "strategy": 0}] (JSON format)
Configuration Description:

  • Resource: resource name, which is the object of the current restriction rule
  • limitApp: the call source of the flow control. If it is default, the call source will not be distinguished
  • grade: flow restriction threshold type (QPS or number of concurrent threads); 0 means flow restriction based on the number of concurrent threads; 1 means flow control based on QPS
  • count: current limiting threshold
  • Strategy: call relationship current limiting strategy
  • Control behavior: flow control effect (direct rejection, Warm Up, uniform queuing)
  • clusterMode: cluster mode or not

Integration notes

1. GateWay supports cross domain

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;

@Configuration
public class GatewayConfig {
	
	/**
	 * -Cross domain support configuration
	 */
	@Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
	
	/**
	 * -Remote address key resolver
	 */
	@Bean(value = "remoteAddrKeyResolver")
	public KeyResolver remoteAddrKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
	}
}

2. Gateway integrates Nacos

I. Jar needed for integration

   <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>

		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>

II. Gateway obtains the weight of Nacos, and adds the following configuration in the configuration

    @Bean
	@Scope(value = "prototype")
	public IRule loadBalanceRule() {
		return new NacosRule();
	}

III. dynamically obtain the routing configuration of gateway router in nacos

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

@Component
public class NacosDynamicRouteService implements ApplicationEventPublisherAware {

    private static String DATAID = "gateway_router";

    private static String GROUP = "DEFAULT_GROUP";

    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    private static final List<String> ROUTE_LIST = new ArrayList<>();

    @PostConstruct
    public void dynamicRouteByNacosListener() {
        try {
            ConfigService configService = NacosFactory.createConfigService(serverAddr);
            configService.getConfig(DATAID, GROUP, 5000);
            configService.addListener(DATAID, GROUP, new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    clearRoute();
                    try {
                    	System.err.println(configInfo);
                        List<RouteDefinition> gatewayRouteDefinitions = JSONObject.parseArray(configInfo, RouteDefinition.class);
                        for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
                            addRoute(routeDefinition);
                        }
                        publish();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    private void clearRoute() {
        for(String id : ROUTE_LIST) {
            this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        }
        ROUTE_LIST.clear();
    }

    private void addRoute(RouteDefinition definition) {
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            ROUTE_LIST.add(definition.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void publish() {
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}

3. Gateway integration sentinel

I. jar needed

        <dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.csp</groupId>
			<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
		</dependency>

II. Inject the corresponding SentinelGatewayFilter instance and SentinelGatewayBlockExceptionHandler instance

@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}

III. official guidance address (anything is still official)

https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81

4. Sentinel based on Nacos persistence

I. add jar

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

II. Add configuration

import java.util.List;
import java.util.Properties;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.api.PropertyKeyConst;

/**
 * sentinel Data persistence to nacos
 * @see https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95
 * @author kinbug
 */
@Component
public class SentinelDataSourceNacos {
	
	// nacos server addr
	@Value("${spring.cloud.nacos.config.server-addr}")
	private String serverAddr;

	// nacos group
	private static final String groupId = "DEFAULT_GROUP";
	// nacos dataId
	private static final String dataId = "gateway-sentinel";

	// if change to true, should be config NACOS_NAMESPACE_ID
	private static boolean isDemoNamespace = false;
	// fill your namespace id,if you want to use namespace. for example:
	// 0f5c7314-4983-4022-ad5a-347de1d1057d,you can get it on nacos's console
	private static final String NACOS_NAMESPACE_ID = "${namespace}";

	@PostConstruct
	public void initRules() {
		if (isDemoNamespace) {
			loadMyNamespaceRules();
		} else {
			loadRules();
		}
	}

	private void loadRules() {
		ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(serverAddr, groupId,
				dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
				}));
		FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
	}

	private void loadMyNamespaceRules() {
		Properties properties = new Properties();
		properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
		properties.put(PropertyKeyConst.NAMESPACE, NACOS_NAMESPACE_ID);

		ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(properties, groupId,
				dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
				}));
		FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
	}

}

III. official guidance

https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95

Tags: Programming Spring JSON Java github

Posted on Thu, 30 Apr 2020 02:28:52 -0700 by westonlea7