springboot 版本2.1.3.RELEASE
springCloud版本Greenwich.RELEASE
LoadBalancerAutoConfiguration
截取重要部分
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
//这里的LoadBalanced整合了@Qualifier
//加载所有带@LoadBalanced标示的RestTemplate集合
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
//创建LoadBalancerInterceptor拦截器
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
//将拦截器加入到restTemplate中
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
接上面LoadBalancerInterceptor拦截器中
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
//这里的LoadBalancerClient默认是引用RibbonLoadBalancerClient
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
//重点在这里RibbonLoadBalancerClient.execute
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
}
//在这里引入了RibbonLoadBalancerClient
@Configuration
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
@RibbonClients
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
return new RibbonLoadBalancerClient(springClientFactory());
}
}
继续看RibbonLoadBalancerClient.execute
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
//springCloud使用了ZoneAwareLoadBalancer实现类
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
//这里根据负载规则获取具体的server信息
Server server = getServer(loadBalancer, hint);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
Server server = null;
if(serviceInstance instanceof RibbonServer) {
server = ((RibbonServer)serviceInstance).getServer();
}
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try {
//传入需要请求的服务实例定义serviceInstance,里面包括了实例id、端口、地址等信息
//到这一步Ribbon拦截结束,调用ClientHttpRequestExecution.execute
T returnVal = request.apply(serviceInstance);
//Ribbon对服务请求进行了跟踪将调用的情况存入ServerStats中
//后续负载均衡器进行choose计算时会使用到
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接口
public interface ILoadBalancer {
//添加新的服务实例
void addServers(List<Server> var1);
//根据一个key选择服务实例
Server chooseServer(Object var1);
//标记一个服务实例down
void markServerDown(Server var1);
/** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1);
//获取所有可用的服务实例(UP)
List<Server> getReachableServers();
//获取所有的服务实例
List<Server> getAllServers();
}
看一下有哪些实现类
这里springCloud使用了ZoneAwareLoadBalancer
@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
}
接下来看下ILoadBalancer的各个具体实现
AbstractLoadBalancer
public abstract class AbstractLoadBalancer implements ILoadBalancer {
//定义了服务的分组
public enum ServerGroup{
ALL,
STATUS_UP,
STATUS_NOT_UP
}
public Server chooseServer() {
return chooseServer(null);
}
public abstract List<Server> getServerList(ServerGroup serverGroup);
//LoadBalancerStats被用来存储各个服务实例的当前属性和统计信息,是制定负载均衡策略的重要依据
public abstract LoadBalancerStats getLoadBalancerStats();
}
BaseLoadBalancer
截取部分重要代码
//Ribbon负载均衡器的基本实现
public class BaseLoadBalancer extends AbstractLoadBalancer implements
PrimeConnections.PrimeConnectionListener, IClientConfigAware {
//默认的负载规则,轮询
private final static IRule DEFAULT_RULE = new RoundRobinRule();
//默认的ping策略,线性检查服务状态
private final static SerialPingStrategy DEFAULT_PING_STRATEGY = new SerialPingStrategy();
//检查服务是否存活,实现boolean isAlive(Server server)方法
protected IPing ping = null;
@Monitor(name = PREFIX + "AllServerList", type = DataSourceType.INFORMATIONAL)
protected volatile List<Server> allServerList = Collections
.synchronizedList(new ArrayList<Server>());
@Monitor(name = PREFIX + "UpServerList", type = DataSourceType.INFORMATIONAL)
protected volatile List<Server> upServerList = Collections
.synchronizedList(new ArrayList<Server>());
public BaseLoadBalancer() {
this.name = DEFAULT_NAME;
this.ping = null;
setRule(DEFAULT_RULE);
//启动一个健康检查任务 10秒检查一次
setupPingTask();
lbStats = new LoadBalancerStats(DEFAULT_NAME);
}
//选择一个具体服务实例,最终是交给IRule接口处理
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
}
DynamicServerListLoadBalancer
ServerList
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer {
//ServerList接口封装了对serverList的处理,定义了俩个方法 分别处理serverList的初始化和更新
volatile ServerList<T> serverListImpl;
protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
@Override
public void doUpdate() {
//这个方法最终调用了serverListImpl.getUpdatedListOfServers()更新serverList列表
updateListOfServers();
}
};
@VisibleForTesting
public void updateListOfServers() {
List<T> servers = new ArrayList<T>();
if (serverListImpl != null) {
//调用ServerList接口更新serverList列表
servers = serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
if (filter != null) {
//这里调用了过滤器
servers = filter.getFilteredListOfServers(servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
}
}
updateAllServerList(servers);
}
//服务更新器,默认实现类是PollingServerListUpdater
//实现了synchronized void start(final UpdateAction updateAction),开启定时器30秒调用一次doUpdate()
protected volatile ServerListUpdater serverListUpdater;
//
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
ServerList<T> serverList, ServerListFilter<T> filter,
ServerListUpdater serverListUpdater) {
super(clientConfig, rule, ping);
this.serverListImpl = serverList;
this.filter = filter;
this.serverListUpdater = serverListUpdater;
if (filter instanceof AbstractServerListFilter) {
((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
}
//这里最终会调用serverListUpdater.start(final UpdateAction updateAction)
restOfInit(clientConfig);
}
}
ServerList接口封装了对serverList的处理,springCloud的实现类DomainExtractingServerList,最终调用了com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList,从eureka获取serverList
public interface ServerList<T extends Server> {
public List<T> getInitialListOfServers();
public List<T> getUpdatedListOfServers();
}
//在这里springCloud创建了DomainExtractingServerList实现ServerList接口,最终委派给DiscoveryEnabledNIWSServerList处理
@Configuration
public class EurekaRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
return this.propertiesFactory.get(ServerList.class, config, serviceId);
}
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
config, eurekaClientProvider);
DomainExtractingServerList serverList = new DomainExtractingServerList(
discoveryServerList, config, this.approximateZoneFromHostname);
return serverList;
}
}
服务更新器ServerListUpdater
public interface ServerListUpdater {
/**
* 实现更新的具体操作
*/
public interface UpdateAction {
void doUpdate();
}
/**
* 开启服务更新器,调用updateAction
*/
void start(UpdateAction updateAction);
/**
* 停止服务更新器
*/
void stop();
/**
* 获取最近的更新时间戳
*/
String getLastUpdate();
/**
* 获取上一次更新到现在的间隔 毫秒
*/
long getDurationSinceLastUpdateMs();
/**
* 获取错过的更新周期数
*/
int getNumberMissedCycles();
/**
* 获取核心线程数
*/
int getCoreThreads();
}
ServerListFilter过滤器,在updateListOfServers方法中调用
volatile ServerListFilter<T> filter;
@VisibleForTesting
public void updateListOfServers() {
List<T> servers = new ArrayList<T>();
if (serverListImpl != null) {
servers = serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
//关键在这里获取到服务列表后,如果有过滤器则进行过滤
if (filter != null) {
servers = filter.getFilteredListOfServers(servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
}
}
updateAllServerList(servers);
}
ServerListFilter接口定义
public interface ServerListFilter<T extends Server> {
public List<T> getFilteredListOfServers(List<T> servers);
}
看一下有哪些可用的过滤器
其中AbstractServerListFilter是抽象过滤器,定义了过滤时用到的重要指标LoadBalancerStats
public abstract class AbstractServerListFilter<T extends Server> implements ServerListFilter<T> {
private volatile LoadBalancerStats stats;
public void setLoadBalancerStats(LoadBalancerStats stats) {
this.stats = stats;
}
public LoadBalancerStats getLoadBalancerStats() {
return stats;
}
}
ZoneAffinityServerListFilter
基于区域感知的方式实现服务实例过滤
public List<T> getFilteredListOfServers(List<T> servers) {
//根据自身的zone和服务实例配置的zone进行匹配
if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){
List<T> filteredServers = Lists.newArrayList(Iterables.filter(
servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));
//这里对筛选后的结果进行一次分析,用到了LoadBalancerStats和serverStats
//分析内容 故障实例百分比、实例平均负载、可用实例数
//如果发现上面的内容有一项不符合要求则放弃此次过滤,保证跨区域高可用
if (shouldEnableZoneAffinity(filteredServers)) {
return filteredServers;
} else if (zoneAffinity) {
overrideCounter.increment();
}
}
return servers;
}
DefaultNIWSServerListFilter完全继承ZoneAffinityServerListFilter
netfix默认使用该过滤器
ServerListSubsetFilter,继承于ZoneAffinityServerListFilter,通常用在大规模服务器集群
他除了区域感知之外,还能对剩下的服务实例进行筛选,剔除相对不够健康的实例
ZonePreferenceServerListFilter继承于ZoneAffinityServerListFilter,springCloud默认使用的过滤器
对原server进行包装,将eureka实例元数据中的zone设置到server中
@Override
public List<Server> getFilteredListOfServers(List<Server> servers) {
//先使用父类ZoneAffinityServerListFilter进行过滤
List<Server> output = super.getFilteredListOfServers(servers);
//将结果再按照zone进行过滤,只保留zone相同的实例
if (this.zone != null && output.size() == servers.size()) {
List<Server> local = new ArrayList<>();
for (Server server : output) {
if (this.zone.equalsIgnoreCase(server.getZone())) {
local.add(server);
}
}
if (!local.isEmpty()) {
return local;
}
}
return output;
}
//扩展netflix原有的server
class DomainExtractingServer extends DiscoveryEnabledServer {
public DomainExtractingServer(DiscoveryEnabledServer server, boolean useSecurePort,
boolean useIpAddr, boolean approximateZoneFromHostname) {
// host and port are set in super()
super(server.getInstanceInfo(), useSecurePort, useIpAddr);
//从eureka服务实例的元对象中获取zone值放入server中
if (server.getInstanceInfo().getMetadata().containsKey("zone")) {
setZone(server.getInstanceInfo().getMetadata().get("zone"));
}
else if (approximateZoneFromHostname) {
setZone(ZoneUtils.extractApproximateZone(server.getHost()));
}
else {
setZone(server.getZone());
}
setId(extractId(server));
setAlive(server.isAlive());
setReadyToServe(server.isReadyToServe());
}
配置写法
##设定自己是北京的服务器
eureka.instance.metadata-map.zone=beijing
ZoneAwareLoadBalancer
ZoneAwareLoadBalancer继承于DynamicServerListLoadBalancer
BaseLoadBalancer中的chooseServer使用的规则是RoundRobinRule轮询,这样可能会产生周期性的跨区域访问,ZoneAwareLoadBalancer就是解决这个问题,加入了区域感知的规则
@Override
//DynamicServerListLoadBalancer.java
//更新serverList后将所有的server按照key=zone value=List<Server>组装成map
protected void setServerListForZones(
Map<String, List<Server>> zoneServersMap) {
LOGGER.debug("Setting server list for zones: {}", zoneServersMap);
//将这个组装好的map跟新到LoadBalancerStats中
getLoadBalancerStats().updateZoneServerMapping(zoneServersMap);
}
private ConcurrentHashMap<String, BaseLoadBalancer> balancers = new ConcurrentHashMap<String, BaseLoadBalancer>();
//ZoneAwareLoadBalancer.java
//重写了这个方法,在调用父类方法之后自己组装了一个balancers,每个zone单独创建一个BaseLoadBalancer,并且将该zone的serverList集合放入到相对应的BaseLoadBalancer中
protected void setServerListForZones(Map<String, List<Server>> zoneServersMap) {
super.setServerListForZones(zoneServersMap);
if (balancers == null) {
balancers = new ConcurrentHashMap<String, BaseLoadBalancer>();
}
for (Map.Entry<String, List<Server>> entry: zoneServersMap.entrySet()) {
String zone = entry.getKey().toLowerCase();
getLoadBalancer(zone).setServersList(entry.getValue());
}
//这里做一个校验,去除那些失效的zone
for (Map.Entry<String, BaseLoadBalancer> existingLBEntry: balancers.entrySet()) {
if (!zoneServersMap.keySet().contains(existingLBEntry.getKey())) {
existingLBEntry.getValue().setServersList(Collections.emptyList());
}
}
}
//这里重写了 BaseLoadBalancer的chooseServer方法
@Override
public Server chooseServer(Object key) {
//如果可用的zone不大于1,则直接调用默认的chooseServer
if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
logger.debug("Zone aware logic disabled or there is only one zone");
return super.chooseServer(key);
}
Server server = null;
try {
//这一段的逻辑是通过ZoneAvoidanceRule来进行zone可用性的判断
//判断的依据是根据负载的阙值默认为小于0.2、断路器开关次数/实例总数小于0.99999
LoadBalancerStats lbStats = getLoadBalancerStats();
Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
logger.debug("Zone snapshots: {}", zoneSnapshot);
if (triggeringLoad == null) {
triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
"ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
}
if (triggeringBlackoutPercentage == null) {
triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
"ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
}
Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
logger.debug("Available zones: {}", availableZones);
//成功筛选出一个zone,通过balancers获取相应的BaseLoadBalancer进行chooseServer
if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
logger.debug("Zone chosen: {}", zone);
if (zone != null) {
BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
server = zoneLoadBalancer.chooseServer(key);
}
}
} catch (Exception e) {
logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);
}
if (server != null) {
return server;
} else {
logger.debug("Zone avoidance logic is not invoked.");
//否则调用父类默认的chooseServer
return super.chooseServer(key);
}
}
IRule
AbstractLoadBalancerRule
抽象类,定义了获取ILoadBalancer
RandomRule
随机获取一个服务实例
RoundRobinRule
轮询
RetryRule
本质上还是RandomRule,内部维护了一个RoundRobinRule,默认在500M内进行循环尝试,最终获得Server或者返回null
WeightedResponseTimeRule
根据服务实例的响应时间计算权重区间,区间越大选取的概率就越大
区间宽度 = 所有实例的总响应时间 - 该实例的平均响应时间
ClientConfigEnabledRoundRobinRule
一个基类,内部定义了RoundRobinRule,方便子类在备选方案上可以调用
BestAvailableRule
继承ClientConfigEnabledRoundRobinRule,注入LoadBalancerStats
通过LoadBalancerStats过滤故障的实例,然后选择最小并发量的实例
PredicateBasedRule
抽象类,基于google的Predicate类实现了一个过滤器,方便子类制定过滤规则,过滤后的服务实例再通过轮询获取
AvailabilityFilteringRule
继承PredicateBasedRule,实现了一个过滤规则
过滤断路器已生效的实例,过滤并发请求数大于阙值的实例 默认是Integer.MAX
ZoneAvoidanceRule
继承PredicateBasedRule 先进行可用zone的过滤再执行availabilityPredicate的过滤
ribbon配置项
<clientName>.ribbon.NFLoadBalancerClassName: Should implement ILoadBalancer
<clientName>.ribbon.NFLoadBalancerRuleClassName: Should implement IRule
<clientName>.ribbon.NFLoadBalancerPingClassName: Should implement IPing
<clientName>.ribbon.NIWSServerListClassName: Should implement ServerList
<clientName>.ribbon.NIWSServerListFilterClassName: Should implement ServerListFilter
实例
users:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
在使用了eureka的前提下 springCloud 已经帮我们默认配置好了合适的接口实现类
@Configuration
public class EurekaRibbonClientConfiguration {
//com.netflix.niws.loadbalancer.NIWSDiscoveryPing
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
return this.propertiesFactory.get(IPing.class, config, serviceId);
}
NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
ping.initWithNiwsConfig(config);
return ping;
}
//org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
return this.propertiesFactory.get(ServerList.class, config, serviceId);
}
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
config, eurekaClientProvider);
DomainExtractingServerList serverList = new DomainExtractingServerList(
discoveryServerList, config, this.approximateZoneFromHostname);
return serverList;
}
}
@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
//com.netflix.loadbalancer.ZoneAvoidanceRule
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, name)) {
return this.propertiesFactory.get(IRule.class, config, name);
}
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
//com.netflix.loadbalancer.ZoneAwareLoadBalancer
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
//org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
return this.propertiesFactory.get(ServerListFilter.class, config, name);
}
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.initWithNiwsConfig(config);
return filter;
}
}
如果需要替换这些默认的实现类 只要在application.properties定义即可 或者直接定义自己的bean
springCloud 重试机制配置
ribbon 所有的配置在 CommonClientConfigKey类
##开启重试机制,默认是开启的
spring.cloud.loadbalancer.retry.enabled=true
# 对同样的server最多进行一次重试,除掉最开始的访问
sample-client.ribbon.MaxAutoRetries=1
# 最多切换一次服务重试
sample-client.ribbon.MaxAutoRetriesNextServer=1
# 默认情况只对get资源进行重试,如果配置了该项,则对post等请求也会重试
sample-client.ribbon.OkToRetryOnAllOperations=true
# 请求连接超时,默认2秒
sample-client.ribbon.ConnectTimeout=3000
# 请求处理超时,默认5秒
sample-client.ribbon.ReadTimeout=3000