🍊 Java学习:社区快速通道
🍊 深入浅出RocketMQ设计思想:深入浅出RocketMQ设计思想
🍊 绝对不一样的职场干货:大厂最佳实践经验指南
📆 最近更新:2023年7月2日
🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!
Ribbon会主动判断服务节点的当前状态,决定是否可作为目标节点,只有当前可用的节点才会作为负载均衡器的目标节点。IPing有以下几个手段:
假如服务节点搭载的服务本身就承载超高并发的情况下,那这种主动出击的IPing策略必然会大大增加服务节点的访问压力。
Ribbon IPing是一个接口,可以通过实现该接口来自定义Ping机制。Ribbon IPing的实现类需要在配置文件或者代码中指定,例如:
#单个服务设置 [service-name]: ribbon: NFLoadBalancerPingClassName: com.netflix.loadbalancer.DummyPing
public class MicroRibbonConfig { @Bean public IPing microIPing() { return new DummyPing(); } } @RibbonClient(name = "micro-service", configuration = MicroRibbonConfig.class) public class RibbonClientConfig { }
Ribbon IPing的作用是保证负载均衡器只选择可用的服务节点,提高系统的可靠性和性能。Ribbon IPing与Eureka结合使用时,可以实现自动化的服务发现和健康检查。
在Ribbon这里,时间和空间经常要被换来换去,时间代表着接口响应时间(RT,Response Time),空间表示服务器的可用连接数。
在Ribbon里有两个和时间与空间密切相关的负载均衡策略,BestAvailableRule(简称BA)和WeightedResponseTimeRule。他们都会选择压力较小的服务节点,但这两个策略的方向不同。BA会根据服务节点过去一段时间的请求数,选择并发量最小的机器(选择空间);WRT则是根据响应时间的统计结果,选择响应时间最快的服务(选择时间)。
总结一下就是轻量级接口选空间(BestAvailableRule)、重量级接口选时间(WeightedResponseTimeRule)
IPing接口的定义如下:
public interface IPing { public boolean isAlive(Server server); }
看一下它的几个实现类:
public class DummyPing extends AbstractLoadBalancerPing { public DummyPing() { } public boolean isAlive(Server server) { return true; } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } }
什么都没发生,直接返回true
public class NoOpPing implements IPing { @Override public boolean isAlive(Server server) { return true; } }
也是直接返回true
PingUrl的内容比较丰富,关注一下isAlive方法:
public boolean isAlive(Server server) { String urlStr = ""; if (this.isSecure) { urlStr = "https://"; } else { urlStr = "http://"; } urlStr = urlStr + server.getId(); urlStr = urlStr + this.getPingAppendString(); boolean isAlive = false; HttpClient httpClient = new DefaultHttpClient(); HttpUriRequest getRequest = new HttpGet(urlStr); String content = null; try { HttpResponse response = httpClient.execute(getRequest); content = EntityUtils.toString(response.getEntity()); isAlive = response.getStatusLine().getStatusCode() == 200; if (this.getExpectedContent() != null) { LOGGER.debug("content:" + content); if (content == null) { isAlive = false; } else if (content.equals(this.getExpectedContent())) { isAlive = true; } else { isAlive = false; } } } catch (IOException var11) { var11.printStackTrace(); } finally { getRequest.abort(); } return isAlive; }
如果是安全协议则使用https,不是安全的则使用http,拼接的时候先加上一个server.getId(),再加上一个this.getPingAppendString()
HttpClient httpClient = new DefaultHttpClient(); HttpUriRequest getRequest = new HttpGet(urlStr);
构造一个http请求来判断是否是up状态
if (this.getExpectedContent() != null)
如果有返回的期望值,则需要实际返回的数据等于期望值才证明是服务节点是up的
NIWSDiscoveryPing实现类:
public boolean isAlive(Server server) { boolean isAlive = true; if (server!=null && server instanceof DiscoveryEnabledServer){ DiscoveryEnabledServer dServer = (DiscoveryEnabledServer)server; InstanceInfo instanceInfo = dServer.getInstanceInfo(); if (instanceInfo!=null){ InstanceStatus status = instanceInfo.getStatus(); if (status!=null){ isAlive = status.equals(InstanceStatus.UP); } } } return isAlive; }
只有server的类型是DiscoveryEnabledServer才将其转换成自己需要的类型,然后获得instanceInfo。
这里InstanceStatus是依靠eureka的服务发现从服务注册中心拉取到的,服务发现并不能即使反映所有服务器的状态变化,因为是客户端发起的,所以有延迟。