一個好的程序員是那種過單行線馬路都要往兩邊看的人。
–> 返回專欄總目錄 <–
代碼下載地址: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