Diagram + source code to explain how Ribbon obtains an example of the registry

Get into the habit of writing together! This is the 12th day of my participation in the "Nuggets Daily New Plan·April Update Challenge", click to view the details of the event

Diagram + source code to explain how Ribbon obtains an example of the registry

Action is the ladder of success, the more action, the higher

Imagine where to start

    In fact, we have said before that the load balancer selects a service that can be used from the obtained registry. If I use the Eureka registry, the registry should also be obtained through the client of the registry, then we will See if there is a clue where the load balancer initialization is taking place

Get the configuration flowchart

image.png

Ribbon client configuration class

    RibbonClientConfiguration Client configuration class, look at what is initialized here, look at the main logic part, which creates routing rules, ping rules, service lists, service list updaters, load balancer creation, filters and contexts, etc. Wait

public class RibbonClientConfiguration {
    // 连接超时时间
	public static final int DEFAULT_CONNECT_TIMEOUT = 1000;
	// 读取超时时间
	public static final int DEFAULT_READ_TIMEOUT = 1000;
	@RibbonClientName
	private String name = "client";
    // ribbon 客户端配置
	@Bean
	@ConditionalOnMissingBean
	public IClientConfig ribbonClientConfig() {
	    ....
	}
    // ribbon 路由规则
	@Bean
	@ConditionalOnMissingBean
	public IRule ribbonRule(IClientConfig config) {
	    ....
	}
    // 路由 ping 操作
	@Bean
	@ConditionalOnMissingBean
	public IPing ribbonPing(IClientConfig config) {
	     ....
	}
    // ribbon 服务列表
	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerList<Server> ribbonServerList(IClientConfig config) {
		 ....
	}
    // ribbon 服务列表更新器
	@Bean
	@ConditionalOnMissingBean
	public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
		....
	}
    // 负载均衡器
	@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);
	}
    // 服务列表过滤器
	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
		....
	}
    // ribbon 负载均衡上下文
	@Bean
	@ConditionalOnMissingBean
	public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer,
			IClientConfig config, RetryHandler retryHandler) {
		 ....
	}
    // 重试处理器
	@Bean
	@ConditionalOnMissingBean
	public RetryHandler retryHandler(IClientConfig config) {
		....
	}

}
复制代码

Create load balancer ribbonLoadBalancer

    The ribbonLoadBalancer is constructed according to the parameters initialized by other methods. There are Rule rules, Ping mechanism, and parameters such as the service address you want to access. The actual load balancer created is ZoneAwareLoadBalancer by default.

@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);
}
复制代码

Default load balancer ZoneAwareLoadBalancer

    This load balancer inherits the DynamicServerListLoadBalancer dynamic service list load balancer, which is the load balancer we need at a glance

public ZoneAwareLoadBalancer(IClientConfig clientConfig, IRule rule,
                             IPing ping, ServerList<T> serverList,
                             ServerListFilter<T> filter,
                             ServerListUpdater serverListUpdater) {
    super(clientConfig, rule, ping, serverList, filter, serverListUpdater);
}
复制代码

    The super method here is the method in **DynamicServerListLoadBalancer**

Dynamic Service List Load Balancer DynamicServerListLoadBalancer

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());
    }
    // 核心方法,其他的方法先不细看
    restOfInit(clientConfig);
}
复制代码

restOfInit method

    This method is the real operation of obtaining the list of service instances, and enabling subsequent operations such as pushing new instance change information from the registry or pulling instance changes.

void restOfInit(IClientConfig clientConfig) {
    boolean primeConnection = this.isEnablePrimingConnections();
    // 开启并且初始化加载新的服务实例,比如注册中心推送或者拉取操作,后面讲解
    enableAndInitLearnNewServersFeature();
    // 获取服务列表操作
    updateListOfServers();
    ......
}
复制代码

Update service list updateListOfServers()

@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);
    }
    // 更新LoadBalancer中的所有服务列表
    updateAllServerList(servers);
}
复制代码

Get the list of update services getUpdatedListOfServers()

    It is the getUpdatedListOfServers() operation under the DiscoveryEnabledNIWSServerList class, which is the service list of the registry.
image.png

@Override
public List<DiscoveryEnabledServer> getUpdatedListOfServers(){
    // 获得服务方法
    return obtainServersViaDiscovery();
}
复制代码

get service discovery list obtainServersViaDiscovery

private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {
    List<DiscoveryEnabledServer> serverList = new ArrayList<DiscoveryEnabledServer>();
    // 如果客户端为提供者为空的话那么就返回一个空的列表
    if (eurekaClientProvider == null || eurekaClientProvider.get() == null) {
        logger.warn("EurekaClient has not been initialized yet,
                    returning an empty list");
        return new ArrayList<DiscoveryEnabledServer>();
    }
    // 获取 eureka 客户端操作
    EurekaClient eurekaClient = eurekaClientProvider.get();
    // 服务地址不为空的情况下
    if (vipAddresses!=null){
        for (String vipAddress : vipAddresses.split(",")) {
            // 通过 eureka 客户端获取服务实例操作
        List<InstanceInfo> listOfInstanceInfo = 
            eurekaClient.getInstancesByVipAddress(vipAddress, isSecure, targetRegion);
        for (InstanceInfo ii : listOfInstanceInfo) {
                // 服务实例必须是启动状态的或者正常状态的
            if (ii.getStatus().equals(InstanceStatus.UP)) {
                // 创建服务操作,加入到服务列表中
                DiscoveryEnabledServer des = 
                    createServer(ii, isSecure, shouldUseIpAddr);
                serverList.add(des);
                }
            }
        }
    }
    // 返回服务列表
    return serverList;
}
复制代码

image.png

Update the list of all services in LoadBalancer updateAllServerList(servers)

protected void updateAllServerList(List<T> ls) {
    if (serverListUpdateInProgress.compareAndSet(false, true)) {
        try {
            for (T s : ls) {
                s.setAlive(true); 
            }
            setServersList(ls);
            // ping 服务后期讲解
            super.forceQuickPing();
        } finally {
            serverListUpdateInProgress.set(false);
        }
    }
}
复制代码

set service list setServersList

    The instance of the service list obtained by the service client is put into allServerList of BaseLoadBalancer, and the instance of the service list obtained by the client is put into the haspMap of serversInZones

@Override
public void setServersList(List lsrv) {
    // 将服务客户端获取的服务列表实例放入到 BaseLoadBalancer 的 allServerList 中
    super.setServersList(lsrv);
    // 下面是将客户端获取的服务列表实例放入到 serversInZones 这个haspMap中
    List<T> serverList = (List<T>) lsrv;
    Map<String, List<Server>> serversInZones = new HashMap<String, List<Server>>();
    for (Server server : serverList) {
        getLoadBalancerStats().getSingleServerStat(server);
        String zone = server.getZone();
        if (zone != null) {
            zone = zone.toLowerCase();
            List<Server> servers = serversInZones.get(zone);
            if (servers == null) {
                servers = new ArrayList<Server>();
                serversInZones.put(zone, servers);
            }
            servers.add(server);
        }
    }
    setServerListForZones(serversInZones);
}
复制代码

summary

  1. Create some necessary prerequisite components, such as ZoneAwareLoadBalancer, PollingServerListUpdater and other operations
  2. Get the list of services through the eureka client client component
  3. Update the service list inside the load balancer according to the obtained service list information

Guess you like

Origin juejin.im/post/7085520967547486221