依然 是 依赖于 Spring-Ioc 和自动配置的方式,实现 客户端负载均衡器的初始化配置. 由于 代码量多,层次关联复杂.因此选择从核心类开始阅读
N : Netflix 的设计的类结构
SN : Spring 集成 Netflix 设计的类结构
S: Spring 设计的类结构
S- LoadBalancerClient :负载均衡器
public interface LoadBalancerClient {
// 根据 serviceId 获取 ServiceInstance
ServiceInstance choose(String serviceId);
// 执行LoadBalancerRequest
T execute(String serviceId, LoadBalancerRequest request) throws IOException;
// 根据ServiceInstance,原始 URI,拼接出 目标URI
URI reconstructURI(ServiceInstance instance, URI original);
}
SN- RibbonLoadBalancerClient : 基于 Ribbon实现的LoadBalancerClient
@Override
public T execute(String serviceId, LoadBalancerRequest request) throws IOException {
// 根据 serviceId 获取 ILoadBalancer
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
// 获取 Server
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
// 重新包装为RibbonServer
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
// 获取RibbonLoadBalancerContext
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
//状态记录
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try {
// 执行请求
T returnVal = request.apply(ribbonServer);
// 状态更新
statsRecorder.recordStats(returnVal);
return returnVal;
}
// catch IOException and rethrow so RestTemplate behaves correctly
catch (IOException ex) {
// 状态更新
statsRecorder.recordStats(ex);
throw ex;
}
catch (Exception ex) {
// 状态更新
statsRecorder.recordStats(ex);
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
可以观察到, 核心的负载均衡是由 ILoadBalancer实现的.通过SpringClientFactory 获取/创建 ILoadBalancer实现实例.
protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.clientFactory.getLoadBalancer(serviceId);
}
SN-SpringClientFactory:
用以 创建 Ribbon 的 负载均衡相关实例. 并 为每个"客户端名称" 创建一个 Spring ApplicationContext per,并从中提取需要的注入对象.(但它们公用一个父容器,可以拿到父容器中的 Bean 实例的引用).而 Spring 通过RibbonClientConfiguration创建 并使用了 ILoadBalancer的一个实现,名为ZoneAwareLoadBalancer.
到这里.差不多可以看出整体雏形了:
Spring Cloud 创建并注册 RibbonLoadBalancerClient. 在execute方法中, 委托给 Ribbon 的 ILoadBalancer获取 Server, 以实现负载均衡. 默认大家了解 Spring RestTemplate(封装了 HTTP 相关方法的模板类), 在ClientHttpRequestExecution调用的过程中, 将被ClientHttpRequestInterceptor 实现拦截功能.在LoadBalancerAutoConfiguration部分,可以看到 配置注册了一个名为LoadBalancerInterceptor的ClientHttpRequestInterceptor.
S-LoadBalancerInterceptor: 实现了客户端负载均衡的拦截器
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
也就是所有的@LoadBalanced
注解的RestTemplate
都会被拦截进入loadBalancer(RibbonLoadBalancerClient)并进行相应的执行.然后我们可以进行下一步了.
S-LoadBalancerRequest
public interface LoadBalancerRequest {
public T apply(ServiceInstance instance) throws Exception;
}
最新版LoadBalancerRequest而它是由LoadBalancerRequestFactory生成.
public LoadBalancerRequest createRequest(final HttpRequest request,
final byte[] body, final ClientHttpRequestExecution execution) {
return new LoadBalancerRequest() {
@Override
public ClientHttpResponse apply(final ServiceInstance instance)
throws Exception {
// HttpRequest包转
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
if (transformers != null) {
for (LoadBalancerRequestTransformer transformer : transformers) {
//
serviceRequest = transformer.transformRequest(serviceRequest, instance);
}
}
return execution.execute(serviceRequest, body);
}
};
}
就是如此 将 RestTemplate 变为支持负载均衡的RestTemplate.
Spring集成 Ribbon 的部分已经介绍好了.下面继续深入了解下 N- ILoadBalancer 负载均衡器.(好累啊!!!.)
public interface ILoadBalancer {
// 添加服务
public void addServers(List newServers);
// 选择服务
public Server chooseServer(Object key);
// 标记为关闭的服务
public void markServerDown(Server server);
// 获取所有服务
@Deprecated
public List getServerList(boolean availableOnly);
// 获取所有可用服务
public List getReachableServers();
// 获取所有服务
public List getAllServers();
}
主要介绍下几个子类
AbstractLoadBalancer 作为ILoadBalancer的抽象.定义了 服务分类.
public abstract class AbstractLoadBalancer implements ILoadBalancer {
public enum ServerGroup{
ALL,
STATUS_UP,
STATUS_NOT_UP
}
public Server chooseServer() {
return chooseServer(null);
}
public abstract List getServerList(ServerGroup serverGroup);
public abstract LoadBalancerStats getLoadBalancerStats();
}
BaseLoadBalancer 作为基础类.主要功能有.
-
定义了 IRule 变量.实现 服务选择算法.
- RandomRule 实现了随机选择算法
- RoundRobinRule:实现了线性轮询算法
- RetryRule:实现了重试选择的算法
- WeightedResponseTimeRule:实现了更具服务状态,进行权重分析选择的算法.
- …..还有很多
定义了 IPingStrategy变量. 实现 Ping的策略.SerialPingStrategy为默认实现,线性顺序 Ping 操作.
-
定义了 IPing 变量.实现 服务是否活跃的判断.主要有:
维护了 服务列表
DynamicServerListLoadBalancer.主要提供 服务状态动态更新的功能.
-
ServerList 获取服务:
DiscoveryEnabledNIWSServerList 就实现了通过 EurekaClient 对服务列表的获取. 源码不写了.有兴趣大家可以自己读
public interface ServerList {
public List getInitialListOfServers();
public List getUpdatedListOfServers();
}
-
ServerListUpdater 控制当前服务列表的更新策略.
- PollingServerListUpdater 轮询方式 更新.
- DynamicServerListLoadBalancer: 客户端维护服务状态,并通过 控制状态改变事件的发布,实现 服务列表更新.
ZoneAwareLoadBalancer: 作为 DynamicServerListLoadBalancer的扩展,实现了关于 Zone 的概念,提高可用性.
参考资料
http://blog.didispace.com/springcloud-sourcecode-ribbon/ (感谢 DD)