本文为《Spring Cloud微服务实战》一书的摘要总结
默认配置类
package org.springframework.cloud.client.loadbalancer;
// classpath下有RestTemplate.class
// Bean容器中有LoadBalancerClient
@ConditionalOnClass({RestTemplate.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
//注入被@LoadBalanced注解的RestTemplate
@LoadBalanced
@Autowired(
required = false
)
private List<RestTemplate> restTemplates = Collections.emptyList();
//实例化一个SmartInitializingSingleton
//当容器初始化完成所有的单例bean之后,回调该bean的afterSingletonsInstantiated()方法
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> {
//调用每一个RestTemplateCustomizer Bean的customize()方法
restTemplateCustomizers.ifAvailable((customizers) -> {
Iterator var2 = this.restTemplates.iterator();
while(var2.hasNext()) {
RestTemplate restTemplate = (RestTemplate)var2.next();
Iterator var4 = customizers.iterator();
while(var4.hasNext()) {
RestTemplateCustomizer customizer = (RestTemplateCustomizer)var4.next();
customizer.customize(restTemplate);
}
}
});
};
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})
static class LoadBalancerInterceptorConfig {
LoadBalancerInterceptorConfig() {
}
//拦截器,用来实现负载均衡
@Bean
public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
//定义一个RestTemplateCustomizer,供前面定义的SmartInitializingSingleton Bean回调
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return (restTemplate) -> {
List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
上面的配置类完成了三件事:
- 创建了一个
LoadBalancerInterceptor
的Bean,用于实现客户端发起请求时进行 拦截 ,以实现客户端负载均衡; - 创建了一个
RestTemplateCustomizer
的Bean,用于给RestTemplate
增加LoadBalancerInterceptor
拦截器; - 维护一个被
@LoadBalanced
注解的RestTemplate
列表,并在初始化这些RestTemplate
之后,通过调用RestTemplateCustomizer
Bean的customize()
方法,为RestTemplate
实例添加拦截器
最主要的就是LoadBalancerInterceptor
:
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
//原始的URI,host为服务名
URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
//RibbonLoadBalancerClient.execute(String serviceId, LoadBalancerRequest<T> request)
//this.requestFactory.createRequest(request, body, execution)看下面的LoadBalancerRequestFactory
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
}
LoadBalancerRequestFactory
:
public class LoadBalancerRequestFactory {
private LoadBalancerClient loadBalancer;
private List<LoadBalancerRequestTransformer> transformers;
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer, List<LoadBalancerRequestTransformer> transformers) {
this.loadBalancer = loadBalancer;
this.transformers = transformers;
}
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer) {
this.loadBalancer = loadBalancer;
}
public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) {
//apply(instance)
return (instance) -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer);
LoadBalancerRequestTransformer transformer;
if (this.transformers != null) {
for(Iterator var6 = this.transformers.iterator(); var6.hasNext(); serviceRequest = transformer.transformRequest((HttpRequest)serviceRequest, instance)) {
transformer = (LoadBalancerRequestTransformer)var6.next();
}
}
//execute 会使用ServiceRequestWrapper的getURI来获取请求路径
return execution.execute((HttpRequest)serviceRequest, body);
};
}
}
RibbonLoadBalancerClient
:
public class RibbonLoadBalancerClient{
private SpringClientFactory clientFactory;
public RibbonLoadBalancerClient(SpringClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
//最先调用这个方法
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
}
//再调用这个方法
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
//serviceId依然是逻辑服务名称
ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
//使用某个负载均衡器获得一个Server
Server server = this.getServer(loadBalancer, hint);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
} else {
//将Server包装成RibbonServer
RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
//调用下面的execute
return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
}
}
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
//hint 为 null
return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
Server server = null;
if (serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) {
server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer();
}
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
} else {
RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try {
//调用LoadBalancerInterceptor中使用requestFactory创建的LoadBalancerRequest.apply();
T returnVal = request.apply(serviceInstance);
statsRecorder.recordStats(returnVal);
return returnVal;
} catch (IOException var8) {
statsRecorder.recordStats(var8);
throw var8;
} catch (Exception var9) {
statsRecorder.recordStats(var9);
ReflectionUtils.rethrowRuntimeException(var9);
return null;
}
}
}
}
ILoadBalancer
public interface ILoadBalancer {
// 向负载均衡器中维护的实例列表添加服务实例
// Server对象定义了一个传统的服务节点,,存储了服务端节点的host,port以及一些元数据
void addServers(List<Server> var1);
// 通过某种策略,从负载均衡器中挑选出一个具体的服务实例
Server chooseServer(Object var1);
//通知和标识具体实例已经停止服务
void markServerDown(Server var1);
/** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1);
// 获取当前正常服务的实例列表
List<Server> getReachableServers();
// 获取所有的列表
List<Server> getAllServers();
}
ILoadBalancer继承结构:
默认的ILoadBalancer
:ZoneAwareLoadBalancer
public class RibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
//当没有配置ILoadBalancer时,默认使用ZoneAwareLoadBalancer
return (ILoadBalancer)(this.propertiesFactory.isSet(ILoadBalancer.class, this.name) ? (ILoadBalancer)this.propertiesFactory.get(ILoadBalancer.class, config, this.name) : new ZoneAwareLoadBalancer(config, rule, ping, serverList, serverListFilter, serverListUpdater));
}
}
apply 方法
public LoadBalancerRequest<ClientHttpResponse> apply(ServiceInstance instance){
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer);
LoadBalancerRequestTransformer transformer;
if (this.transformers != null) {
for(Iterator var6 = this.transformers.iterator(); var6.hasNext(); serviceRequest = transformer.transformRequest((HttpRequest)serviceRequest, instance)) {
transformer = (LoadBalancerRequestTransformer)var6.next();
}
}
//execute 会使用ServiceRequestWrapper的getURI来获取请求路径
return execution.execute((HttpRequest)serviceRequest, body);
}
ServiceRequestWrapper
:
public class ServiceRequestWrapper extends HttpRequestWrapper {
private final ServiceInstance instance;
//这里是RibbonLoadBalancerClient
private final LoadBalancerClient loadBalancer;
public ServiceRequestWrapper(HttpRequest request, ServiceInstance instance, LoadBalancerClient loadBalancer) {
super(request);
this.instance = instance;
this.loadBalancer = loadBalancer;
}
public URI getURI() {
//调用RibbonLoadBalancerClient.reconstructURI
URI uri = this.loadBalancer.reconstructURI(this.instance, this.getRequest().getURI());
return uri;
}
}
RibbonLoadBalancerClient
public class RibbonLoadBalancerClient{
public URI reconstructURI(ServiceInstance instance, URI original) {
Assert.notNull(instance, "instance can not be null");
String serviceId = instance.getServiceId();
RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
URI uri;
Server server;
if (instance instanceof RibbonLoadBalancerClient.RibbonServer) {
RibbonLoadBalancerClient.RibbonServer ribbonServer = (RibbonLoadBalancerClient.RibbonServer)instance;
server = ribbonServer.getServer();
uri = RibbonUtils.updateToSecureConnectionIfNeeded(original, ribbonServer);
} else {
server = new Server(instance.getScheme(), instance.getHost(), instance.getPort());
IClientConfig clientConfig = this.clientFactory.getClientConfig(serviceId);
ServerIntrospector serverIntrospector = this.serverIntrospector(serviceId);
uri = RibbonUtils.updateToSecureConnectionIfNeeded(original, clientConfig, serverIntrospector, server);
}
//调用LoadBalancerContext的reconstructURIWithServer
return context.reconstructURIWithServer(server, uri);
}
}
LoadBalancerContext
public class LoadBalancerContext{
public URI reconstructURIWithServer(Server server, URI original) {
String host = server.getHost();
int port = server.getPort();
String scheme = server.getScheme();
if (host.equals(original.getHost()) && port == original.getPort() && scheme == original.getScheme()) {
return original;
} else {
if (scheme == null) {
scheme = original.getScheme();
}
if (scheme == null) {
scheme = (String)this.deriveSchemeAndPortFromPartialUri(original).first();
}
try {
StringBuilder sb = new StringBuilder();
sb.append(scheme).append("://");
if (!Strings.isNullOrEmpty(original.getRawUserInfo())) {
sb.append(original.getRawUserInfo()).append("@");
}
sb.append(host);
if (port >= 0) {
sb.append(":").append(port);
}
sb.append(original.getRawPath());
if (!Strings.isNullOrEmpty(original.getRawQuery())) {
sb.append("?").append(original.getRawQuery());
}
if (!Strings.isNullOrEmpty(original.getRawFragment())) {
sb.append("#").append(original.getRawFragment());
}
URI newURI = new URI(sb.toString());
return newURI;
} catch (URISyntaxException var8) {
throw new RuntimeException(var8);
}
}
}
}
负载均衡器
AbstractLoadBalancer
public abstract class AbstractLoadBalancer implements ILoadBalancer {
public AbstractLoadBalancer() {
}
//调用ILoadBalancer接口的chooseServer(Object var1)方法
public Server chooseServer() {
return this.chooseServer((Object)null);
}
public abstract List<Server> getServerList(AbstractLoadBalancer.ServerGroup var1);
//定义了一个获取LoadBalancerStats对象的方法,该对象用来记录负载均衡其中服务实例当前的属性和统计信息
public abstract LoadBalancerStats getLoadBalancerStats();
//定义了一个静态服务分组枚举类型
public static enum ServerGroup {
ALL,
STATUS_UP,
STATUS_NOT_UP;
private ServerGroup() {
}
}
}
BaseLoadBalancer
//继承了`AbstractLoadBalancer`
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
//维护一个存储全部服务实例的列表
protected volatile List<Server> allServerList;
//维护一个存储正常服务是咧的列表
protected volatile List<Server> upServerList;
//定义了一个LoadBalancerStats对象
protected LoadBalancerStats lbStats;
//定义了默认的IRule
private static final IRule DEFAULT_RULE = new RoundRobinRule();
protected IRule rule;
//定义了默认的IPingStrategy
private static final BaseLoadBalancer.SerialPingStrategy DEFAULT_PING_STRATEGY = new BaseLoadBalancer.SerialPingStrategy((SyntheticClass_1)null);
protected IPingStrategy pingStrategy;
protected IPing ping;
//检查服务的间隔时间
protected int pingIntervalSeconds;
public BaseLoadBalancer(){
this.lbStats = new LoadBalancerStats("default");
//默认的负载均衡规则
this.rule = DEFAULT_RULE;
//默认的ping策略
this.pingStrategy = DEFAULT_PING_STRATEGY;
this.ping = null;
//线程安全的列表
this.allServerList = Collections.synchronizedList(new ArrayList());
this.upServerList = Collections.synchronizedList(new ArrayList());
//列表的读写锁
this.allServerLock = new ReentrantReadWriteLock();
this.upServerLock = new ReentrantReadWriteLock();
//启动一个定时任务来检查服务是否健康
this.setupPingTask();
}
//选择服务
public Server chooseServer(Object key) {
if (this.counter == null) {
this.counter = this.createCounter();
}
this.counter.increment();
if (this.rule == null) {
return null;
} else {
try {
//调用负载均衡规则对象的choose()方法
return this.rule.choose(key); //rule 默认是RoundRobinRule
} catch (Exception var3) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3});
return null;
}
}
}
}
RoundRobinRule
线性返回allServerList
中的服务实例,如果在一次获取服务实例的过程中,循环了10次都没有获取到服务,将返回null
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
//通过取余数的方法来获取下一个服务实例的位置
int nextServerIndex = this.incrementAndGetModulo(serverCount);
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
DynamicServerListLoadBalancer
继承了BaseLoadBalancer
类,是对基础负载均衡器的扩展。实现了服务清单在运行期间的 动态更新 能力;还具备对服务清单的过滤功能。
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer{
volatile ServerList<T> serverListImpl;
}
ServerList
public interface ServerList<T extends Server> {
//获取初始化的服务实例清单
List<T> getInitialListOfServers();
//获取更新的服务实例清单
List<T> getUpdatedListOfServers();
}
ServerList继承结构图:
如果是用Eureka做服务治理,那么我们在org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientConfiguration
配置类中找到:
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
if (this.propertiesFactory.isSet(ServerList.class, this.serviceId)) {
return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.serviceId);
} else {
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider);
//默认使用DomainExtractingServerList
DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
return serverList;
}
}
DomainExtractingServerList
:
public class DomainExtractingServerList implements ServerList<DiscoveryEnabledServer> {
private ServerList<DiscoveryEnabledServer> list;
private final RibbonProperties ribbon;
private boolean approximateZoneFromHostname;
public DomainExtractingServerList(ServerList<DiscoveryEnabledServer> list, IClientConfig clientConfig, boolean approximateZoneFromHostname) {
//默认是DiscoveryEnabledNIWSServerList
this.list = list;
this.ribbon = RibbonProperties.from(clientConfig);
this.approximateZoneFromHostname = approximateZoneFromHostname;
}
//委托给了DiscoveryEnabledNIWSServerList
public List<DiscoveryEnabledServer> getInitialListOfServers() {
List<DiscoveryEnabledServer> servers = this.setZones(this.list.getInitialListOfServers());
return servers;
}
//委托给了DiscoveryEnabledNIWSServerList
public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
List<DiscoveryEnabledServer> servers = this.setZones(this.list.getUpdatedListOfServers());
return servers;
}
private List<DiscoveryEnabledServer> setZones(List<DiscoveryEnabledServer> servers) {
List<DiscoveryEnabledServer> result = new ArrayList();
boolean isSecure = this.ribbon.isSecure(true);
boolean shouldUseIpAddr = this.ribbon.isUseIPAddrForServer();
Iterator var5 = servers.iterator();
while(var5.hasNext()) {
DiscoveryEnabledServer server = (DiscoveryEnabledServer)var5.next();
//将从DiscoveryEnabledNIWSServerList获取的服务列表中的服务实例转为DomainExtractingServer类型
result.add(new DomainExtractingServer(server, isSecure, shouldUseIpAddr, this.approximateZoneFromHostname));
}
return result;
}
}
DomainExtractingServerList
将获取初始化服务列表与获取更新列表委托给了DiscoveryEnabledNIWSServerList
去处理;
DiscoveryEnabledNIWSServerList
:
public class DiscoveryEnabledNIWSServerList extends AbstractServerList<DiscoveryEnabledServer> {
public List<DiscoveryEnabledServer> getInitialListOfServers() {
return this.obtainServersViaDiscovery();
}
public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
return this.obtainServersViaDiscovery();
}
//使用EurekaClient去获取服务实例,并将状态未UP的服务实例放入列表
private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {
List<DiscoveryEnabledServer> serverList = new ArrayList();
if (this.eurekaClientProvider != null && this.eurekaClientProvider.get() != null) {
EurekaClient eurekaClient = (EurekaClient)this.eurekaClientProvider.get();
if (this.vipAddresses != null) {
String[] var3 = this.vipAddresses.split(",");
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
String vipAddress = var3[var5];
//获取服务实例
List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, this.isSecure, this.targetRegion);
Iterator var8 = listOfInstanceInfo.iterator();
while(var8.hasNext()) {
InstanceInfo ii = (InstanceInfo)var8.next();
//过滤掉不正常服务
if (ii.getStatus().equals(InstanceStatus.UP)) {
if (this.shouldUseOverridePort) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding port on client name: " + this.clientName + " to " + this.overridePort);
}
InstanceInfo copy = new InstanceInfo(ii);
if (this.isSecure) {
ii = (new Builder(copy)).setSecurePort(this.overridePort).build();
} else {
ii = (new Builder(copy)).setPort(this.overridePort).build();
}
}
DiscoveryEnabledServer des = this.createServer(ii, this.isSecure, this.shouldUseIpAddr);
serverList.add(des);
}
}
if (serverList.size() > 0 && this.prioritizeVipAddressBasedServers) {
break;
}
}
}
return serverList;
} else {
logger.warn("EurekaClient has not been initialized yet, returning an empty list");
return new ArrayList();
}
}
}
ServerListUpdater
如何触发想Eureka服务治理中心中获取服务实例清单:
在DynamicServerListLoadBalancer
中,维护了一个ServerListUpdater
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer{
protected volatile ServerListUpdater serverListUpdater;
protected final UpdateAction updateAction;
}
public interface ServerListUpdater {
//启动服务更新器,ServerListUpdater.UpdateAction对象为具体的更新实现
void start(ServerListUpdater.UpdateAction var1);
//停止服务更新器
void stop();
//获取最近的更新时间戳
String getLastUpdate();
//获取上一次更新到这一次更新的时间间隔
long getDurationSinceLastUpdateMs();
//获取错过的更新周期数
int getNumberMissedCycles();
//获取核心线程数
int getCoreThreads();
public interface UpdateAction {
void doUpdate();
}
}
ServerListUpdater
的继承机构图:
我们看一下PollingServerListUpdataer
:
public class PollingServerListUpdater implements ServerListUpdater {
...
/**
* 新线程中执行定时任务进行更新
*/
public synchronized void start(final UpdateAction updateAction) {
if (this.isActive.compareAndSet(false, true)) {
Runnable wrapperRunnable = new Runnable() {
public void run() {
if (!PollingServerListUpdater.this.isActive.get()) {
if (PollingServerListUpdater.this.scheduledFuture != null) {
PollingServerListUpdater.this.scheduledFuture.cancel(true);
}
} else {
try {
//更新操作
updateAction.doUpdate();
PollingServerListUpdater.this.lastUpdated = System.currentTimeMillis();
} catch (Exception var2) {
PollingServerListUpdater.logger.warn("Failed one update cycle", var2);
}
}
}
};
//启动一个定时任务
//其中任务在服务实例在初始化之后延迟initialDelayMs毫秒时间后执行,默认为1000毫秒
//执行周期为refreshIntervalMs毫秒,默认为30*1000毫秒
this.scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(wrapperRunnable, this.initialDelayMs, this.refreshIntervalMs, TimeUnit.MILLISECONDS);
} else {
logger.info("Already active, no-op");
}
}
}
回到DynamicServerListLoadBalancer
的构造方法中,看看是如何启动定时任务的:
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer{
public DynamicServerListLoadBalancer(IClientConfig clientConfig) {
...
this.initWithNiwsConfig(clientConfig);
}
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) {
...
this.restOfInit(clientConfig);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
...
this.restOfInit(clientConfig);
}
void restOfInit(IClientConfig clientConfig) {
...
this.enableAndInitLearnNewServersFeature();
...
}
public void enableAndInitLearnNewServersFeature() {
LOGGER.info("Using serverListUpdater {}", this.serverListUpdater.getClass().getSimpleName());
//启动服务更新器
this.serverListUpdater.start(this.updateAction);
}
}
所以,在构造DynamicServerListLoadBalancer
实例是,就启动了更新器,周期性的获取服务实例清单。
再来看UpdateAction
中的doUpdate
方法,该方法在DynamicServerListLoadBalancer
中使用匿名类别类实现,下面是更新的具体步骤:
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer{
public DynamicServerListLoadBalancer(...) {
...
this.serverListUpdater = serverListUpdater;
//一个匿名内部类,实现更新操作
this.updateAction = new ServerListUpdater.UpdateAction(){
@Override
public void doUpdate() {
DynamicServerListLoadBalancer.this.updateListOfServers();
}
};
}
//获取服务实例清单;过滤服务;更新存储服务实例的域
public void updateListOfServers() {
List<T> servers = new ArrayList();
if (this.serverListImpl != null) {
//获取服务中心的服务实例清单
servers = this.serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers);
if (this.filter != null) {
//这里看下面的
servers = this.filter.getFilteredListOfServers((List)servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers);
}
}
//设置服务实例的一些属性,并为DynamicServerListLoadBalancer的一些属性赋值
this.updateAllServerList((List)servers);
}
}
ServerListFilter
:
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer {
volatile ServerListFilter<T> filter;
...
}
public interface ServerListFilter<T extends Server> {
//通过一定规则对服务实例列表过滤
List<T> getFilteredListOfServers(List<T> var1);
}
ServerListFilter
的继承结构:
-
AbstractServerFilter
:一个抽象过滤器,定义了过滤时需要的一个重要依据对象LoadBalancerStats
。 -
ZoneAffinityServerListFilter
:“区域感知(Zone Affinity)”的方式实现服务实例的过滤,它将过滤掉那些提供服务的实例所处的区域与消费者自身所处的区域不同的那些服务实例。
public List<T> getFilteredListOfServers(List<T> servers) {
if (this.zone != null && (this.zoneAffinity || this.zoneExclusive) && servers != null && servers.size() > 0) {
List<T> filteredServers = Lists.newArrayList(Iterables.filter(servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));
//在过滤之后并不马上返回过滤结果,而是需要根据某种算法判断是否要启用区域感知功能
if (this.shouldEnableZoneAffinity(filteredServers)) {
return filteredServers;
}
if (this.zoneAffinity) {
this.overrideCounter.increment();
}
}
return servers;
}
private boolean shouldEnableZoneAffinity(List<T> filtered) {
//配置了区域感知和区域独享为false
if (!this.zoneAffinity && !this.zoneExclusive) {
return false;
} else if (this.zoneExclusive) {//配置了区域独享为true
return true;
} else {
LoadBalancerStats stats = this.getLoadBalancerStats();
if (stats == null) {
return this.zoneAffinity;
} else {
logger.debug("Determining if zone affinity should be enabled with given server list: {}", filtered);
ZoneSnapshot snapshot = stats.getZoneSnapshot(filtered);
double loadPerServer = snapshot.getLoadPerServer();
int instanceCount = snapshot.getInstanceCount();
int circuitBreakerTrippedCount = snapshot.getCircuitTrippedCount();
//故障实例 < 0.8
//实例评价负载 < 0.6
//可用实例数 >= 2
if ((double)circuitBreakerTrippedCount / (double)instanceCount < this.blackOutServerPercentageThreshold.get() && loadPerServer < this.activeReqeustsPerServerThreshold.get() && instanceCount - circuitBreakerTrippedCount >= this.availableServersThreshold.get()) {
return true;
} else {
logger.debug("zoneAffinity is overriden. blackOutServerPercentage: {}, activeReqeustsPerServer: {}, availableServers: {}", new Object[]{(double)circuitBreakerTrippedCount / (double)instanceCount, loadPerServer, instanceCount - circuitBreakerTrippedCount});
return false;
}
}
}
}
当故障实例 < 0.8 且实例评价负载 < 0.6且可用实例数 >= 2时,过滤掉不在同一区域的服务实例。
-
DefualtNIWSServerListFilter
:完全继承ZoneAffinityServerListFilter
,是默认的NIWS(Netflix Internal Web Service)过滤器 -
ServerListSubsetFilter
:也继承自ZoneAffinityServerListFilter
,适合大规模服务器集群的系统。 -
ZonePreferenceServerListFilter
:Spring Cloud整合是新增的过滤器。若使用Spring Cloud整合Eureka和Ribbon时会默认使用这个过滤器。
public List<Server> getFilteredListOfServers(List<Server> servers) {
//先通过父类`ZoneAffinityServerListFilter`的过滤器来获得“区域感知”的服务实例列表
List<Server> output = super.getFilteredListOfServers(servers);
//再根据消费者配置的区域来过滤
if (this.zone != null && output.size() == servers.size()) {
List<Server> local = new ArrayList();
Iterator var4 = output.iterator();
while(var4.hasNext()) {
Server server = (Server)var4.next();
if (this.zone.equalsIgnoreCase(server.getZone())) {
local.add(server);
}
}
if (!local.isEmpty()) {
return local;
}
}
return output;
}
ZoneAwareLoadBalancer
在DynamicServerListLoadBalancer
中,没有重写选择具体服务实例的chooseServer()
函数,所以它还是以 线性轮询 的方式来获取服务实例,这样就可能造成周期性的 跨区域访问 的情况。
DynamicServerListLoadBalancer
实现服务实例清单的逻辑没有变,但是它重写了setServerListForZones()
方法。
暂时跳过,后面再补充。
负载均衡策略
IRule
的继承结构:
AbstractLoadBalancer
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb;
public AbstractLoadBalancerRule() {
}
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
public ILoadBalancer getLoadBalancer() {
return this.lb;
}
}
维护了一个ILoadBalancer
(负载均衡器)对象,在具体实现选择服务策略时,可以从该对象中获取到负载均衡器维护的信息来作为分配依据。
RandomRule
@Override
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
//随机选择一个服务实例
int index = this.chooseRandomInt(serverCount);
server = (Server)upList.get(index);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
从它实现的choose()
方法可以看出,它会 随机选择 一个正常服务实例。
RoundRobinRule
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
//这是实现线性轮询的关键点
int nextServerIndex = this.incrementAndGetModulo(serverCount);
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
从上面可以看到,该规则以 线性轮询 的方式来获取服务实例,如果一直选择不到server超过10次,就会结束获取服务实例,并打印警告信息。
RetryRule
//维护着一个子规则
IRule subRule = new RoundRobinRule();
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public Server choose(ILoadBalancer lb, Object key) {
long requestTime = System.currentTimeMillis();
long deadline = requestTime + this.maxRetryMillis;
Server answer = null;
//通过子规则获取服务实例
answer = this.subRule.choose(key);
//若没有获取到server且没有到结束时间那么将再次获取
if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline) {
InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());
//循环获取服务,直到获取到服务实例,或者超时
while(!Thread.interrupted()) {
answer = this.subRule.choose(key);
if (answer != null && answer.isAlive() || System.currentTimeMillis() >= deadline) {
break;
}
Thread.yield();
}
task.cancel();
}
return answer != null && answer.isAlive() ? answer : null;
}
还是使用 线性轮询 的方式获取服务实例,但不像是RoundRobinRule
那样可以尝试10次,而是设置一个超时时间,在超时时间内,循环获取服务实例。
WeightedResponseTimeRule
protected Timer serverWeightTimer = null;
public WeightedResponseTimeRule(ILoadBalancer lb) {
//这里会调用setLoadBalancer(ILoadBalancer lb)方法
super(lb);
}
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
if (lb instanceof BaseLoadBalancer) {
this.name = ((BaseLoadBalancer)lb).getName();
}
this.initialize(lb);
}
void initialize(ILoadBalancer lb) {
if (this.serverWeightTimer != null) {
this.serverWeightTimer.cancel();
}
this.serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-" + this.name, true);
//定时计算每个服务实例的权重,默认执行周期为30s
this.serverWeightTimer.schedule(new WeightedResponseTimeRule.DynamicServerWeightTask(), 0L, (long)this.serverWeightTaskTimerInterval);
WeightedResponseTimeRule.ServerWeight sw = new WeightedResponseTimeRule.ServerWeight();
sw.maintainWeights();
//增加关闭钩子,当关闭程序时,关闭这个定时任务
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
WeightedResponseTimeRule.logger.info("Stopping NFLoadBalancer-serverWeightTimer-" + WeightedResponseTimeRule.this.name);
WeightedResponseTimeRule.this.serverWeightTimer.cancel();
}
}));
}
//计算权重的任务
class DynamicServerWeightTask extends TimerTask {
DynamicServerWeightTask() {
}
public void run() {
WeightedResponseTimeRule.ServerWeight serverWeight = WeightedResponseTimeRule.this.new ServerWeight();
try {
//计算每个服务的权重
serverWeight.maintainWeights();
} catch (Exception var3) {
WeightedResponseTimeRule.logger.error("Error running DynamicServerWeightTask for {}", WeightedResponseTimeRule.this.name, var3);
}
}
}
权重的计算方式:
- 根据
LoadBalancerStats
中记录的每个实例的统计信息,累加所有实例的平均响应时间,得到总平均响应时间totalResponseTime
; - 逐个计算每个实例的 权重区间:
Double weightSoFar = 0.0;
//记录每个权重区间的上限
List<Double> finalWeights = new ArrayList();
Iterator iterator = nlb.getAllServers().iterator();
while(iterator.hasNext()) {
Server serverx = (Server)iterator.next();
ServerStats ssx = stats.getSingleServerStat(serverx);
//计算权重
double weight = totalResponseTime - ssx.getResponseTimeAvg();
//权重区间的上限
weightSoFar = weightSoFar + weight;
finalWeights.add(weightSoFar);
}
服务的权重=总平均响应时间 - 服务平均响应时间;
服务区间下限 = 上一个服务区间的上限(第一个服务实例的权重区间下限为0)
服务间的上限 = 区间下限 + 服务权重
服务的选取规则:
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
List<Double> currentWeights = this.accumulatedWeights;
if (Thread.interrupted()) {
return null;
}
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
int serverIndex = 0;
//获取最后一个服务实例的权重
double maxTotalWeight = currentWeights.size() == 0 ? 0.0D : (Double)currentWeights.get(currentWeights.size() - 1);
if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
//生成一个0-最有一个服务权重上限的随机数
double randomWeight = this.random.nextDouble() * maxTotalWeight;
int n = 0;
//选择随机数命中的服务实例
for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
Double d = (Double)var13.next();
if (d >= randomWeight) {
serverIndex = n;
break;
}
}
server = (Server)allList.get(serverIndex);
} else {
//如果最后一个服务实例的权重<0.001,则使用RoundRobinRule的策略
server = super.choose(this.getLoadBalancer(), key);
if (server == null) {
return server;
}
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
}
}
return server;
}
}
权重区间越大,那么命中的概率越高,权重区间的宽度就是服务的权重(总平均响应时间-服务的平均响应时间),所以平均响应时间越低,越容易被选中。
ClientConfigEnabledRoundRobinRule
public class ClientConfigEnabledRoundRobinRule extends AbstractLoadBalancerRule {
RoundRobinRule roundRobinRule = new RoundRobinRule();
public ClientConfigEnabledRoundRobinRule() {
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.roundRobinRule = new RoundRobinRule();
}
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
this.roundRobinRule.setLoadBalancer(lb);
}
public Server choose(Object key) {
if (this.roundRobinRule != null) {
return this.roundRobinRule.choose(key);
} else {
throw new IllegalArgumentException("This class has not been initialized with the RoundRobinRule class");
}
}
}
一般直接使用该类型,因为直接使用它,跟使用RoundRobinRule
是一样的。更多的是使用它的子类,使用更加高级的策略。当子类无法满足使用高级策略的条件的时候,就可以使用父类的策略(线性轮询)。
BestAvailableRule
public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule {
private LoadBalancerStats loadBalancerStats;
public Server choose(Object key) {
//不满足使用高级策略的条件
if (this.loadBalancerStats == null) {
return super.choose(key);
} else {
List<Server> serverList = this.getLoadBalancer().getAllServers();
int minimalConcurrentConnections = Integer.MAX_VALUE;
long currentTime = System.currentTimeMillis();
Server chosen = null;
Iterator var7 = serverList.iterator();
while(var7.hasNext()) {
Server server = (Server)var7.next();
ServerStats serverStats = this.loadBalancerStats.getSingleServerStat(server);
if (!serverStats.isCircuitBreakerTripped(currentTime)) {//过滤掉故障实例
int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
if (concurrentConnections < minimalConcurrentConnections) {
minimalConcurrentConnections = concurrentConnections;//超找最小并发数服务实例
chosen = server;
}
}
}
if (chosen == null) {
return super.choose(key);
} else {
return chosen;
}
}
}
}
该策略过滤掉故障服务实例,并选择最小并发数的服务。
PredicateBasedRule
public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
public PredicateBasedRule() {
}
public abstract AbstractServerPredicate getPredicate();
public Server choose(Object key) {
ILoadBalancer lb = this.getLoadBalancer();
//先通过子类实现的getPredicate过滤掉一部分服务,然后再通过线性轮询的方式获取服务实例
Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
return server.isPresent() ? (Server)server.get() : null;
}
}
AvailabilityFilteringRule
public class AvailabilityFilteringRule extends PredicateBasedRule {
//定义了AbstractServerPredicate
private AbstractServerPredicate predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, (IClientConfig)null)).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
//实现了父类的getPredicate()方法
public AbstractServerPredicate getPredicate() {
return this.predicate;
}
}
public abstract class AbstractServerPredicate implements Predicate<PredicateKey> {
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
//过滤掉故障或并发请求数大于阈值的服务实例
List<Server> eligible = this.getEligibleServers(servers, loadBalancerKey);
//线性轮询
return eligible.size() == 0 ? Optional.absent() : Optional.of(eligible.get(this.incrementAndGetModulo(eligible.size())));
}
public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
if (loadBalancerKey == null) {
return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));
} else {
List<Server> results = Lists.newArrayList();
Iterator var4 = servers.iterator();
while(var4.hasNext()) {
Server server = (Server)var4.next();
//调用子类实现的apply()方法进行过滤
if (this.apply(new PredicateKey(loadBalancerKey, server))) {
results.add(server);
}
}
return results;
}
}
}
public class AvailabilityPredicate extends AbstractServerPredicate {
public boolean apply(@Nullable PredicateKey input) {
LoadBalancerStats stats = this.getLBStats();
if (stats == null) {
return true;
} else {
//主要是这里的判断,故障或并发请求数大于阈值将排除这个服务实例
return !this.shouldSkipServer(stats.getSingleServerStat(input.getServer()));
}
}
private boolean shouldSkipServer(ServerStats stats) {
//故障或并发请求数大于阈值
return CIRCUIT_BREAKER_FILTERING.get() && stats.isCircuitBreakerTripped() || stats.getActiveRequestsCount() >= (Integer)this.activeConnectionsLimit.get();
}
}
来看一下它的choose()
方法:
public Server choose(Object key) {
int count = 0;
for(Server server = this.roundRobinRule.choose(key); count++ <= 10; server = this.roundRobinRule.choose(key)) {
if (this.predicate.apply(new PredicateKey(server))) {
return server;
}
}
return super.choose(key);
}
可以看到,在该方法下,以线性轮询的方式每次获取一个服务实例,然后判断该服务是否故障,并发数是否大于阈值,满足条件则返回,不满足条件则继续轮询下一个服务实例。最多尝试10次,超过10次则使用父类的规则:获取所有的服务实例列表,过滤掉故障的和并发数大于阈值的,然后线性轮询返回一个服务实例。
ZoneAvoidanceRule
同ZoneAwareLoadBalancer一起补充