一个好的程序员是那种过单行线马路都要往两边看的人。
–> 返回专栏总目录 <–
代码下载地址:https://github.com/f641385712/netflix-learning
前言
Ribbon
作为客户端负载均衡器,有一个必要的基础条件就获取到ServerList
服务器列表,以及后续的动态更新服务列表。通过前面学习知道,服务列表它可以来自任何地方,比如默认实现ConfigurationBasedServerList
它表示服务列表可以来自于配置(文件)。实际生产中,我们不可能把ServerList地址写死在配置里,实际的方式是把Ribbon同注册中心整合从而从注册中心里获取到列表,并且动态的去sync服务列表,本文“A哥”就带你领略一番。
服务注册中心有多种,本文将讲述它和自家产品Eureka做整合,以Eureka为代表进行说明即可,其它的举一反三。另需要说明的是:虽说eureka1.x
目前也已经处在停更维护状态,但在Spring Cloud
体系注册中心方面它依旧坚挺。为了便于整合,Ribbon官方提供了专门的整合工程:ribbon-eureka
(基于Eureka 1.x)。
在阅读本文之前,建议/要求你已对Eureka有一定的认识了。关于Netflix各组件的学习,A哥非常用心的专门汇总了一篇文章,供以参考:Netflix OSS套件一站式学习驿站
正文
该工程是Ribbon旗下的一个子模块,所以GAV和Ribbon保持一致:
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-eureka</artifactId>
<version>2.3.0</version>
</dependency>
它的间接依赖截图如下:
说明:关于版本的使用上,请参照本专栏第一篇文章的版本声明部分,详细介绍了为何本系列依旧使用2.3.0版本。Eureka版本我们是可以单独升级的,本处约定使用其1.9.13
版本(保持和Spring Cloud Hoxton.SR1
版本内置的Eureka版本一致)。
因为
ribbon-eureka
仅依赖Eureka的核心API,因此只要大版本号不变,核心API必定是向下兼容的
为何Ribbon需要Eureka?
Ribbon 维护了一个服务器列表,如果服务器有宕机现象,Ribbon 能够自行将其剔除(内部有探活机制),没毛病;但如果该服务器故障排除,重新启动,或者增加新的负载节点,那么我们需要手工调用 Ribbon 的接口将其动态添加/移除进Ribbon 的服务器列表才能正常work,这样明显不够尽如人意。
我们想,如何能够在服务节点启动时,自行动态的添加/减少服务列表呢?答案那就是注册中心,也就是本文要说的Eureka。Eureka 提供了 Application Service 客户端的自行注册的功能。此外,Eureka 的缓存机制能够防止大规模宕机带来的灾难性后果。因此Ribbon和它整合,便可以让本地服务列表实现动态化。
Eureka和Ribbon因为都是Netflix自家产品,所以整合起来是比较方便的。若你想整合其它注册中心,可以使用其它相关整合包
ribbon-eureka工程详解
该整合工程由Netflix官方提供,是Ribbon主动去整合Eureka的(从命名上你也能看得到主次)。ribbon-eureka
这个工程的内容并不多,截图如下:
针对这个工程的详解,主要会分两大部分展开:
- 工程内各类的源码解释
- 手工代码示例,领略Ribbon整合Eureka后是如何工作的
DiscoveryEnabledServer:扩展Server实现
它扩展自Server,代表该实例来自于注册中心(服务发现),所以它额外扩展了包含InstanceInfo
形式的元数据。
说明:
InstanceInfo
是eureka里面的一个实例info信息,包含如:instanceId、appName、appGroupName、ipAddr、port、securePort、homePageUrl、healthCheckUrl...
非常非常多的属性
public class DiscoveryEnabledServer extends Server{
private final InstanceInfo instanceInfo;
// com.netflix.loadbalancer.Server.MetaInfo服务元信息,基础数据均来自于InstanceInfo
private final MetaInfo serviceInfo;
// 构造器:通过InstanceInfo构造出一个DiscoveryEnabledServer实例
public DiscoveryEnabledServer(final InstanceInfo instanceInfo, boolean useSecurePort) {
this(instanceInfo, useSecurePort, false);
}
// useIpAddr:是否使用IP地址
public DiscoveryEnabledServer(final InstanceInfo instanceInfo, boolean useSecurePort, boolean useIpAddr) {
// 如果允许使用ip地址,并且判断该注册中心实例的port的是允许的,那就设置上
if(useSecurePort && instanceInfo.isPortEnabled(PortType.SECURE)) {
super.setPort(instanceInfo.getSecurePort());
}
this.instanceInfo = instanceInfo;
// MetaInfo的实现,全部委托给instanceInfo实例信息
this.serviceInfo = new MetaInfo() {
...
@Override
public String getAppName() {
return instanceInfo.getAppName();
}
@Override
public String getServiceIdForDiscovery() {
return instanceInfo.getVIPAddress();
}
...
};
}
// 属性get方法
public InstanceInfo getInstanceInfo() {
return instanceInfo;
}
// 这可是复写了父类的方法哦
// 父类的MetaInfo实现几乎为空实现:大都返回null
@Override
public MetaInfo getMetaInfo() {
return serviceInfo;
}
}
该Server实例的ip、端口等其它信息均来自于注册中心的实例info:InstanceInfo
,因此对Eureka中的InstanceInfo
的理解就显得很有必要,还好我有准备,请参考:Eureka的最核心概念:InstanceInfo实例信息
LegacyEurekaClientProvider
Legacy
:遗赠,遗产。
一个通过静态方法,单例模式提供EurekaClient的遗留类,不建议再使用。
class LegacyEurekaClientProvider implements Provider<EurekaClient> {
private volatile EurekaClient eurekaClient;
@Override
public synchronized EurekaClient get() {
if (eurekaClient == null) {
eurekaClient = DiscoveryManager.getInstance().getDiscoveryClient();
}
return eurekaClient;
}
}
因为DiscoveryManager
已经被标记为@Deprecated
,自然而然的本(工具)类也就不再推使用了(容易出错)。
NIWSDiscoveryPing:通过实例状态探活
对于IPing
接口,Ribbon内置的几个实现如NoOpPing、DummyPing
等其实均没有实际意义,空实现而已(永远返回true)。而对于本处集成了Eureka注册中心的话,定时ping这个动作显得就非常的有意义了。
本处给的实现,就是一个结合注册中心实例状态来实现探活的:
public class NIWSDiscoveryPing extends AbstractLoadBalancerPing {
@Override
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;
}
...
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
它并不会进行远成访问。Server的活与否,完全由注册中心(本地)实例InstanceInfo.status
属性来决定:
InstanceStatus.UP
状态表示Server是活着的(isAlive=true)- 其它状态如
InstanceStatus.DOWN/STARTING/OUT_OF_SERVICE/UNKNOWN
都会认为Server已死(暂时不可用),从而最终就会被T出去
还记得IPing多久执行一次吗?
突然被灵魂拷问的感觉有木有,这在前面讲IPing
这个组件的时候可没少啰嗦,这里只是“复习”一下。答案是:30s(默认值),详见BaseLoadBalancer#PingTask
。
当然喽:此值必须是可配置的啊。通过
ribbon.NFLoadBalancerPingInterval = xxx
来指定,单位秒。
DefaultNIWSServerListFilter:具有区域意识的服务过滤器
默认的NIWS筛选器——处理基于zone区域关联性和其他相关属性的筛选服务器。
public class DefaultNIWSServerListFilter<T extends Server> extends ZoneAffinityServerListFilter<T> {
}
直接继承自ZoneAffinityServerListFilter
的“空”实现,关于它的讲解前面A哥也没少啰嗦。
总结
关于Ribbon和Eureka的整合第一部分就先讲解到这,你会发现ribbon-eureka工程还有两个API没有涉及到,因为那哥俩才是重头戏,为了分离关注,A哥把它放在了下篇文章单独、重点叙述,请您移步。
声明
- 原创不易,码字更不易,你的【三连】是对A哥的最大支持
- 欢迎关注公众号【BAT的乌托邦】(知识星球同名),亦可
扫码 / wx号:fsx641385712
加A哥好友,邀你加入Java高工、架构师系列纯纯纯技术群 - 本号所有“享学xxx”系列文章/视频,和什么“享学课堂”、“享学科技”无任何关系。只因笔者名字和其重名,仅此而已
- [享学Ribbon] 一、源生Ribbon介绍 — 客户端负载均衡器
- [享学Ribbon] 二、Ribbon核心API源码解析:ribbon-core(一)IClient请求客户端
- [享学Ribbon] 三、Ribbon核心API源码解析:ribbon-core(二)IClientConfig配置详解
- [享学Ribbon] 四、Ribbon核心API源码解析:ribbon-core(三)RetryHandler重试处理器
- [享学Ribbon] 五、Ribbon核心API源码解析:ribbon-core(四)ClientException及常用工具
- [享学Ribbon] 六、Ribbon的LoadBalancer五大组件之:IPing心跳检测
- [享学Ribbon] 七、Ribbon的LoadBalancer五大组件之:ServerList服务列表
- [享学Ribbon] 八、netflix-statistics详解,手把手教你写个超简版监控系统
- [享学Ribbon] 九、Ribbon服务器状态:ServerStats及其断路器原理
- [享学Ribbon] 十、Ribbon负载均衡策略服务器状态总控:LoadBalancerStats
- [享学Ribbon] 十一、Ribbon多区域选择:ZoneAvoidanceRule.getAvailableZones()获取可用区
- [享学Ribbon] 十二、Ribbon服务器过滤逻辑的基础组件:AbstractServerPredicate
- [享学Ribbon] 十三、Ribbon的LoadBalancer五大组件之:ServerListFilter服务列表过滤器
- [享学Ribbon] 十四、Ribbon的LoadBalancer五大组件之:ServerListUpdater服务列表更新器
- [享学Ribbon] 十五、Ribbon的LoadBalancer五大组件之:IRule(一)轮询和加权轮询
- [享学Ribbon] 十六、Ribbon的LoadBalancer五大组件之:IRule(二)应用于大规模集群的可配置规则
- [享学Ribbon] 十七、Ribbon的LoadBalancer五大组件之:IRule(三)随机和重试,所有IRule实现总结
- [享学Ribbon] 十八、Ribbon启动连接操作:IPrimeConnection检测Server是否能够提供服务
- [享学Ribbon] 十九、Ribbon负载均衡器执行上下文:LoadBalancerContext
- [享学Ribbon] 二十、Ribbon负载均衡器ILoadBalancer(一):BaseLoadBalancer
- [享学Ribbon] 二十一、Ribbon负载均衡器ILoadBalancer(二):ZoneAwareLoadBalancer具备区域意识、动态服务列表的负载均衡器
- [享学Ribbon] 二十二、Ribbon负载均衡命令:LoadBalancerCommand(一)基础类打点
- [享学Ribbon] 二十三、Ribbon负载均衡命令:LoadBalancerCommand(二)执行目标请求
- [享学Ribbon] 二十四、Ribbon具有负载均衡能力的客户端:AbstractLoadBalancerAwareClient
转载:https://blog.csdn.net/f641385712/article/details/105031383