微服务架构之均衡组件 Ribbon解析:IPing与server列表

举报
qingting-fly 发表于 2021/08/06 00:13:59 2021/08/06
【摘要】 IPingIPing是Ribbon用来定义检查server是否可用的接口。public interface IPing { //检查server是否可用。 public boolean isAlive(Server server);}Ribbon默认提供IPing接口的实现类是DummyPing。其实它并没有去真正的判断server是否是可用的,而是直接返回了true。publ...

IPing

IPingRibbon用来定义检查server是否可用的接口。

public interface IPing {
    //检查server是否可用。
    public boolean isAlive(Server server);
}

Ribbon默认提供IPing接口的实现类是DummyPing。其实它并没有去真正的判断server是否是可用的,而是直接返回了true。

public class DummyPing extends AbstractLoadBalancerPing {

    public DummyPing() {
    }

    public boolean isAlive(Server server) {
        return true;
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

除了DummyPing之外,Ribbon还提供了常用的http的PingUrl和判断微服务框架内的服务是否存活的NIWSDiscoveryPing,前者通过发送HTTP请求判断服务器是否可用,后者则通过eureka获取的注册服务的信息来判断服务是否可用。

PingUrl会使用HttpClient发送HttpGet请求,通过HttpResponse的状态码来判断服务器是否可用。如果状态码为200,则服务可用,否则就是不可用。

//PingUrl.java 通过Http请求来判断server是否可用
public boolean isAlive(Server server) {
    String urlStr   = "";
    if (isSecure){
        urlStr = "https://";
    }else{
        urlStr = "http://";
    }
    urlStr += server.getId();
    urlStr += getPingAppendString();

    boolean isAlive = false;

    HttpClient httpClient = new DefaultHttpClient();
    HttpUriRequest getRequest = new HttpGet(urlStr);
    String content=null;
    try {
        //发送网络请求查看response code是否为200
        HttpResponse response = httpClient.execute(getRequest);
        content = EntityUtils.toString(response.getEntity());
        isAlive = (response.getStatusLine().getStatusCode() == 200);
        if (getExpectedContent()!=null){
            LOGGER.debug("content:" + content);
            if (content == null){
                isAlive = false;
            }else{
                if (content.equals(getExpectedContent())){
                    isAlive = true;
                }else{
                    isAlive = false;
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        // Release the connection.
        getRequest.abort();
    }

    return isAlive;
}

NIWSDiscoveryPing则利用了服务注册中心Eureka的机制,因为Eureka也会判断服务是否可用,所以直接使用EurekaDiscoveryEnabledServer对象的InstanceStatus来判断服务是否可用。

//NIWSDiscoveryPing.java 微服务框架内的服务存活
public boolean isAlive(Server server) {
    boolean isAlive = true;
    //如果server是DiscoveryEnabledServer的实例,也就是Eureka Client的server实例
    if (server!=null && server instanceof DiscoveryEnabledServer){
        DiscoveryEnabledServer dServer = (DiscoveryEnabledServer)server;	            
        InstanceInfo instanceInfo = dServer.getInstanceInfo();
        //通过InstanceInfo.getStatus来判断server是否可用。
        if (instanceInfo!=null){	                
            InstanceStatus status = instanceInfo.getStatus();
            if (status!=null){
                isAlive = status.equals(InstanceStatus.UP);
            }
        }
    }
    return isAlive;
}

ServerList

RibbonServerList是定义生成server列表的接口,用来通过各种途径获取负载均衡中的所有server列表。

public interface ServerList<T extends Server> {

    public List<T> getInitialListOfServers();

    /**
     * 更新服务器列表,Loadbalancer Ping周期每30sec会调用该函数一次。
     */
    public List<T> getUpdatedListOfServers();   

}

RibbonClientConfiguration中默认配置的ServerListConfigurationBasedServerList。它是通过配置文件中的listOfServers属性来获取所有的服务器列表的。

ConfigurationBasedServerList.png

public class ConfigurationBasedServerList extends AbstractServerList<Server>  {

	private IClientConfig clientConfig;

	@Override
	public List<Server> getInitialListOfServers() {
	    return getUpdatedListOfServers();
	}

	@Override
	public List<Server> getUpdatedListOfServers() {
        //从配置的listOfServers属性中获取到所有的server地址的字符串
        String listOfServers = clientConfig.get(CommonClientConfigKey.ListOfServers);
        //按照逗号来拆分字符串,获得所有的服务器列表
        return derive(listOfServers);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
	    this.clientConfig = clientConfig;
	}

	protected List<Server> derive(String value) {
	    List<Server> list = Lists.newArrayList();
		if (!Strings.isNullOrEmpty(value)) {
			for (String s: value.split(",")) {
				list.add(new Server(s.trim()));
			}
		}
        return list;
	}
}

DomainExtractingServerList类则是从Eureka服务注册中心中获取所有的server列表。EurekaRibbonClientConfiguration是针对Eureka自定义的Ribbon相关的配置类。包括了DomainExtractingServerList和我们之前讲解的NIWSDiscoveryPing

//EurekaRibbonClientConfiguration.java
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
    //设置Eureka所使用的IPing
    if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
        return this.propertiesFactory.get(IPing.class, config, serviceId);
    }
    NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
    ping.initWithNiwsConfig(config);
    return ping;
}

@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);
    }
    //获得DomainExtractingServerList
    DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
            config, eurekaClientProvider);
    DomainExtractingServerList serverList = new DomainExtractingServerList(
            discoveryServerList, config, this.approximateZoneFromHostname);
    return serverList;
}

DomainExtractingServerListgetInitialListOfServers的实现十分简单,就是直接返回从Eureka中获取的服务器列表。

@Override
public List<DiscoveryEnabledServer> getInitialListOfServers() {
    List<DiscoveryEnabledServer> servers = setZones(this.list
            .getInitialListOfServers());
    return servers;
}

@Override
public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
    List<DiscoveryEnabledServer> servers = setZones(this.list
            .getUpdatedListOfServers());
    return servers;
}
//添加zone相关的信息
private List<DiscoveryEnabledServer> setZones(List<DiscoveryEnabledServer> servers) {
    List<DiscoveryEnabledServer> result = new ArrayList<>();
    //判断是否secure和是否使用ip地址
    boolean isSecure = this.clientConfig.getPropertyAsBoolean(
            CommonClientConfigKey.IsSecure, Boolean.TRUE);
    boolean shouldUseIpAddr = this.clientConfig.getPropertyAsBoolean(
            CommonClientConfigKey.UseIPAddrForServer, Boolean.FALSE);
    for (DiscoveryEnabledServer server : servers) {
        result.add(new DomainExtractingServer(server, isSecure, shouldUseIpAddr,
                this.approximateZoneFromHostname));
    }
    return result;
}

通过上面可以了解到,Ribbon的核心思想就是named client,也就是带有名称的Ribbon Client。每个Client由可配置的组件构成,负责一类服务的调用请求。Spring Cloud通过RibbonClientConfiguration为每个named client创建一个ApplicationContext来进行组件装配。这些组件就包括ILoadBalancer,RestClientServerListFilter等。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。