Spring-Cloud-Gateway负载均衡源码分析-1

Spring-Cloud-Gateway源码系列学习

版本 v2.2.6.RELEASE

LoadBalancerClientFilter源码分析

public class LoadBalancerClientFilter implements GlobalFilter, Ordered {

	/**
	 * Filter order for {@link LoadBalancerClientFilter}.
	 */
	public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;

	private static final Log log = LogFactory.getLog(LoadBalancerClientFilter.class);

	protected final LoadBalancerClient loadBalancer;

	private LoadBalancerProperties properties;

	public LoadBalancerClientFilter(LoadBalancerClient loadBalancer,
			LoadBalancerProperties properties) {
		this.loadBalancer = loadBalancer;
		this.properties = properties;
	}

	@Override
	public int getOrder() {
		return LOAD_BALANCER_CLIENT_FILTER_ORDER;
	}

	/**
	 * @see RouteToRequestUrlFilter#filter(org.springframework.web.server.ServerWebExchange, org.springframework.cloud.gateway.filter.GatewayFilterChain)
	 */
	@Override
	@SuppressWarnings("Duplicates")
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		//拿出目标url
		URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
		//获取协议,如http、lb
		String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
		if (url == null
				|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
			return chain.filter(exchange);
		}
		// preserve the original url
		//把原始的目标url保存到exchange上下文,如lb://user-service
		addOriginalRequestUrl(exchange, url);

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

		//通过负载均衡器拿到一个服务实例
		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();
		}

		//获取真实的目标请求地址,如http://localhost:1000/user/get?id=1
		URI requestUrl = loadBalancer.reconstructURI(
				new DelegatingServiceInstance(instance, overrideScheme), uri);

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

		//把目标url保存到exchange上下文
		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
		//下一个filter
		return chain.filter(exchange);
	}

	/**
	 * 通过负载均衡器拿到一个实例,示例数据:exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR) = lb://user-service/user/get?id=1
	 * @see GatewayLoadBalancerClientAutoConfiguration
	 * @see RibbonLoadBalancerClient
	 * @see RibbonNacosAutoConfiguration
	 */
	protected ServiceInstance choose(ServerWebExchange exchange) {
		return loadBalancer.choose(
				((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost()); //示例数据:getHost拿到的是user-service
	}

}

Spring-Cloud负载均衡设计

从上面LoadBalancerClientFilter的源码分析中我们可以看到,负载均衡核心代码是LoadBalancerClient#choose,而LoadBalancerClient是Spring-Cloud定义的负载均衡客户端,继承了ServiceInstanceChooser接口

public interface LoadBalancerClient extends ServiceInstanceChooser {

	//request相当于一个Function,需要自己实现,参数是一个负载均衡得到的ServiceInstance
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

	//指定serviceId和serviceInstance
	<T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException;

	//根据ServiceInstance和原始URI(如:http://user-service)得到真实的uri(http://192.168.1.91:8181)
	URI reconstructURI(ServiceInstance instance, URI original);

}
public interface ServiceInstanceChooser {

	//根据serviceId 经过一定的负载均衡算法,获得一个ServiceInstance
	ServiceInstance choose(String serviceId);

}

LoadBalancerClient目前唯一实现类RibbonLoadBalancerClient#choose分析

Spring-Cloud目前负载均衡好像就只有Ribbon一个组件

public class RibbonLoadBalancerClient implements LoadBalancerClient {

	private SpringClientFactory clientFactory;

    //SpringClientFactory可以生产ILoadBalancer
	public RibbonLoadBalancerClient(SpringClientFactory clientFactory) {
		this.clientFactory = clientFactory;
	}

    //通过服务id获取一个服务实例
	@Override
	public ServiceInstance choose(String serviceId) {
		return choose(serviceId, null);
	}

	//通过服务id获取一个服务实例
	public ServiceInstance choose(String serviceId, Object hint) {
        //核心代码,getLoadBalancer创建一个ILoadBalancer
        //委托ILoadBalancer去负载均衡获取一个Ribbon的Server
		Server server = getServer(getLoadBalancer(serviceId), hint);
		if (server == null) {
			return null;
		}
        //组装返回一个RibbonServer,RibbonServer属于ServiceInstance子类
		return new RibbonServer(serviceId, server, isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));
	}

	// Note: This method could be removed?
	protected Server getServer(String serviceId) {
		return getServer(getLoadBalancer(serviceId), null);
	}

	protected Server getServer(ILoadBalancer loadBalancer) {
		return getServer(loadBalancer, null);
	}

	protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
		if (loadBalancer == null) {
			return null;
		}
		//核心代码,委托ILoadBalancer去负载均衡获取一个Ribbon的Server
		return loadBalancer.chooseServer(hint != null ? hint : "default");
	}

    //通过clientFactory生产一个ILoadBalancer
	protected ILoadBalancer getLoadBalancer(String serviceId) {
		return this.clientFactory.getLoadBalancer(serviceId);
	}

}

ILoadBalancer及其子类体系

在这里插入图片描述

ILoadBalancer源码分析
public interface ILoadBalancer {

	//向负载均衡器中维护的实例列表增加服务实例
	public void addServers(List<Server> newServers);
	
	//通过某种策略,从负载均衡器中挑选出一个具体的服务实例
	public Server chooseServer(Object key);
	
	//用来通知和标识负载均衡器中某个具体实例已经停止服务,不然负载均衡器在下一次获取服务实例清单前都会认为服务实例均是正常服务的
	public void markServerDown(Server server);
	
	//根据参数判断返回可正常服务的实例列表还是全部服务实例列表
	@Deprecated
	public List<Server> getServerList(boolean availableOnly);

	//返回当前可正常服务的实例列表
    public List<Server> getReachableServers();

    //返回所有已知的服务实例列表,包括正常服务和停止服务的实例
	public List<Server> getAllServers();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值