微服务架构之均衡组件 Ribbon解析:IPing与server列表
IPing
IPing
是Ribbon
用来定义检查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
也会判断服务是否可用,所以直接使用Eureka
的DiscoveryEnabledServer
对象的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
Ribbon
的ServerList
是定义生成server列表的接口,用来通过各种途径获取负载均衡中的所有server列表。
public interface ServerList<T extends Server> {
public List<T> getInitialListOfServers();
/**
* 更新服务器列表,Loadbalancer Ping周期每30sec会调用该函数一次。
*/
public List<T> getUpdatedListOfServers();
}
在RibbonClientConfiguration
中默认配置的ServerList
是ConfigurationBasedServerList
。它是通过配置文件中的listOfServers
属性来获取所有的服务器列表的。
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;
}
DomainExtractingServerList
的getInitialListOfServers
的实现十分简单,就是直接返回从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
,RestClient
和ServerListFilter
等。
- 点赞
- 收藏
- 关注作者
评论(0)