gateway使用及负载均衡原理

时间:2021-04-12 22:44:13   收藏:0   阅读:40

引入

pom.xml文件添加依赖,如果引入了gateway的依赖,但是不想使用,可以在application.yml文件中设置spring.cloud.gateway.enabled=false

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

Gateway组成

Geyeway工作原理

  1. 客户端发送请求到Gateway
  2. Gateway Handler Mapping判断请求是否匹配某个路由
  3. 发送请求到Gateway Web Handler,执行该请求的过滤器。过滤器可以在请求之前和之后执行不同逻辑。
  4. 当所有的预(pre)过滤请求执行完后,创建代理请求,创建好了代理请求后,才执行post请求

核心GlobalFilter

ForwardRoutingFilter

Order: Integer.MAX_VALUE
请求转发过滤器。
从exchange对象中获取gatewayRequestUrl,如果这个url中有forward的scheme,则使用Spring的DispatcherHandler 进行请求转发。

LoadBalancerClientFilter

Order: 10100
负载均衡过滤器。(核心)
从exchange对象中获取gatewayRequestUrl、gatewaySchemePrefix,如果url为空或者url的schema不是lb并且gatewaySchemePrefix前缀不是lb,则进入下个过滤器;否则去获取真正的url。
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    	// 拿到请求url
		URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
    	// 拿到匹配的路由中url的前缀
		String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
    	// 如果url为null或者url的schema不是lb并且请求Route中配置的url不是lb,进入下个过滤器
		if (url == null
				|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
			return chain.filter(exchange);
		}
		// 保留原始的Url,就是将原始的url放入exchange对象的gatewayOriginalRequestUrl参数值中
		addOriginalRequestUrl(exchange, url);
    	// 获取真正的请求url并组装成ServiceInstance对象
		final ServiceInstance instance = choose(exchange);

		if (instance == null) {
			throw NotFoundException.create(properties.isUse404(),
					"Unable to find instance for " + url.getHost());
		}

		URI uri = exchange.getRequest().getURI();

		// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
		// if the loadbalancer doesn‘t provide one.
		String overrideScheme = instance.isSecure() ? "https" : "http";
		if (schemePrefix != null) {
			overrideScheme = url.getScheme();
		}

		URI requestUrl = loadBalancer.reconstructURI(
				new DelegatingServiceInstance(instance, overrideScheme), uri);

		if (log.isTraceEnabled()) {
			log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
		}

		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
		return chain.filter(exchange);
	}

服务来源

首先看一个接口ServerListUpdater自己核心方法

有个内部接口UpdayeAction,真正执行服务列表更新的接口。

public interface ServerListUpdater {

    /**
     * an interface for the updateAction that actually executes a server list update
     */
    public interface UpdateAction {
        void doUpdate();
    }


    /**
     * start the serverList updater with the given update action
     * This call should be idempotent.
     *
     * @param updateAction
     */
    void start(UpdateAction updateAction);
}

再看看ServerListUpdater接口的实现类PollingServerListUpdater,只贴核心方法start()。

参数为UpdateAction 对象,定义了一个线程类,线程里调用updateAction.doUpdate()方法。

启动一个定时任务线程池,默认每隔30S执行一次,也就是说每隔30从注册中心获取一次最新的服务列表。

public class PollingServerListUpdater implements ServerListUpdater {
    @Override
    public synchronized void start(final UpdateAction updateAction) {
        if (isActive.compareAndSet(false, true)) {
            final Runnable wrapperRunnable = new Runnable() {
                @Override
                public void run() {
                    if (!isActive.get()) {
                        if (scheduledFuture != null) {
                            scheduledFuture.cancel(true);
                        }
                        return;
                    }
                    try {
                        updateAction.doUpdate();
                        lastUpdated = System.currentTimeMillis();
                    } catch (Exception e) {
                        logger.warn("Failed one update cycle", e);
                    }
                }
            };

            scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
                    wrapperRunnable,
                    initialDelayMs,
                    refreshIntervalMs,
                    TimeUnit.MILLISECONDS
            );
        } else {
            logger.info("Already active, no-op");
        }
    }
}

NettyWriteResponseFilter

Order:-1
在其它过滤器执行完后执行,并将服务端响应的结果写回客户端,如果需要重新处理响应结果,则新的过滤器必须在此过滤器之后执行,也就是order比-1小。

GatewayMetricsFilter

Order:0
gateway性能监控核心过滤器,用于采集请求数据,主要包含
routeId: 路由id
routeUri: 路由的url
outcome: 
status: 请求状态
httpStatusCode: 响应状态码
httpMethod: 请求方法

用户自定义过滤器

全局过滤器

实现GlobalFilter, Ordered,并重写getOrder()和filter()方法

public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

Route过滤器

Route过滤器命名必须以GatewayFilterFactory结尾,并且在application.yml文件中只需配置前缀

public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

    public PreGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(builder.build()).build());
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

原文:https://www.cnblogs.com/ns-study/p/14649392.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!