Back to Javatutorial

SpringCloudRibbon源码分析

docs/Spring全家桶/SpringCloud源码分析/SpringCloudRibbon源码分析.md

1.0.024.8 KB
Original Source

ѧϰĿ

  1. ƵRibbonĺ
  2. дһװRibbon
  3. ͨԴ֤Ƶ 1 Ƶ ʵRibbonĺ̺ܼ򵥣ʹù޷Ǿһspring-cloud-starter-netflix-ribbonjarȻڳʱעһRestTemplateڸöһ@LoadBalancedע⣬ȻͨRestTemplateȥURLʱܸݲͬĸؾȥͬķע⣬˵jarʲôأ

Ҫףspring-cloud-starter-netflix-ribbonjar֪ǻstarterģ϶springbootԶװԭʱṩһԶ࣬ҪõĶע뵽IoCȥˣӹɡ

ȻҪRestTemplateȥĿʱʱǿ϶ҪʵIPͶ˿滻һʵǺIJ裬Ҫôأô֮ǰַͶ˿è̫ӻʵأ

ճУӦ֪һһʵ԰ɣԣʵϾڻȡRestTemplateʱ򣬽öһRestTemplateִijʱ򣬶ȥִһ顣Ȼˡ

ͼƵ£2 װRibbonʵ Ƶ̣ǽʵһװRibbon

IJҪ˼·

1.ҪʵһstarterspringbootspringbootʱõӦRestTemplatebean󡣴һMavenquickstartĿ

2.Ȼ

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  myribbon-spring-cloud-starter
  <version>1.0-SNAPSHOT</version>

  <name>myribbon-spring-cloud-starter</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring-boot.version>2.3.2.RELEASE</spring-boot.version>
  </properties>

  <!-- RestTemplateҪõSpringMVC -->
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      spring-boot-starter-web
      <version>${spring-boot.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      spring-boot-starter-test
      <version>${spring-boot.version}</version>
    </dependency>

    <!-- 漯һЩĽӿ -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      spring-cloud-commons
      <version>2.2.6.RELEASE</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          maven-clean-plugin
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          maven-resources-plugin
          <version>3.0.2</version>
        </plugin>
        <plugin>
          maven-compiler-plugin
          <version>3.8.0</version>
        </plugin>
        <plugin>
          maven-surefire-plugin
          <version>2.22.1</version>
        </plugin>
        <plugin>
          maven-jar-plugin
          <version>3.0.2</version>
        </plugin>
        <plugin>
          maven-install-plugin
          <version>2.5.2</version>
        </plugin>
        <plugin>
          maven-deploy-plugin
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          maven-site-plugin
          <version>3.7.1</version>
        </plugin>
        <plugin>
          maven-project-info-reports-plugin
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
@Configuration
public class MyRibbonAutoConfiguration {
    //װRibbonǿȥɸؾ㷨ԼʵipͶ˿滻
    @Bean
    public LoadBalancerClient loadBalancerClient(){
        return new MyLoadBalancerClient();
    }
    //ռдMyLoadBalancedעRestTemplate
    @MyLoadBalanced
    @Autowired(required = false)
    private List<RestTemplate> restTemplates = Collections.emptyList();
    @Bean
    @ConditionalOnMissingBean
    public LoadBalancerRequestFactory loadBalancerRequestFactory(
            LoadBalancerClient loadBalancerClient) {
        return new LoadBalancerRequestFactory(loadBalancerClient);
    }
    //Ǻĵ
    @Bean
    public MyLoadBalancerInterceptor myLoadBalancerInterceptor(
            LoadBalancerClient loadBalancerClient,
            LoadBalancerRequestFactory requestFactory){
        return new MyLoadBalancerInterceptor(loadBalancerClient,requestFactory);
    }
    //ռRestTemplateﶼһ
    @Bean
    public SmartInitializingSingleton smartInitializingSingleton(
            final MyLoadBalancerInterceptor myLoadBalancerInterceptor){
        return ()->{
            for (RestTemplate restTemplate : MyRibbonAutoConfiguration.this.restTemplates) {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(myLoadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            }
        };
    }
}

4.MyLoadBalancerClient

public class MyLoadBalancerClient implements LoadBalancerClient {
    @Autowired
    AbstractEnvironment environment;
    //1.
    @Override
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        ServiceInstance server = this.choose(serviceId);
        return execute(serviceId, server, request);
    }	
    //3.ִHttp
    @Override
    public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
        T returnVal = null;
        try {
            returnVal = request.apply(serviceInstance);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnVal;
    } 
	//4.һʵipport滻
    @Override
    public URI reconstructURI(ServiceInstance instance, URI original) {
        String host = instance.getHost();
        int port = instance.getPort();
        if (host.equals(original.getHost())
                && port == original.getPort()
                ) {
            return original;
        }
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("http").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 e){
            throw new RuntimeException(e);
        }
    }
    //2.ؾ㷨һзipͶ˿ѡõ㷨
    @Override
    public ServiceInstance choose(String serviceId) {
        Server instance = new Server(serviceId,null,"127.0.0.1",8080);
        String sr = environment.getProperty(serviceId+".ribbon.listOfServers");
        if (!StringUtils.isEmpty(sr)){
            String[] arr = sr.split(",",-1);
            Random selector = new Random();
            int next = selector.nextInt(arr.length);
            String a = arr[next];
            String[] srr = a.split(":",-1);
            instance.setHost(srr[0]);
            instance.setPort(Integer.parseInt(srr[1]));
        }
        return instance;
    }
}

5.߼ʵܼ򵥣http֮ǰִҵ߼

public class MyLoadBalancerInterceptor implements ClientHttpRequestInterceptor {
    private LoadBalancerClient loadBalancerClient;
    private LoadBalancerRequestFactory requestFactory;
    public MyLoadBalancerInterceptor(LoadBalancerClient loadBalancerClient,
                                   LoadBalancerRequestFactory requestFactory) {
        this.loadBalancerClient = loadBalancerClient;
        this.requestFactory = requestFactory;
    }
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        final URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        return this.loadBalancerClient.execute(serviceName,
                this.requestFactory.createRequest(request, body, execution));
    }
}

6.Լע

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface MyLoadBalanced {
}

7.һԼServerʵ

public class Server implements ServiceInstance {
    private String serviceId;
    private String instanceId;
    private String host;
    private int port;
    public Server(String serviceId, String instanceId, String host, int port) {
        this.serviceId = serviceId;
        this.instanceId = instanceId;
        this.host = host;
        this.port = port;
    }
    public Server() {
    }
    public void setServiceId(String serviceId) {
        this.serviceId = serviceId;
    }
    public void setInstanceId(String instanceId) {
        this.instanceId = instanceId;
    }
    public void setHost(String host) {
        this.host = host;
    }
    public void setPort(int port) {
        this.port = port;
    }
    @Override
    public String getInstanceId() {
        return null;
    }
    @Override
    public String getServiceId() {
        return null;
    }
    @Override
    public String getHost() {
        return host;
    }
    @Override
    public int getPort() {
        return port;
    }
    @Override
    public boolean isSecure() {
        return false;
    }
    @Override
    public URI getUri() {
        return null;
    }
    @Override
    public Map<String, String> getMetadata() {
        return null;
    }
    @Override
    public String getScheme() {
        return null;
    }
}

8.дspring.factoriesļ

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.example.config.MyRibbonAutoConfiguration

9.jarԣԵʱҪļ

<serverName>.ribbon.listOfServers=127.0.0.1:2223,127.0.0.1:2222

3 Դ֤ 3.1 @LoadBalanced ϽڿεĴ뿴ֻRestTemplateһ@LoadBalance,Ϳʵָؾˣǵ@LoadBalanceһ£עһ@Qualifierע⡣ע޶ĸbeanӦñԶע롣Spring޷жϳĸbeanӦñעʱ@QualifierעbeanԶע룬Ӽ롣

/**
 * Annotation to mark a RestTemplate or WebClient bean to be configured to use a
 * LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {

}

עп֪עRestTemplateǣʹøؾͻˣLoadBalancerClientԣɵRestTemplatebeanôһע⣬beanͻLoadBalancerClient

3.2 LoadBalancerClient ôٿLoadBalancerClientĴ룺

public interface LoadBalancerClient extends ServiceInstanceChooser {
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
	<T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException;
	URI reconstructURI(ServiceInstance instance, URI original);
}
public interface ServiceInstanceChooser {
	ServiceInstance choose(String serviceId);
}

LoadBalancerClientһӿڣ

ServiceInstance choose(String serviceId);ӷϾͿԿǸݴserviceIdӸؾѡһʵʵͨServiceInstanceʾ executeʹôӸؾѡķʵִݡ URI reconstructURI(ServiceInstance instance, URI original);¹һURIģǵڴУͨRestTemplateʱдǷɣͻURIתhost+portͨhost+portʽȥ 3.3 Զװ springboot֮󣬻ͨԶװԶȥ spring-cloud-netflix-ribbonjarMETA-INFĿ¼spring.factoriesļҽRibbonAutoConfigurationע롣RibbonAutoConfigurationΪ@AutoConfigureBeforeע⣬ֻLoadBalancerAutoConfigurationࡣLoadBalancerAutoConfigurationУspringὫб@LoadBalanceעεbeanע뵽IOC

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();

ͬʱLoadBalancerAutoConfigurationлΪÿRestTemplateʵLoadBalancerInterceptor

RibbonAutoConfigurationעLoadBalancerClientӿڵʵRibbonLoadBalancerClient

@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
    return new RibbonLoadBalancerClient(springClientFactory());
}

**3.4 ** ԶУrestTemplateʵLoadBalancerInterceptorԣrestTemplatehttpʱͻִintercept

interceptУrequest.getURI()ȡuriٻȡhostڷhttpʱõķΪhostԣͻõٵþLoadBalancerClientʵexecute

LoadBalancerClientʵΪRibbonLoadBalancerClientյĸؾִУԣҪRibbonLoadBalancerClient߼

ȿRibbonLoadBalancerClientеexecute

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
    throws IOException {
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    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 {
        T returnVal = request.apply(serviceInstance);
        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;
}

ΪserviceIdֶδͨgetLoadBalancerȡloadBalancerٸloadBalancerȡservergetServerĴ룺

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
    if (loadBalancer == null) {
        return null;
    }
    // Use 'default' on a null hint, or just pass it on?
    return loadBalancer.chooseServer(hint != null ? hint : "default");
}

loadBalancerΪգֱӷؿգ͵loadBalancerchooseServerȡӦserver

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

ЩȽֱۣ׾ܲ³ǸɶģaddServersһserverϣchooseServerѡһservermarkServerDownijߣgetReachableServersȡõServerϣgetAllServersǻȡеserverϡ ILoadBalancerкܶʵ֣ǾõĸأRibbonAutoConfigurationעSpringClientFactoryͨRibbonClientConfiguration࿴ڳʼʱ򣬷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);
}

3.5 ZoneAwareLoadBalancer ZoneAwareLoadBalancerпԿؾzoneйϵġ濴ZoneAwareLoadBalancerеchooseServer

eurekaṩregionzoneзѷAWS regionԼΪϵķ޵߻ٻ߱ȵȣûоСơĿкregion zoneԼΪregionڵľ˵regionΪȻ󱱾Ϳڴregion֮»ֳzone1,zone2zone

@Override
public Server chooseServer(Object key) {
    //ֻеؾάʵZoneĸ1ʱŻִѡ
    //ʹøʵ
    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 {
        LoadBalancerStats lbStats = getLoadBalancerStats();
        //ΪǰؾеZoneֱ𴴽գzoneSnapshotУЩеں㷨
        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);
        }
        //ÿZoneļϣgetAvailableZonesͨzoneSnapshotʵֿѡ
        Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
        logger.debug("Available zones: {}", availableZones);
        if (availableZones != null &&  availableZones.size() < zoneSnapshot.keySet().size()) {
            //ѡһZone
            String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
            logger.debug("Zone chosen: {}", zone);
            if (zone != null) {
                //öӦĸؾ
                BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
                //ѡķʵ
                //chooseServerнʹIRuleӿڵchooseѡʵIRuleӿڵʵֻʵZoneAvoidanceRuleѡķʵ
                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.");
        return super.chooseServer(key);
    }
}

serverzoneͿѡʵһServer

ļ

  1. setServerListForZones : Zoneз񻮷
  2. chooseServerҲҪzoneйصļ㣬ȻĬϵZoneֻһֱǵõĸchooseServerkey)
  3. getLoadBalancer(String zone) zoneȥȡLoadBalancer
  4. setRule(IRule rule) Ϊÿؾù ԿʵҪZoneһЩദǽԭͬһķʵٸݵл֡ҲΪܹӦõġ

3.5.1 DynamicServerListLoadBalancer

ZoneAwareLoadBalancerĸ

ఴ˵Ƕ̬طбʹõġмȽҪķ

  1. updateListOfServers:б±ػķб
  2. enableAndInitLearnNewServersFeature:б¶ʱ
  3. :@Monitor

DynamicServerListLoadBalancerĺľǻȡбEurekaĬͨDomainExtractingServerListȡorg.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientConfiguration#ribbonServerListûмEurekaʱ

3.5.2 BaseLoadBalancer

DynamicServerListLoadBalancerĸ

Ĭֵ

  • ĬϵĸؾRoundRobinRule
  • ĬϵPingSerialPingStrategy
  • зʵallServerList
  • ߷ʵupServerList ๹нӦĸؾpingԣpingȴݹ

pingЩʲô

PingTaskΪһ߳񣬾ǶڼǷ񶼴ServerListUpdater»ƲͻribbonԼάһ׷ƣҪΪ˽ͷʧܵĸʡĬʹeurekaʱpingʹõNIWSDiscoveryPingɷ񱣻⡣eureka ServerListUpdaterˢ·биõĶʱ˳ķҾԼдʱҲʹá

ͬһʱִʱ䳬˶ʱڣôһʱһʱûִʱȡҲ˺ܶƣзʵһµĶʱʹõǶǸallServersֻܶдڷping󣬽ͨķnewUpListУͨдupServerListס

ֻһдҲܶpingڼйڶдԭʹá

Ҫ̾ǣ

  1. ȡȫʵб
  2. ʵǷpingServers
  3. ״̬ıķchangedServers
  4. ߵķnewUpList
  5. newUpListֵupServerList ߷ʵб

pingServersǼ

BaseLoadBalancerܼ

  1. allServerListupServerListĶд
  2. ṩallServerListupServerListɾĹ
  3. ṩPingTaskpingĶʱ񣩣Pingerpingִ
  4. ڸؾѡrule.choose(key)
  5. ṩĬϵpingSerialPingStrategy 3.6 LoadBalancerRequest ͨZoneAwareLoadBalancerѡServerٰ֮װRibbonServer֮ǰصserverǸöеһֶΣ֮⣬зserviceIdǷҪʹhttpsϢͨLoadBalancerRequestapplyserver󣬴Ӷʵ˸ؾ⡣

applyĶ壺

public interface LoadBalancerRequest<T> {
    T apply(ServiceInstance instance) throws Exception;
}

ʱribbonServer󣬱ServiceInstance͵ĶнաServiceInstanceһӿڣ˷ϵͳУÿʵҪṩϢserviceIdhostportȡ

LoadBalancerRequestһӿڣջͨʵapplyȥִУʵLoadBalancerInterceptorеRibbonLoadBalancerClientexecuteʱһ࣬ͨ鿴LoadBalancerInterceptorĴ뿴

LoadBalancerRequestʱ򣬾дapplyapplyУ½һServiceRequestWrapperڲ࣬УдgetURIgetURIloadBalancerreconstructURIuri

ѾԴ֪RibbonʵָؾˣRestTemplateע⣬ͻLoadBalancerClientĶҲRibbonLoadBalancerClientͬʱ LoadBalancerAutoConfigurationãһLoadBalancerInterceptorõrestTemplateЩrestTemplateLoadBalancerInterceptor

ͨrestTemplateʱͻᾭУͻRibbonLoadBalancerClientеķȡݷͨؾⷽȡʵȻȥʵ

3.7 ȡб ˵Щζиؾģǻи⣬ʵǴEureka Serverϻȡģʵбλȡأô֤ʵбеʵǿõأ

RibbonLoadBalancerClientѡʵʱͨILoadBalancerʵݸؾ㷨ѡʵģҲZoneAwareLoadBalancerchooseServerе߼Ǿ鿴ZoneAwareLoadBalancerļ̳йϵԿͼʾԿILoadBalancerӿڣAbstractLoadBalancer̳ӿڣBaseLoadBalancer̳AbstractLoadBalancer࣬ DynamicServerListLoadBalancer̳BaseLoadBalancerZoneAwareLoadBalancer̳DynamicServerListLoadBalancer

ILoadBalancerӿڵĴѾˣڿAbstractLoadBalancerĴ룺

public abstract class AbstractLoadBalancer implements ILoadBalancer {
    public enum ServerGroup{
        ALL,
        STATUS_UP,
        STATUS_NOT_UP        
    }    
    /**
     * delegate to {@link #chooseServer(Object)} with parameter null.
     */
    public Server chooseServer() {
    	return chooseServer(null);
    }
    /**
     * List of servers that this Loadbalancer knows about
     * 
     * @param serverGroup Servers grouped by status, e.g., {@link ServerGroup#STATUS_UP}
     */
    public abstract List<Server> getServerList(ServerGroup serverGroup);
    /**
     * Obtain LoadBalancer related Statistics
     */
    public abstract LoadBalancerStats getLoadBalancerStats();    
}

һ࣬һö٣󷽷chooseServer

ٿBaseLoadBalancer࣬BaseLoadBalancerǸؾһʵ࣬Կlist

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

Ͽάзʵбά״̬Ϊupʵб һԿBaseLoadBalancerʵֵILoadBalancerӿеķȡõķбͻupServerListأȡеķбͻallServerListء

@Override
public List<Server> getReachableServers() {
    return Collections.unmodifiableList(upServerList);
}
@Override
public List<Server> getAllServers() {
    return Collections.unmodifiableList(allServerList);
}

ٿDynamicServerListLoadBalancerࡣͷϵעͿ֪Զ̬ĻȡбfilterԷбйˡ

DynamicServerListLoadBalancerУܿһServerList͵serverListImplֶΣServerListһӿڣ

public interface ServerList<T extends Server> {
    public List<T> getInitialListOfServers();
    /**
     * Return updated list of servers. This is called say every 30 secs
     * (configurable) by the Loadbalancer's Ping cycle
     * 
     */
    public List<T> getUpdatedListOfServers();   
}

getInitialListOfServersǻȡʼķб getUpdatedListOfServersǻȡµķб ServerListжʵ࣬õĸأ EurekaRibbonClientConfigurationҵRibbonEurekaϵԶ࣬ĿǰûEurekaͨļãԻConfigurationBasedServerListࡣ

ο

https://lijunyi.xyz/docs/SpringCloud/SpringCloud.html#_2-2-x-%E5%88%86%E6%94%AF https://mp.weixin.qq.com/s/2jeovmj77O9Ux96v3A0NtA https://juejin.cn/post/6931922457741770760 https://github.com/D2C-Cai/herring http://c.biancheng.net/springcloud https://github.com/macrozheng/springcloud-learning