Spring Cloud Netflix
Dalston.RELEASE
該項目通過自動配置為Spring Boot應用程序提供Netflix OSS集成,并綁定到Spring環(huán)境和其他Spring編程模型成語浇垦。通過幾個簡單的注釋苗膝,您可以快速啟用和配置應用程序中的常見模式绽左,并通過經過測試的Netflix組件構建大型分布式系統(tǒng)。提供的模式包括服務發(fā)現(Eureka),斷路器(Hystrix),智能路由(Zuul)和客戶端負載平衡(Ribbon)盆犁。
服務發(fā)現:Eureka客戶端
服務發(fā)現是基于微服務架構的關鍵原則之一。嘗試配置每個客戶端或某種形式的約定可能非常困難篡九,可以非常脆弱谐岁。Netflix服務發(fā)現服務器和客戶端是Eureka¢痪剩可以將服務器配置和部署為高可用性伊佃,每個服務器將注冊服務的狀態(tài)復制到其他服務器。
如何包含Eureka客戶端
要在您的項目中包含Eureka客戶端讽坏,請使用組org.springframework.cloud
和工件ID spring-cloud-starter-eureka
的啟動器。有關 使用當前的Spring Cloud發(fā)布列表設置構建系統(tǒng)的詳細信息例证,請參閱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服務ID或VIP的默認值)空幻,那么默認值將是正常的。
有關可配置選項的更多詳細信息晨抡,請參閱EurekaInstanceConfigBean和EurekaClientConfigBean氛悬。
使用Eureka服務器進行身份驗證
如果其中一個eureka.client.serviceUrl.defaultZone
網址中包含一個憑據(如http://user:password@localhost:8761/eureka
)),HTTP基本身份驗證將自動添加到您的eureka客戶端耘柱。對于更復雜的需求如捅,您可以創(chuàng)建DiscoveryClientOptionalArgs
類型的@Bean
,并將ClientFilter
實例注入到其中调煎,所有這些都將應用于從客戶端到服務器的調用镜遣。
注意: 由于Eureka中的限制,不可能支持每個服務器的基本身份驗證憑據士袄,所以只能使用第一個找到的集合悲关。
狀態(tài)頁和健康指標
Eureka實例的狀態(tài)頁面和運行狀況指示器分別默認為“/ info”和“/ health”,它們是Spring Boot執(zhí)行器應用程序中有用端點的默認位置娄柳。如果您使用非默認上下文路徑或servlet路徑(例如server.servletPath=/foo
)或管理端點路徑(例如management.contextPath=/admin
)寓辱,則需要更改這些,即使是執(zhí)行器應用程序赤拒。例:
application.yml
eureka:
instance:
statusPageUrlPath: ${management.context-path}/info
healthCheckUrlPath: ${management.context-path}/health
這些鏈接顯示在客戶端使用的元數據中秫筏,并在某些情況下用于決定是否將請求發(fā)送到應用程序诱鞠,因此如果它們是準確的,這是有幫助的这敬。
注冊安全應用程序
如果您的應用程序想通過HTTPS聯系航夺,則可以分別在EurekaInstanceConfig
,即 eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]
中設置兩個標志崔涂。這將使Eureka發(fā)布實例信息顯示安全通信的明確偏好阳掐。Spring Cloud DiscoveryClient
將始終為以這種方式配置的服務返回一個https://…;
URI,并且Eureka(本機)實例信息將具有安全的健康檢查URL冷蚂。
由于Eureka內部的工作方式缭保,它仍然會發(fā)布狀態(tài)和主頁的非安全網址,除非您也明確地覆蓋帝雇。您可以使用占位符來配置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或其他平臺作為服務),則需要確保代理“轉發(fā)”頭部被截取并處理應用程序宦芦。Spring Boot應用程序中的嵌入式Tomcat容器會自動執(zhí)行“X-Forwarded - \ *”標頭的顯式配置宙址。你這個錯誤的一個跡象就是你的應用程序本身所呈現的鏈接是錯誤的(錯誤的主機,端口或協(xié)議)调卑。
Eureka的健康檢查
默認情況下抡砂,Eureka使用客戶端心跳來確定客戶端是否啟動。除非另有規(guī)定恬涧,否則發(fā)現客戶端將不會根據Spring Boot執(zhí)行器傳播應用程序的當前運行狀況檢查狀態(tài)注益。這意味著成功注冊后Eureka將永遠宣布申請?zhí)幱凇癠P”狀態(tài)。通過啟用Eureka運行狀況檢查可以改變此行為溯捆,從而將應用程序狀態(tài)傳播到Eureka丑搔。因此,每個其他應用程序將不會在“UP”之外的狀態(tài)下將流量發(fā)送到應用程序提揍。
application.yml
eureka:
client:
healthcheck:
enabled: true
警告:
eureka.client.healthcheck.enabled=true
只能在application.yml
中設置啤月。設置bootstrap.yml
中的值將導致不期望的副作用,例如在具有UNKNOWN
狀態(tài)的eureka中注冊劳跃。
如果您需要更多的控制健康檢查谎仲,您可以考慮實施自己的com.netflix.appinfo.HealthCheckHandler
。
Eureka實例和客戶端的元數據
值得花點時間了解Eureka元數據的工作原理刨仑,以便您可以在平臺上使用它郑诺。有主機名绞呈,IP地址,端口號间景,狀態(tài)頁和運行狀況檢查等標準元數據。這些發(fā)布在服務注冊表中艺智,由客戶使用倘要,以直接的方式聯系服務。額外的元數據可以添加到eureka.instance.metadataMap
中的實例注冊中十拣,并且這將在遠程客戶端中可訪問封拧,但一般不會更改客戶端的行為,除非意識到元數據的含義夭问。下面描述了幾個特殊情況泽西,其中Spring Cloud已經為元數據映射指定了含義。
在Cloudfoundry上使用Eureka
Cloudfoundry有一個全局路由器缰趋,所以同一個應用程序的所有實例都具有相同的主機名(在具有相似架構的其他PaaS解決方案中也是如此)捧杉。這不一定是使用Eureka的障礙,但如果您使用路由器(建議秘血,甚至是強制性的味抖,具體取決于您的平臺的設置方式),則需要明確設置主機名和端口號(安全或非安全)灰粮,以便他們使用路由器仔涩。您可能還需要使用實例元數據,以便您可以區(qū)分客戶端上的實例(例如粘舟,在自定義負載平衡器中)熔脂。默認情況下,eureka.instance.instanceId
為vcap.application.instance_id
柑肴。例如:
application.yml
eureka:
instance:
hostname: ${vcap.application.uris[0]}
nonSecurePort: 80
根據Cloudfoundry實例中安全規(guī)則的設置方式霞揉,您可以注冊并使用主機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_實例注冊的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
eureka:
instance:
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
使用這個元數據和在localhost上部署的多個服務實例耗式,隨機值將在那里進行胁住,以使實例是唯一的趁猴。在Cloudfoundry中,vcap.application.instance_id
將在Spring Boot應用程序中自動填充彪见,因此不需要隨機值儡司。
使用EurekaClient
一旦您擁有@EnableDiscoveryClient
(或@EnableEurekaClient
)的應用程序,您就可以使用它來從Eureka服務器發(fā)現服務實例余指。一種方法是使用本機com.netflix.discovery.EurekaClient
(而不是Spring云DiscoveryClient
)捕犬,例如
@Autowired
private EurekaClient discoveryClient;
public String serviceUrl() {
InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false);
return instance.getHomePageUrl();
}
提示
不要使用
@PostConstruct
方法或@Scheduled
方法(或ApplicationContext
可能尚未啟動的任何地方)EurekaClient
。它被初始化為SmartLifecycle
(帶有phase=0
)酵镜,所以最早可以依靠它可用的是另一個具有更高階段的SmartLifecycle
碉碉。
本機Netflix EurekaClient的替代方案
您不必使用原始的Netflix EurekaClient
,通常在某種包裝器后面使用它更為方便淮韭。Spring Cloud支持Feign(REST客戶端構建器)垢粮,還支持Spring RestTemplate
使用邏輯Eureka服務標識符(VIP)而不是物理URL。要使用固定的物理服務器列表配置Ribbon靠粪,您可以將<client>.ribbon.listOfServers
設置為逗號分隔的物理地址(或主機名)列表蜡吧,其中<client>
是客戶端的ID。
您還可以使用org.springframework.cloud.client.discovery.DiscoveryClient
占键,它為Netflix不具體的發(fā)現客戶端提供簡單的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
)捞慌,默認持續(xù)時間為30秒耀鸦。在實例,服務器和客戶端在其本地緩存中都具有相同的元數據(因此可能需要3個心跳)之前啸澡,客戶端才能發(fā)現服務袖订。您可以使用eureka.instance.leaseRenewalIntervalInSeconds
更改期限,這將加快客戶端連接到其他服務的過程嗅虏。在生產中洛姑,最好堅持使用默認值,因為服務器內部有一些計算可以對租賃更新期進行假設皮服。
區(qū)
如果您已將Eureka客戶端部署到多個區(qū)域楞艾,您可能希望這些客戶端在使用另一個區(qū)域中的服務之前,利用同一區(qū)域內的服務龄广。為此硫眯,您需要正確配置您的Eureka客戶端。
首先择同,您需要確保將Eureka服務器部署到每個區(qū)域两入,并且它們是彼此的對等體。有關詳細信息敲才,請參閱區(qū)域和區(qū)域部分 裹纳。
接下來择葡,您需要告知Eureka您的服務所在的區(qū)域。您可以使用metadataMap
屬性來執(zhí)行此操作剃氧。例如敏储,如果service 1
部署到zone 1
和zone 2
,則需要在service 1
中設置以下Eureka屬性
1區(qū)服務1
eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true
第2區(qū)的服務1
eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true
服務發(fā)現:Eureka服務器
如何包含Eureka服務器
要在項目中包含Eureka服務器朋鞍,請使用組org.springframework.cloud
和工件id spring-cloud-starter-eureka-server
的啟動器虹曙。有關 使用當前的Spring Cloud發(fā)布列表設置構建系統(tǒng)的詳細信息,請參閱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的依賴關系解決規(guī)則和父母的bom功能缺乏,只要依靠spring-cloud-starter-eureka-server就可能導致應用程序啟動失敗呛讲。要解決這個問題禾怠,必須添加Spring Boot Gradle插件,并且必須導入Spring云啟動器父母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" } }
高可用性贝搁,區(qū)域和地區(qū)
Eureka服務器沒有后端存儲吗氏,但是注冊表中的服務實例都必須發(fā)送心跳以保持其注冊更新(因此可以在內存中完成)±啄妫客戶端還具有eureka注冊的內存緩存(因此弦讽,他們不必為注冊表提供每個服務請求)。
默認情況下膀哲,每個Eureka服務器也是一個Eureka客戶端往产,并且需要(至少一個)服務URL來定位對等體。如果您不提供該服務將運行和工作某宪,但它將淋浴您的日志與大量的噪音無法注冊對等體仿村。
關于區(qū)域和區(qū)域的客戶端Ribbon支持的詳細信息,請參見下文兴喂。
獨立模式
只要存在某種監(jiān)視器或彈性運行時間(例如Cloud Foundry)蔼囊,兩個高速緩存(客戶機和服務器)和心跳的組合使獨立的Eureka服務器對故障具有相當的彈性。在獨立模式下衣迷,您可能更喜歡關閉客戶端行為畏鼓,因此不會繼續(xù)嘗試并且無法訪問其對等體。例:
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(Two Peer Aware 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
。
您可以向系統(tǒng)添加多個對等體啤斗,只要它們至少一個邊緣彼此連接表箭,則它們將在它們之間同步注冊。如果對等體在物理上分離(在數據中心內或多個數據中心之間)钮莲,則系統(tǒng)原則上可以分裂腦型故障免钻。
喜歡IP地址
在某些情況下,Eureka優(yōu)先發(fā)布服務的IP地址而不是主機名崔拥。將eureka.instance.preferIpAddress
設置為true
极舔,并且當應用程序向eureka注冊時,它將使用其IP地址而不是其主機名链瓦。
保護Eureka服務器
只需將Spring Security添加到服務器的類路徑中即可保護您的Eureka服務器spring-boot-starter-security
拆魏。默認情況下,當Spring Security位于類路徑上時慈俯,它將要求在應用程序的每個請求中發(fā)送有效的CSRF令牌稽揭。Eureka客戶端通常不會擁有有效的跨站點請求偽造(CSRF)令牌,您需要為/eureka/**
端點禁用此要求肥卡。例如:
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http);
}
}
有關CSRF的更多信息溪掀,請參閱Spring Security文檔。
可以在Spring Cloud Samples 回購中找到演示Eureka Server 步鉴。
JDK 11支持
在JDK 11中刪除了Eureka服務器所依賴的JAXB模塊揪胃。如果您打算在運行Eureka服務器時使用JDK 11,則必須在POM或Gradle文件中包含這些依賴項氛琢。
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
筆記來自Spring Cloud官方文檔