前言
最近項目開始使用到spring cloud作為項目的微服架構(gòu),在開發(fā)中遇
到很多問題,相信很多多人也遇到,寫這篇博客也是談談我關(guān)于spring cloud中的eureka的一些認識,當中有誤的地方還請各位留言指出,多多交流。
首先看看官方對eureka的定義
Eureka是一個基于REST(Representational State Transfer)服務,主要是用于云服務為目的的中間層服務器的負載平衡和故障轉(zhuǎn)移。Eureka還附帶了一個基于java的客戶端組件,Eureka客戶機使得交互與服務更加容易??蛻舳艘灿幸粋€基于循環(huán)負載平衡內(nèi)置的負載均衡器。當然在Netflix中,還提供很多更加能滿足復雜要求的負載均衡器,它們基于交通、資源使用、錯誤條件等因素提供更好的彈性。
這個我根據(jù)官方的介紹翻譯的原文鏈接在這https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance/當中有翻譯不對的還請留言指出。
從官方的文檔中我們能得到這些重要的信息:
- Eureka是基于REST服務的,也就意味著它是基于http協(xié)議的
- 它分為服務端(java語言實現(xiàn))和 客服端(可以是java也可以是非Java語言,因為Eureka提供的是 rest服務,當然官方也有提供部分其他語言的官方包)。
- Eureka的作用是實現(xiàn)為服務間的負載均衡和故障轉(zhuǎn)移。
Eureka的服務端和客服端
Eureka的服務端來管理所有的微服,微服內(nèi)的所有服務需要依賴Eureka客戶端的依賴包,并在application上添加@EnableEurekaClient注解來實現(xiàn)Eureka客戶端。
<dependency>
<groupId>com.netflix.eureka</groupId>
<artifactId>eureka-client</artifactId>
<version>1.1.16</version>
</dependency>
@EnableEurekaClient
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHiApplication.class, args);
}
}
當然還有配置文件需要添加相關(guān)的配置,具體的可以參考官方文檔https://github.com/Netflix/eureka/wiki/Configuring-Eureka/
,現(xiàn)在網(wǎng)上也有很多相關(guān)的博客,這里我就不詳細寫了。
Eureka的客服端則是通過rest服務通知Eureka的服務端該客服端的健康狀況,事實是每個客服端的具體信息保存在InstanceInfo類中,通過ConcurrentHashMap<String, Map<String,Lease<InstanceInfo>>>
的雙層Map結(jié)構(gòu)來管理所有的的客服端。更重要的是其實在每個客服端在以心跳的模式定時通知服務端客戶端的實時狀態(tài)時,客戶端也會獲得到一份最新的服務端的InstanceInfo列表清單,沒錯其實每個客服端也能獲得微服的所有客服端的健康狀況。具體客服端獲得服務信息的方法如下:
@Qualifier("eurekaClient")
@Autowired
private EurekaClient eurekaClient;
public String serviceUrl(){
InstanceInfo instance = eurekaClient.getNextServerFromEureka("service-hi", false);
return instance.getHomePageUrl();
}
@Autowired
private DiscoveryClient discoveryClient;
//獲得對應服務名下所有的服務實力信息列表,服務如果有做集群,則返回的是該服務集群下的所有實力的列表
List<ServiceInstance> list = discoveryClient.getInstances("service-hi");
if (list != null && list.size() > 0 ) {
String aa = list.get(0).getUri().getAuthority();
}
//獲得微服下所有的服務名
List<String> servicesNames = discoveryClient.getServices();
StringBuilder sb = new StringBuilder();
for (String s:servicesNames) {
sb.append(s+"\t");
}
Eureka的REST服務
上面說過服務端和客戶端是通過rest服務實現(xiàn)通信的,也就是說如果我現(xiàn)在想知道服務端下所有客服端的具體信息和健康狀況只需要通過一個http請求就可以完成,答案是肯定的,當然本身eureka服務本身就提供了管理界面來查看客戶端的具體信息如下:
但是這樣獲得的信息并不完全,所有如果你想獲得更加詳細的信息,或則你想使用其他編程語言實現(xiàn)客服端的話可以通過Eureka服務提供的接口文檔實現(xiàn)注冊、取消注冊、更新、獲得所有InstanceInfo信息等操作,文檔如下:
| 操作 | 接口地址 | 描述 |
|---|---|---|
| 注冊服務 | POST /eureka/v2/apps/appID | Input: JSON/XML payload HTTP Code: 204 on success |
| 取消服務注冊 | DELETE /eureka/v2/apps/appID/instanceID | HTTP Code: 200 on success |
| 發(fā)送一個服務的心跳 | PUT /eureka/v2/apps/appID/instanceID | HTTP Code: 200 on success 404 if instanceID doesn’t exist |
| 查詢所有服務信息 | GET /eureka/v2/apps | HTTP Code: 200 on success Output: JSON/XML |
| 查詢所有服務的服務id | GET /eureka/v2/apps/appID | HTTP Code: 200 on success Output: JSON/XML |
| 根據(jù)具體服務id查詢服務信息 | GET /eureka/v2/apps/appID/instanceID | HTTP Code: 200 on success Output: JSON/XML |
| 對于一個具體的實例查詢 | GET /eureka/v2/instances/instanceID | HTTP Code: 200 on success Output: JSON/XML |
| 停止實力服務 | PUT /eureka/v2/apps/appID/instanceID/status?value=OUT_OF_SERVICE | HTTP Code: 200 on success 500 on failure |
| 把實例重新放入服務中 | DELETE /eureka/v2/apps/appID/instanceID/status?value=UP (The value=UP is optional, it is used as a suggestion for the fallback status due to removal of the override) | HTTP Code: 200 on success 500 on failure |
| 更新 metadata中的數(shù)據(jù) | PUT /eureka/v2/apps/appID/instanceID/metadata?key=value | HTTP Code: 200 on success 500 on failure |
| 查詢特定vipaddress地址下的所有實例 | GET /eureka/v2/vips/vipAddress | HTTP Code: 200 on success Output: JSON/XML 404 if the vipAddress does not exist. |
| 查詢特定安全vipaddress下的所有實例 | GET /eureka/v2/svips/svipAddress | HTTP Code: 200 on success Output: JSON/XML 404 if the svipAddress does not exist. |
官方文檔的鏈接在這:https://github.com/Netflix/eureka/wiki/Eureka-REST-operations/
已獲取所有InstanceInfo列表信息為例,我在postman上的請求結(jié)果如下:
<applications>
<versions__delta>1</versions__delta>
<apps__hashcode>UP_3_</apps__hashcode>
<application>
<name>SERVICE-HI-APPNAME 8763</name>
<instance>
<instanceId>service-hi</instanceId>
<hostName>DESKTOP-CKLCJ5F</hostName>
<app>SERVICE-HI-APPNAME 8763</app>
<ipAddr>192.168.1.8</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8763</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1510988885998</registrationTimestamp>
<lastRenewalTimestamp>1511102494467</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1510988822454</serviceUpTimestamp>
</leaseInfo>
<metadata>
<testkey4>testValue4</testkey4>
<testkey3>testValue3</testkey3>
<testkey2>testValue2</testkey2>
<testkey1>testValue1</testkey1>
</metadata>
<homePageUrl>http://DESKTOP-CKLCJ5F:8763/</homePageUrl>
<statusPageUrl>http://DESKTOP-CKLCJ5F:8763/info</statusPageUrl>
<healthCheckUrl>http://DESKTOP-CKLCJ5F:8763/health</healthCheckUrl>
<vipAddress>service-hi</vipAddress>
<secureVipAddress>service-hi</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1510988885998</lastUpdatedTimestamp>
<lastDirtyTimestamp>1510988885942</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
<application>
<name>SERVICE-RIBBON</name>
<instance>
<instanceId>DESKTOP-CKLCJ5F:service-ribbon:8764</instanceId>
<hostName>DESKTOP-CKLCJ5F</hostName>
<app>SERVICE-RIBBON</app>
<ipAddr>192.168.1.8</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8764</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1510993263471</registrationTimestamp>
<lastRenewalTimestamp>1511102494632</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1510988934957</serviceUpTimestamp>
</leaseInfo>
<metadata class="java.util.Collections$EmptyMap"/>
<homePageUrl>http://DESKTOP-CKLCJ5F:8764/</homePageUrl>
<statusPageUrl>http://DESKTOP-CKLCJ5F:8764/info</statusPageUrl>
<healthCheckUrl>http://DESKTOP-CKLCJ5F:8764/health</healthCheckUrl>
<vipAddress>service-ribbon</vipAddress>
<secureVipAddress>service-ribbon</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1510993263471</lastUpdatedTimestamp>
<lastDirtyTimestamp>1510993263422</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
<application>
<name>SERVICE-HI-APPNAME 8765</name>
<instance>
<instanceId>service-hi</instanceId>
<hostName>DESKTOP-CKLCJ5F</hostName>
<app>SERVICE-HI-APPNAME 8765</app>
<ipAddr>192.168.1.8</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8765</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1511100242138</registrationTimestamp>
<lastRenewalTimestamp>1511102492656</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1511100242138</serviceUpTimestamp>
</leaseInfo>
<metadata>
<testkey4>testValue4</testkey4>
<testkey3>testValue3</testkey3>
<testkey2>testValue2</testkey2>
<testkey1>testValue1</testkey1>
</metadata>
<homePageUrl>http://DESKTOP-CKLCJ5F:8765/</homePageUrl>
<statusPageUrl>http://DESKTOP-CKLCJ5F:8765/info</statusPageUrl>
<healthCheckUrl>http://DESKTOP-CKLCJ5F:8765/health</healthCheckUrl>
<vipAddress>service-hi</vipAddress>
<secureVipAddress>service-hi</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1511100242138</lastUpdatedTimestamp>
<lastDirtyTimestamp>1511100242050</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
</applications>
上面的信息更加詳細,如IP地址、服務的健康狀況、instanceId、hostName等信息都可以查到,方便我們在開發(fā)中發(fā)現(xiàn)問題。
總結(jié)
相信講到這大家對Eureka是如何管理微服務已經(jīng)有了一定的認識,管理Eureka下的服務其實是管理每個InstanceInfo,而負載均衡,錯誤故障轉(zhuǎn)移都是基于每個InstanceInfo實現(xiàn)的。后面我會單獨對InstanceInfo做更具體的講解,歡迎大家評論。