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();
}