版權聲明:本文爲博主原創文章,未經博主允許不得轉載。
服務發現:Eureka客戶端
服務發現是基於微服務架構的關鍵原則之一。嘗試配置每個客戶端或某種形式的約定可能非常困難,可以非常脆弱。Netflix服務發現服務器和客戶端是Eureka。可以將服務器配置和部署爲高可用性,每個服務器將註冊服務的狀態複製到其他服務器。
如何包含Eureka客戶端
要在您的項目中包含Eureka客戶端,使用組org.springframework.cloud
和工件id spring-cloud-starter-eureka
的啓動器。有關 使用當前的Spring Cloud發佈列表設置構建系統的詳細信息,請參閱Spring Cloud項目頁面。
註冊Eureka
當客戶端註冊Eureka時,它提供有關自身的元數據,例如主機和端口,運行狀況指示符URL,主頁等。Eureka從屬於服務的每個實例接收心跳消息。如果心跳失敗超過可配置的時間表,則通常將該實例從註冊表中刪除。
示例eureka客戶端:
@Configuration @ComponentScan @EnableAutoConfiguration @EnableEurekaClient @RestController public class Application { @RequestMapping("/") public String home() { return "Hello world"; } public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } }
(即完全正常的Spring Boot應用程序)。在這個例子中,我們明確地使用@EnableEurekaClient
,但只有Eureka可用,你也可以使用@EnableDiscoveryClient
。需要配置才能找到Eureka服務器。例:
application.yml
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
其中“defaultZone”是一個魔術字符串後備值,爲任何不表示首選項的客戶端提供服務URL(即它是有用的默認值)。
從Environment
獲取的默認應用程序名稱(服務ID),虛擬主機和非安全端口分別爲${spring.application.name}
,${spring.application.name}
和${server.port}
。
@EnableEurekaClient
使應用程序成爲Eureka“實例”(即註冊自身)和“客戶端”(即它可以查詢註冊表以查找其他服務)。實例行爲由eureka.instance.*
配置鍵驅動,但如果您確保您的應用程序具有spring.application.name
(這是Eureka服務標識或VIP的默認值),那麼默認值將會很好。
有關可配置選項的更多詳細信息,請參閱EurekaInstanceConfigBean和EurekaClientConfigBean。
使用Eureka服務器進行身份驗證
如果其中一個eureka.client.serviceUrl.defaultZone
URL中包含一個憑據(如http://user:password@localhost:8761/eureka
)),HTTP基本身份驗證將自動添加到您的eureka客戶端。對於更復雜的需求,您可以創建@Bean
類型DiscoveryClientOptionalArgs
並注入ClientFilter
實例,所有這些都將應用於從客戶端到服務器的調用。
注意 | 由於Eureka中的限制,不可能支持每個服務器的基本身份驗證憑據,因此只能使用第一個找到的集合。 |
---|
狀態頁和健康指標
Eureka實例的狀態頁面和運行狀況指示器分別默認爲“/ info”和“/ health”,它們是Spring Boot Actuator應用程序中有用端點的默認位置。如果您使用非默認上下文路徑或servlet路徑(例如server.servletPath=/foo
)或管理端點路徑(例如management.contextPath=/admin
)),則需要更改這些,即使是執行器應用程序。例:
application.yml
eureka: instance: statusPageUrlPath: ${management.context-path}/info healthCheckUrlPath: ${management.context-path}/health
這些鏈接顯示在客戶端使用的元數據中,並在某些情況下用於決定是否將請求發送到應用程序,因此如果它們是準確的,這是有幫助的。
註冊安全應用程序
如果您的應用程序想通過HTTPS聯繫,則可以分別在EurekaInstanceConfig
,即 eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]
中設置兩個標誌。這將使Eureka發佈實例信息顯示安全通信的顯式偏好。Spring Cloud DiscoveryClient
將始終爲這樣配置的服務返回https://…
;
URI,並且Eureka(本機)實例信息將具有安全的健康檢查URL。
由於Eureka在內部工作,它仍然會發布狀態和主頁的非安全網址,除非您也明確地覆蓋。您可以使用佔位符來配置eureka實例URL,例如
application.yml
eureka: instance: statusPageUrl: https://${eureka.hostname}/info healthCheckUrl: https://${eureka.hostname}/health homePageUrl: https://${eureka.hostname}/
(請注意,${eureka.hostname}
只是在Eureka的更高版本中可用的本地佔位符,您也可以使用Spring佔位符實現同樣的功能,例如使用${eureka.instance.hostName}
。)
注意 | 如果您的應用程序在代理服務器後面運行,並且SSL終止服務在代理中(例如,如果您運行在Cloud Foundry或其他平臺作爲服務),則需要確保代理“轉發”頭部被截取並處理應用程序。Spring Boot應用程序中的嵌入式Tomcat容器會自動執行“X-Forwarded - \ *”頭的顯式配置。你這個錯誤的一個跡象就是你的應用程序本身所呈現的鏈接是錯誤的(錯誤的主機,端口或協議)。 |
---|
Eureka的健康檢查
默認情況下,Eureka使用客戶端心跳來確定客戶端是否已啓動。除非另有規定,否則Discovery Client將不會根據Spring Boot Actuator傳播應用程序的當前運行狀況檢查狀態。這意味着成功註冊後Eureka將永遠宣佈申請處於“UP”狀態。可以通過啓用Eureka運行狀況檢查來改變此行爲,從而將應用程序狀態傳播到Eureka。因此,每個其他應用程序將不會在“UP”之外的狀態下將流量發送到應用程序。
application.yml
eureka: client: healthcheck: enabled: true
警告 | eureka.client.healthcheck.enabled=true只能在application.yml中設置。設置bootstrap.yml中的值將導致不良副作用,例如在eureka中註冊UNKNOWN狀態。 |
---|
如果您需要更多的控制健康檢查,您可以考慮實施自己的com.netflix.appinfo.HealthCheckHandler
。
Eureka實例和客戶端的元數據
值得花點時間瞭解Eureka元數據的工作原理,以便您可以在平臺上使用它。有主機名,IP地址,端口號,狀態頁和運行狀況檢查等標準元數據。這些發佈在服務註冊表中,由客戶使用,以直接的方式聯繫服務。額外的元數據可以添加到eureka.instance.metadataMap
中的實例註冊中,並且這可以在遠程客戶端中訪問,但一般不會改變客戶端的行爲,除非知道元數據的含義。下面描述了幾個特殊情況,其中Spring Cloud已經爲元數據映射指定了含義。
在Cloudfoundry上使用Eureka
Cloudfoundry有一個全局路由器,所以同一個應用程序的所有實例都具有相同的主機名(在具有相似架構的其他PaaS解決方案中也是如此)。這不一定是使用Eureka的障礙,但是如果您使用路由器(建議,甚至是強制性的,具體取決於您的平臺的設置方式),則需要明確設置主機名和端口號(安全或非安全),以便他們使用路由器。您可能還需要使用實例元數據,以便您可以區分客戶端上的實例(例如,在自定義負載平衡器中)。默認情況下,eureka.instance.instanceId
爲vcap.application.instance_id
。例如:
application.yml
eureka: instance: hostname: ${vcap.application.uris[0]} nonSecurePort: 80
根據Cloudfoundry實例中安全規則的設置方式,您可以註冊並使用主機VM的IP地址進行直接的服務到服務調用。此功能尚未在Pivotal Web Services(PWS)上提供。
在AWS上使用Eureka
如果應用程序計劃將部署到AWS雲,那麼Eureka實例必須被配置爲AWS意識到,這可以通過定製來完成EurekaInstanceConfigBean方式如下:
@Bean @Profile("!default") public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) { EurekaInstanceConfigBean b = new EurekaInstanceConfigBean(inetUtils); AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka"); b.setDataCenterInfo(info); return b; }
更改Eureka實例ID
香草Netflix Eureka實例註冊了與其主機名相同的ID(即每個主機只有一個服務)。Spring Cloud Eureka提供了一個明智的默認,如下所示:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}}
。例如myhost:myappname:8080
。
使用Spring Cloud,您可以通過在eureka.instance.instanceId
中提供唯一的標識來覆蓋此。例如:
application.yml
<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:rgba(0, 0, 0, 0.9)">eureka: instance: instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}</span></span>
使用這個元數據和在localhost上部署的多個服務實例,隨機值將在那裏進行,以使實例是唯一的。在Cloudfoundry中,vcap.application.instance_id
將在Spring Boot應用程序中自動填充,因此不需要隨機值。
使用EurekaClient
一旦您有一個@EnableDiscoveryClient
(或@EnableEurekaClient
)的應用程序,您可以使用它來從Eureka服務器發現服務實例。一種方法是使用本機com.netflix.discovery.EurekaClient
(而不是Spring Cloud DiscoveryClient
),例如
eureka: instance: instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
提示 | 不要使用@PostConstruct方法或@Scheduled方法(或ApplicationContext可能尚未啓動的任何地方)EurekaClient。它被初始化爲SmartLifecycle(使用phase=0),所以您可以依賴的最早可用的是另一個具有較高階段的SmartLifecycle。 |
---|
本機Netflix EurekaClient的替代方案
您不必使用原始的Netflix EurekaClient
,通常在某種包裝器後面使用它更爲方便。Spring Cloud支持Feign(REST客戶端構建器),還支持使用邏輯Eureka服務標識符(VIP)而不是物理URL的Spring RestTemplate
。要使用固定的物理服務器列表配置Ribbon,您可以將<client>.ribbon.listOfServers
設置爲以逗號分隔的物理地址(或主機名)列表,其中<client>
是客戶端的ID。
您還可以使用org.springframework.cloud.client.discovery.DiscoveryClient
,它爲Netflix不具體的發現客戶端提供簡單的API,例如
@Autowired private DiscoveryClient discoveryClient; public String serviceUrl() { List<ServiceInstance> list = discoveryClient.getInstances("STORES"); if (list != null && list.size() > 0 ) { return list.get(0).getUri(); } return null; }
爲什麼註冊服務這麼慢?
作爲一個實例也包括定期心跳到註冊表(通過客戶端的serviceUrl
),默認持續時間爲30秒。在實例,服務器和客戶端在其本地緩存中都具有相同的元數據(因此可能需要3個心跳)之前,客戶端才能發現服務。您可以使用eureka.instance.leaseRenewalIntervalInSeconds
更改期限,這將加快客戶端連接到其他服務的過程。在生產中,最好堅持使用默認值,因爲服務器內部有一些計算可以對租賃更新期進行假設。
區
如果您已將Eureka客戶端部署到多個區域,您可能希望這些客戶端在使用另一個區域中的服務之前,在同一區域內利用服務。爲此,您需要正確配置您的Eureka客戶端。
首先,您需要確保將Eureka服務器部署到每個區域,並且它們是彼此的對等體。有關詳細信息,請參閱區域和區域部分 。
接下來,您需要告知Eureka您的服務所在的區域。您可以使用metadataMap
屬性來執行此操作。例如,如果將service 1
部署到zone 1
和zone 2
,則需要在service 1
中設置以下Eureka屬性
1區服務1
eureka.instance.metadataMap.zone = zone1 eureka.client.preferSameZoneEureka = true
第2區的服務1
eureka.instance.metadataMap.zone = zone2 eureka.client.preferSameZoneEureka = true
服務發現:Eureka服務器
如何包括Eureka服務器
要在項目中包含Eureka服務器,請使用組org.springframework.cloud
和工件id spring-cloud-starter-eureka-server
的啓動器。有關 使用當前的Spring Cloud發佈列表設置構建系統的詳細信息,請參閱Spring Cloud項目頁面。
如何運行Eureka服務器
示例eureka服務器;
@SpringBootApplication @EnableEurekaServer public class Application { public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } }
服務器具有一個帶有UI的主頁,根據/eureka/*
下的正常Eureka功能的HTTP API端點。
提示 | 由於Gradle的依賴關係解決規則和父母的bom功能缺乏,只要依靠spring-cloud-starter-eureka-server就可能導致應用程序啓動失敗。要解決這個問題,必須添加Spring Boot Gradle插件,並且必須像Spring那樣導入Spring cloud starter parent bom: 的build.gradle buildscript { dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.5.RELEASE") } } apply plugin: "spring-boot" dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.RELEASE" } } |
---|
高可用性,區域和地區
Eureka服務器沒有後端存儲,但註冊表中的服務實例都必須發送心跳以保持其註冊更新(因此可以在內存中完成)。客戶端還具有eureka註冊的內存緩存(因此,他們不必爲註冊表提供每個服務請求)。
默認情況下,每個Eureka服務器也是Eureka客戶端,並且需要(至少一個)服務URL來定位對等體。如果您不提供該服務將運行和工作,但它將淋浴您的日誌與大量的噪音無法註冊對等體。
有關區域和區域的客戶端Ribbon支持的詳細信息,請參見下文。
獨立模式
只要存在某種監視器或彈性運行時間(例如Cloud Foundry),兩個緩存(客戶機和服務器)和心跳的組合使獨立的Eureka服務器對故障具有相當的彈性。在獨立模式下,您可能更喜歡關閉客戶端行爲,因此不會繼續嘗試並且無法訪問其對等體。例:
application.yml(Standalone Eureka Server)
server: port: 8761 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
請注意,serviceUrl
指向與本地實例相同的主機。
同行意識
Eureka可以通過運行多個實例並要求他們相互註冊而變得更有彈性。事實上,這是默認的行爲,所以你需要做的只是爲對方添加一個有效的serviceUrl
,例如
application.yml(兩個同行的Eureka服務器)
--- spring: profiles: peer1 eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://peer2/eureka/ --- spring: profiles: peer2 eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://peer1/eureka/
在這個例子中,我們有一個YAML文件可以用於通過在不同的Spring配置文件中運行它來運行2臺主機(peer1和peer2)上的相同服務器。您可以使用此配置來測試單個主機上的對等體感知(通過操作/etc/hosts
來解析主機名,在生產中沒有太多價值)。事實上,如果您在一臺知道自己的主機名的機器上運行(默認情況下使用java.net.InetAddress
查找),則不需要eureka.instance.hostname
。
您可以向系統添加多個對等體,只要它們至少一個邊緣彼此連接,則它們將在它們之間同步註冊。如果對等體在物理上分離(在數據中心內或多個數據中心之間),則系統原則上可以分裂腦型故障。
喜歡IP地址
在某些情況下,Eureka最好是通告服務的IP地址而不是主機名。將eureka.instance.preferIpAddress
設置爲true
,當應用程序向eureka註冊時,它將使用其IP地址而不是其主機名。