javascript
Spring Cloud Netflix中文文档翻译笔记
原文地址:http://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/1.2.2.RELEASE/
Spring Cloud Netflix
1.2.2.RELEASE
Spring Cloude Netflix這個項目提供Netflix OSS和Spring Boot apps集成,通過自動配置和綁定到Spring環境和其他Spring編程模塊。通過一些簡單的注解配置,你可以很快的使用和配置應用的模塊,和構建大型分布式高可用的Netflix組件。這里提供包括服務發現(Service Discovery Eureka),斷路器或熔斷器(Circuit Breaker Hystrix),智能路由(intelligent routing Zuul)和 負載均衡(Ribbon)。
Service Discovery:Eureka Client
服務發現是微服務架構依賴的一個關鍵模塊。嘗試去管理每個客戶端的配置或者某些形式的約定是非常困難而且不穩定。Eureka是Netflix服務發現的服務端和客戶端。服務端可義高可用的配置和部署,每個服務器可以相互復制已注冊的服務的狀態。
如何引入Eureka Client
如何在你的項目中使用Eureka Client?使用org.spring.cloud和artifactid spring-cloud-starter-eureka。 請瀏覽網頁spring cloud project page去查看詳情如何配置你的系統使用當前的spring cloud版本。
Eureka注冊
當一個客戶端注冊到Eureka,它就提供了一些自己的元數據,比如host和port,可用的URL指示器,主頁等。Eureka接收每個注冊到Eureka的實例的心跳包,如果在配置的時間片內沒有接收到心跳,這個實例通常就會被注冊中心移除掉。
例子:
(i.e 完全普通的spring boot app)。在這個例子中我們顯示的使用用@EnableEurekaClient(explicitly)。但是僅可用的Eureka你可以使用@EnableDiscoveryClient。我們必須通過配置去定位一個Eureka服務。比如:
application.yml eureka:client:srviceUrl:defaultZone:http://localhost:8761/eureka/這個 “defaultZone” 是神奇的字符串值,他提供一個服務地址供其他任何客戶端使用,沒有明確的優先級。(i.e. 他是默認可用的)。
這個默認的應用名稱(service ID),主機和非安全的端口,分別是 spring.application.name和 {server.port}
@EnableEurekaClient 使你的應用同時變成一個 Eureka 實例(i.e. it registers itself)和 一個客戶端 (i.e. 它可以查詢注冊中心去定位其他服務)。這個實例行為通過 eureka.instance.* 驅動,但是默認的就夠了,如果確保你的應用有一個 spring.application.name (這是個默認的Eureka服務ID,或則VIP)。
查看 EurekaInstanceConfigBean 和 EurekaClientConfigBean更多配置參數詳情。
Eureka Server驗證
如果一個eureka客戶端嵌入了認證信息在 “eureka.client.serviceUrl.defaultZone”中,那么HTTP基礎身份驗證會自動添加到eureka客戶端(比如,http://user:password@localhost:8761/eureka)。更多的復雜的配置你需要創建一個 類型為DiscoveryClientOptionalArgs 的 @Bean,而且注入一個ClientFilter實例,這些都會被應用到客戶端到服務端之間的調用上。
注意: 由于Eureka的一個限制是不可能支持每個服務器基本授權認證,所以只被發現的第一組會被使用。
狀態頁和健康指示器
Eureka的狀態頁和健康指示器默認分別為“/info”和“/health”,是Spring boot actuator默認的配置,它非常好用。即便是一個Actuator應用,如果你想使用非默認的上下文路徑或者servlet路徑(如server.servletPath=/foo)或管理端點的路徑(如management.contextPath=/admin),你都需要做出相應的改變。例如:
application.yml eureka:instance:statusPageUrlPath:${management.context-path}/infohealthCheckUrlPath:${management.context-path}/health這些鏈接暴露了客戶端消費的元數據,和在一些情況下決定是否發送請求到你的應用,所以非常有用如果數據精確。
注冊安全應用
如果你的app想通過HTTPS連接,你需要設置兩個標記在EurekaInstanceConfig,即分別是,eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]。這會使Eureka實例明確的使用安全通道。spring cloud DiscoveryClient總是返回一個https://;服務的URI配置成這種方式,Eureka實例信息將會有一個安全的檢查URL。
因為Eureka的內部工作方式,它將繼續推送一個非安全的URL的狀態和主頁,除非你還覆蓋那些聲明。你可以使用占位符娶配置eureka實例的url。 例子:
(注意: eureka.hostname是一個本地的占位符僅僅在最近的版本中才可以使用,你需要很好的完成同樣的事情在Springplaceholders,例如 {eureka.instance.hostName})
注意:如果你的應用在慢于一個代理啟動運行,并且SSL終端在代理里面(如:如果你的應用作為一個服務在Cloud Foundry或其它平臺上跑的話),那么你將要確保應用能夠攔截和處理代理轉發的頭信息。如果它明確配置有’X-Forwarded-*`這類頭信息的情況下,在一個Spring Boot應用里面內嵌的Tomcat容器自動處理的。出現這個錯誤的原因,是因為你的應用程序提供的鏈接本身弄錯了。(錯誤的主機,端口,協議)。
Eureka的健康檢查
默認的,Eureka使用客戶端心跳確定一個客戶端是否在線。除非指定了其他的
Discovery Client不會傳播當前的spring boot actuator健康檢查狀態。這就是說只要成功注冊了Eureka就會一直通知應用是在“UP”狀態。這個動作可以被改變通過使用Eureka health checks,這種發送應用狀態給Eureka的行為將觸發Eureka的健康檢查,因此其他每個應用程序在其他狀態下不會給應用程序發送通信然后才‘UP’。
警告:eureka.client.healthcheck.enabled=true應該只在application.yml中被設置。如果設置在bootstrap.yml將會引起不可預知的影響比如注冊eureka出現unknown status。
如果你需要更多的配置關于health checks,你可能考慮實現你自己的com.netflix.appinfo.HealthCheckHandler。
Eureka實例和客戶端的元數據
這里值得我們花一點時間去理解eureka元數據是如何工作的,所以你可以在平臺上使用它找點感覺。這里有一個標準的元數據比如hostname,ip address,port numbers,status page和health check。他們被發布到服務注冊,而且被客戶端聯系服務端通過一種直接的方式。另外的,元數據可以被添加到實例注冊在eureka.instance.metadataMap,而且這會被遠程客戶端容易訪問,但是通常的不要去改變客戶端的行為,除非你知道了元數據的意義。有一些特殊情況下的描述,spring cloud 已經分配好了有意義的元數據映射。
在Cloudfoundry使用eureka在cloudfoundry
Cloudfoundry有一個全局的根路由器,因此所有相同的app都有一樣的hostname(在其他PaaS解決方案也是類似的架構)。這不妨礙我們使用Eureka(推薦的,或者強制的依賴你的平臺),你需要明確的設置hostname和post(secure of non-secure)以便他們使用路由器。你可能也想使用實例元數據,以便你可以區分實例在客戶端(在一個定制的負載均衡器)。默認的,eureka.instance.instanceId 是 vcap.application.instance_id。例如:
application.yml eureka:instance:hostname:${vcap.application.uris[0]}nonSecurePort:80根據安全規則的方式設置你的Cloudfoundry實例,你可能想注冊和使用主機的ip address去直接進行服務到服務之間的調用。這個特性目前還不能在 Pivotal Web Services。
在AWS上使用Eureka
如果應用準備發布到AWS,eureka實例需要配置成Amazon aware,這個可以通過以下方式定制EurekaInstanceConfigBean。
@Bean @Profile("!default") public EurekaInstanceConfigBean eurekaInstanceConfig(){EurekaInstanceConfigBean b = new EurekaInstanceConfigBean();AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");b.setDataCenterInfo(info);return b; }改變Eureka實例ID
Netflix Eureka實例是一個身份證,等于其域名注冊(i.e.每個host一個service)。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部署的服務實例,random.value設置會保證實例唯一。在cloudfoundry中,vcap.appliation.instance_id在spring boot中是自動增長的,所以random.value并不必須。
使用EurekaClient
如果你有一個 @EnalbeDicoveryClient(或@EurekaClient)的應用,你可以使用它從Eukeka Server去發現服務實例。一種方式是使用原生的com.netflix.discovery.EurekaClient(而不是spring cloud DiscoveryClient)。
@Autowired private EurekaClient discoveryClient;public String serviceUrl(){InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES",false);return instance.getHomePageUrl(); }提示:不要使用eurekaClient在@PostConstruct方法或者其他@Scheduled方法(或者任何ApplicationContext還沒有啟動的其他地方)。它初始化在一個SmartLifecycle(phase=0的條件)所以想盡早的使用就必須在另一個更高phase的SmartLifecycle上使用。
原生Netflix EurekaClient的替代品
你不必使用原始的Netflix EurekaClient,通常使用一個包裝器會更方便。Spring Cloud提供Fegin(REST客戶端構建器)和Spring RestTemplate去使用Eureka service的邏輯標識符替代物理URLS。配置帶固定的物理服務器集合的Ribbon,你可以簡單的設置.ribbon.listOfServers的物理服務器地址(或者hostname)集合,并使用逗號分隔符分開,是客戶端的ID。
你也可以使用 org.springframework.cloud.client.discoveryClient,它提供了一個簡單的API而不是特定于Netflix。
@Autowired private DiscoveryClient discoveryClient;public String serviceUrl(){List<ServiceInstane> list = discoveryClient.getInstances("STORES");if(list!=null && list.siz()>0) {return list.get(0).getUri();}return null; }為什么注冊一個服務很慢
成為一個實例也包含一個到注冊中心的心跳(serviceUrl),默認30秒。一個服務不會被客戶端發現,直到實例、服務端和客戶端全都擁有相同的元數據在它們的緩存里面(這可能還需要3次心跳)。你可以改變這個周期通過 eureka.instance.leaseRenewalIntervalInSeconds,這會加速client連接到其他的services。在生產環境或許最好保持默認值,因為server有些本地的計算去確保假設的更新周期(make assumptions about the lease renewal period)。
服務發現:Eureka Server
如何引入Eureka Server
引入Eureka Server到你的項目你需要使用org.springframework.cloud和spring-cloud-starter-eureka-server。訪問spring cloud project page查看更多詳情。
如何運行Eureka Server
eureka server示例:
@SpringBootApplication @EnableEurekaServer public class Application{public static void main(String [] args) {new SpringApplicationBuilder(Application.class).web(true).run(args);} }Server有一個UI主頁,和HTTP API端點提供平常的功能,地址:/eureka/*
Eureka背景:flux capacitor和google group discussion
TIP:由于Gradle的依賴解析規則,它沒有父bom依賴的特性,簡單的spring-cloud-starter-eureka-server依賴會引發錯誤。為了補救,必須添加Spring Boot的Gradle插件,而且引入Spring cloud starter的父bom。like so:
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" } }高可用,Zones和Regions
Eureka server沒有一個后端的存儲,但是服務實例在注冊里面全都得發送心跳去保持注冊更新(在內存里操作)。Clients同樣有一個erureka注冊中心的內存緩存(所以他們不是去為每一個到service的請求都去一次注冊中心)。
默認的,每一個Eureka server同樣是一個Eureka client,而且需要(至少一個)service url去定位同伴。如果你沒有提供,service同樣會運行和工作,但他會產生很多無法與其他同伴注冊的錯誤日志。
也可查看 客戶端Riboon支持,Zones 和 Regions。
獨立模式
client和server結合的緩存和心跳會使一個單機的Eureka server很好的彈性失敗(fairly resilient to failure),有一些監視和elastic runtime會使它保持活躍(比如:cloud foundry)。在獨立模式下,,您可能更傾向于關閉客戶端的行為,所以它不能保持失敗重試和重新找回它的那些節點。如:
application.yml server:port:8761eureka:instance:hostname:localhostclient:registerWithEureka:falsefetchRegistry:falseserviceUrl:defaultZone:http://${eureka.instance.hostname}:${server.port}/eureka/注意:serviceUrl指向了自己本地的實例。
Peer Awareness
Eureka可以有很好的彈性和可用性通過運行多個實例,和請求他們去相互注冊。事實上,這是默認的行為,所以所有你需要做的就是添加一個可用的serviceUrl到每一個同伴讓它可以工作。
applicatin.yml(Two Peer Aware Eureka Servers) --- spring:profiles: peer1 eureka:instance:hostname: peer1client:serviceUrl:defaultZone: http://peer2/eureka/--- spring:profiles: peer2 eureka:instance:hostname:peer2client:serviceUrl:defaultZone: http://peer1/eureka在這個例子中,我們有一個YAML文件,它可以用來運行同樣的兩個server在兩個hosts上(peer1 和 peer2),兩個不同的Spring profiles。你可以使用這個配置測試單機上的兩個對等實例(沒有多少價值在生產環境中這樣做)。通過修改/etc/hosts改變hostnames。事實上,eureka.instance.hostname并不需要如果你運行你自己直到的主機名的機器(它默認使用java.net.InetAddress檢查)。
你可以添加多個實例到一個系統上,而且只要他們都彼此連接到至少一個邊緣,他們將會同步注冊信息。If the peers are physically separated (inside a data centre or between multiple data centres) then the system can in principle survive split-brain type failures.
Prefer IP Address
一些情況,相比hostname,Eureka更好的是使用IP Adresses。設置 eureka.instance.preferIpAddress=true,當應用注冊到eureka上的時候,他們將使用IP Address替代hostname。
電子斷路器:Hystrix Clients
Netflix創建了一個庫叫Hystrix實現了電子斷路器模塊。在一個微服務架構中它一般有多個服務調用層。
一個底層的服務錯誤會引起級聯錯誤一直反饋到用戶。當調用一個特定的服務到達一定的閥值后(20 failures in 5 seconds is the default in Hystrix),回路開啟然后調用也不會成功。一些錯誤情況下可以由程序員提供
open circuit a fallback。
Having an open circuit stops cascading failures and allows overwhelmed or failing services time to heal. The fallback can be another Hystrix protected call, static data or a sane empty value. Fallbacks may be chained so the first fallback makes some other business call which in turn falls back to static data.
如何引入Hystrix
在你的項目中通過 org.springframework.cloud 和 spring-cloud-starter-hystrix 引入Hystrix。查看詳情并設置你的系統使用當前的spring cloud Release。
例如:
Netflix的普通發布庫叫Javanica提供了@HystrixCommand注解。Spring Cloud使用注解自動適配spring bean使用代理去連接到Hystrix斷路器。斷路器計算何時打開和關閉斷路,并決定在失敗的情況下做什么。
配置@HystrixCommand你可以使用commandProperties屬性,它有@HystrixProperty的注解列表。通過這里查看更多詳情.訪問Hystrix wiki查看更多可用的屬性。
Propagating the Security Context or using Spring Scopes
如果你想把本地線程上下文傳播到@HystrixCommand,默認的聲明將不可用因為它是在一個線程池中被啟動的。你可以選擇讓Hystrix使用同一個線程,通過一些配置,或直接寫在注解上,通過使用isolation strategy屬性。例如:
@HystrixCommand(fallbackMethod="stubMyService",commandProperties={@HystrixProperty(name="execution.isolation.strategy",value="SEMAPHORE")})同樣的方式適用于如果你用@SessionScope 或者 @RequestScope。你應該知道什么時候去做這件事因為有些運行時異常報找不到scoped上下文。
你還可以選擇設置 hystrix.shareSecurityContext 屬性為true。設置這個值會自動配置一個Hystrix兵法策略會把securityContext從主線程傳輸到你使用的Hystrix command。Hystrix does not allow multiple hystrix concurrency strategy to be registered so an extension mechanism is available by declaring your own HystrixConcurrencyStrategy as a Spring bean. Spring Cloud will lookup for your implementation within the Spring context and wrap it inside its own plugin
Health Indicator
斷路器的狀態同樣暴露在/health端點上。
{ "hystrix": {"openCircuitBreakers": ["StoreIntegration::getStoresByLocationLink"],"status": "CIRCUIT_OPEN" }, "status": "UP" }Hystrix Metrics Stream
使用Hystrix metrics stream需要引入依賴 spring-boot-starter-actuator。這會暴露/hystrix.stream作為一個管理端點。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>Circuit Breaker: Hystrix Dashboard
Hystrix的主要好處就是她收集了關于每個HystrixCommand的指標。Hystrix儀表盤用一種高效的方式展示了斷路器的健康數據。
如何引入Hystrix儀表盤
…org.springframework.cloud and artifact id spring-cloud-starter-hystrix-dashboard…Spring Cloud Project page
在Spring boot main class上加@EnableHystrixDashboard可以運行Hystrix儀表盤,然后可以訪問/hystrix并把儀表盤指向一個個體實例/hystrix.stream端點在一個應用中。
Turbine
看一個實例Hystrix數據對于整個系統的健康不是很有用. Turbine 是一個應用程序,該應用程序匯集了所有相關的/hystrix.stream端點到 /turbine.stream用于Hystrix儀表板。運行turbine使用@EnableTurbine注解你的主類,使用spring-cloud-starter-turbine這個jar。配置請參考 the Turbine 1 wiki 唯一的區別是turbine.instanceUrlSuffix不需要端口號前綴,因為這是自動處理,除非turbine.instanceInsertPort=false。
turbine.appConfig配置是一個eureka服務ID列表,turbine將使用這個配置查詢實例。turbine stream在hystrix dashboard中使用如下的url配置: http://my.turbine.server:8080/turbine.stream?cluster=,如果集群的名稱是default,集群參數可以忽略)。這個cluster參數必須和turbine.aggregator.clusterConfig匹配。從eureka返回的值都是大寫的,因此我們希望下面的例子可以工作,如果一個app使用eureka注冊,并且被叫做”customers”:
turbine:aggregator:clusterConfig: CUSTOMERSappConfig: customersclusterName可以使用SPEL表達式定義,在turbine.clusterNameExpression。 默認值是appName,意思是eureka服務ID最終將作為集群的key,例如customers的 InstanceInfo有一個CUSTOMERS的appName。另外一個例子是turbine.clusterNameExpression=aSGName,將從AWS ASG name獲取集群名稱。作者例子:
turbine:aggregator:clusterConfig: SYSTEM,USERappConfig: customers,stores,ui,adminclusterNameExpression: metadata['cluster']在這種情況下,集群名稱從4個服務從其元數據映射,期望包含“SYSTEM”和“USER”。
所有的app使用default,你需要一個文字表達式(使用單引號):
turbine:appConfig: customers,storesclusterNameExpression: "'default'"spring cloud提供一個spring-cloud-starter-turbine,所有依賴項你需要運行一個turbine服務器。使用@EnableTurbine創建一個spring boot應用。
注意:默認情況下Spring Cloud 允許 Turbine 在集群的每個主機下使用主機名和端口運行多個進程。如果你想在集群中的每個主機使用本機原生Netfix行為且不允許多個進程創建運行Turbine。(實例id的key為主機名)然后設置屬性turbine.combineHostPort=false
Turbine Stream
在一些環境(Pass), 在所有分布式下典型的Turbine 模型的Hystrix 命令都不工作,在這種情況下,你可能想要 Hystrix 命令 推送到 Tuibine, 和Spring Cloud進行消息傳遞,那么你需要要做的是在客戶端添加一個依賴spring-cloud-netflix-hystrix-stream和你所選擇的 spring-cloud-starter-stream-*的依賴(相關信息請查看 Spring Cloud Stream 方檔,以及如何配置客戶端憑證,和工作時的要本地代理)
創建一個帶有注解 @EnableTurbineStream 的Spring boot 應用服務器,端口默認 8989 (Hystrix 儀表盤的URL都使用此端口), 如果你想自定義端口,可以配置 server.port 或 turbine.stream.port 任一個,如果你使用了 spring-boot-starter-web 和 spring-boot-starter-actuator ,那么你可以提供(使用Tomcat默認情況下) management.port 不同的端口,并打開這個單獨的執行器端口
你可以把Dashboard指向Turbine Stream Server來代替個別Hystrix streams。如果Tubine Stream 使用你本機的8989端口運行,然后把 http://myhost:8989在流輸入字段Hystrix儀表板 Circuits 將由各自的 serverId關綴,緊隨其后的是一個點,然后是circuit 名稱
客戶端負載均衡:Ribbon
Ribbon是一個客戶端的負載均衡器,可以提供很多HTTP和TCP的控制行為。Feign已經使用了Ribbon,所以如果你使用了@FeignClient,Riboon也同樣被應用了。
Ribbon核心的概念是named client。每個負載均衡器都是共同體的一部分,可以一起運行去連接遠程服務器,你會給你的應用設置一個名字(比如使用@FeignClient注解)。Spring Cloud creates a new ensemble as an ApplicationContext on demand for each named client using RibbonClientConfiguration. This contains (amongst other things) an ILoadBalancer, a RestClient, and a ServerListFilter.
如何引入Ribbon
org.springframework.cloud and artifact id spring-cloud-starter-ribbon. 查看詳情 Spring Cloud Project page
定制Ribbon Clietn
你可以配置一些Ribbon client的屬性在外部的屬性文件里(application.properties/yml),如.ribbon.*,這個和Netflix APIS本身沒有什么不同。本機選項可以被檢查使用CommonClientConfigKey等靜態字段。
Spring cloud還允許你完全控制客戶端通過聲明額外的配置,使用@RibbonClient(位于RibbonClientConfiguration的頂部)。
例如:
In this case the client is composed from the components already in RibbonClientConfiguration together with any in FooConfiguration (where the latter generally will override the former).
警告:FooConfiguration已經設置為@Configuration,但是注意它不是@ComponentScan在主程序上下文,另外它會被所有的@RibbonClients共享。如果你使用了@ComponentScan(或者@SpringBootApplication)你需要采取措施去避免引入。(例如把他分割開來,不要重疊包,或者指定明確的包路徑在@ComponentScan)。
Spring Cloud Netflix默認為Ribbon提供了如下beans(BeanType beanName:ClassName):
* IClientConfig ribbonClientConfig: DefaultClientConfigImpl
* IRule ribbonRule: ZoneAvoidanceRule
* IPing ribbonPing: NoOpPing
* ServletList ribbonServerList: ConfigurationBasedServerlList
* ServerListFilter ribbonServerListFilter:
* ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer
創建一個這些類型的一個Bean放置到@RibbonClient配置類中(就像上面的FooConfiguration一樣),它允許你重寫每一個bean的描述。例如:
@Configuration public class FooConfiguation {@Beanpublic IPing ribbonPing(IClientConfig config){return new PingUrl();} }這里使用PingUrl替換了NoOpPing。
Customizing the ribbon client using properties
從1.2.0版本開始,sping cloud netflix支持使用配置文件的方式定制RibbOn clients并且與文檔兼容 Ribbon documentation
這允許你在不同環境中,改變啟動時的行為。
這些屬性都列在下面,并且他們必須使用 .ribbon.作為前綴。
* NFLoadBalancerClassName: should implement ILoadBalancer
* NFLoadBalanceerRuleClassName: should implement IRuld
* NFLoadBalancePingClassName: should implement IPing
* NIWSServerListClassName: should implement ServerList
* NIWServerListFilterClassName: should implement ServerListFilter
注意: 類中定義了這些屬性將會優先于@RibbonClient(configuration=MyRibbonConfig.class),默認的是Spring Cloud Netflix提供了。
給服務名為user設置IRule,你可以如下設置:
application.yml user:ribbon:NFLoadBalancerRuleClassName:com.netflix.loadbalancer.WeightedResponseTimeRule從 Ribbon documentation 查看Ribbon的實現。
Using Ribbon with Eureka
當Eureka跟Ribbon結合使用的時候(都在classpath),ribbonServerList會被一個外部的DiscoveryEnabledNIWServerList重寫,它填充了服務懶得列表從Eureka中。它同樣使用了NIWDiscoveryPing替換了IPing,它讓Eureka去確定一個server是否啟動。serverList默認使用的是DomainExtractingServerList,目的是讓物理元數據用于負載均衡器而不是AWS AMI(這是Netflix依賴的)。默認srverlist會構造”zone”信息提供給實例使用(遠程客戶端設置eureka.instance.metadataMap.zone),如果沒有設置它可以使用域名服務器的主機名作為區域代理(如果approximateZoneFromHostname被設置了)。一旦zone信息可用,它也會被用在ServerListFilter。默認它會用來定位一個客戶端在同一個zone,因為默認的是ZonePrefeerenceServerListFilter。client的zone默認跟遠程實例的一樣。i.e. eureka.instance.metadataMap.zone。
注意:正統的“archaius”方式設置client zone是通過配置屬性”@zone”,Sping Cloud將會優先使用這個設置(它會去引用YAML的配置)。
注意:If there is no other source of zone data then a guess is made based on the client configuration (as opposed to the instance configuration). We take eureka.client.availabilityZones, which is a map from region name to a list of zones, and pull out the first zone for the instance’s own region (i.e. the eureka.client.region, which defaults to “us-east-1” for comatibility with native Netflix).
Example:How to Use Ribbon Without Eureka
Eureka是一個方便的方式去抽象遠程服務發現,所以你不需要在客戶端硬編碼他們的URLS。但是如果你不想用eureka,Ribbon和Feign仍然可用。假設你已經在“stores”定義了@RibbOnClient,而且沒有使用Eureka(沒有在classpath中)。Ribbon client默認要配置server list,你可以提供配置像這樣:
application.yml stores:ribbon:listOfServers: example.com.google.comExample:Disable Eureka use in Ribbon
設置property ribbon.eureka.enable=false將會明確的讓Eureka的ribbon失效。
application.yml ribbon:eureka:enabled: falseUsing the Ribbon API Directly
你也可以直接使用 LoadBalancerClient。例如:
public class MyClass {@Autowiredprivate LoadBalancerClient loadBalancer;public void dostuff(){ServiceInstance instance = loadBalancer.choose("stors");URI storeUri = URI.create(String.format("httP://%s:%s",instance.getHost(),instance.getPort()));//... do something with the URI} }Declarative REST Client:Feign
Feign是一種聲明式的web service client。它讓web service變得更容易。使用Feign你只需要創建一個接口并且寫上注解。它提供插拔式的Feign注解和JAX-RS注解支持。Feign同樣提供插拔式的編碼解碼器。Spring Cloud添加了Spring MVC的注解支持,在Spring web中默認使用相同的HttpMessageConverters。spring cloud集成了Ribbon 和 Eureka去提供負載均衡。
How to include Feign
org.springframework.cloud and artifact id spring-cloud-starter-feign。Spring Cloud Project page。
Example spring boot app:
@Configuration @ComponentScan @EnableAutoConfiguration @EnableEurekaClient @EnableFeignClients public class Application {public stati void main(String[] args){SpringApplication.run(Application.class,args);} }StoreClient.java
@FeignClient("sotes") public interface StoreClient{@RequestMapping(method=RequestMethod.GET,value="/stores")List<Store> getStores();@RequestMapping(method=RequestMethod.POST,value="/stores/{storeId}",consumes="appliation/json")Store update(@PathVariable("storeId") Long storeId,Store store); }在@FeignClient注解里是一個任意的服務端的名字(比如 “store”),用于創建一個Ribbon負載均衡。你也可以指定一個URL,通過使用url屬性(絕對值或者只是個hostname)。應用程序上下文中的bean的名稱是接口的完全限定名稱。一個別名同樣被創建就是 “name”屬性上附加上“FeignClient”。看上面的列子,@Qualifire(“storesFeignClient”)可以用來引用bean,如果你想改變默認@Qualifier值,這可以在@FeignClient使用qualifier值。
Ribbon client會發現“stores”服務的物理地址。如果你的應用是Eureka client然后Eureka注冊中心會決定service的地址。如果你不想使用Eureka,你可以簡單的配置一個 server list 在你的外配配置中。
Overriding Feign Defaults
Sping cloud Feign支持的一個核心概念就是聲明的客戶端。每一個Feign client是整體的的一部分一起通過遠程服務器聯系,使用@FeignClient注解指定一個整體使用的名字。Sping cloud為每一個使用FeignClientConfiguration聲明的客戶端創建一個新的ApplictionContxt。這包括(除去其他東西)feign.Decode,feign.Encoder和feign.Contract。
Spring cloud提供通過@FeignClient.添加添額外的配置的方法讓你完全控制feign client。例如:
@FeignClient(name="stores", configuration=FooConfiguration.class) public interface StoreClient{ }在這個例子中,FeignClientsConfiguration已經有的和FooConfiguration自定義的共同組成了client(后者會覆蓋先者)。
警告: FooConfiguration必須是@Configuration,但是注意不能在@CompinentScan中,否則將被用于每個@FeignClient。如果你使用@ComponentScan(或@ SpringBootApplication),你需要采取一些措施來避免它被列入(比如把它放在一個單獨的,非重疊的包,或者指定包在@ComponentScan明確掃描)。
注意:該 serviceId 已經過時,建議使用 name 屬性
警告:以前,使用 url 屬性,則 name 不是必須的,但現在是必須的.
name 和 url 屬性都支持占位符。
@FeignClient(name="${feign,name}",url="${feign.url}") public interface StoreClient{ }Spring cloud netflix默認給feign提供如下bean(BeanType beanName:ClassName)
* Decoder feignDecoder: RespinseEntityDecoder(包裝了SpringDeccoder)
* Encoder fergnEncoder: SpringEncoder
* Logger feignLogger: SLF4JLogger
* contract feignContract:SpringMvcContract
* Feign.Builder feignBuilder: HystrixFeign.Builder
* Client feignClient:如果Ribbon可用就是loadBalancerFeignClient,否則默認feign client。
OkHttpClient和ApacheHttpClient feign clients可以通過分別設置fiegn.okhttp.enable 或者 feign.httpclient.enable為true,并且添加到classpath。
Spring cloud netflix默認沒有提供一下bean,但是仍然可以從上下文中查找這些bean并創建feign client:
* Logger.Level
* Retryer
* ErrorDecoder
* Request.options
* Collection
創建這些類型的一個bean可以放在@FeignClient配置中(如上FooConfiguration),允許你覆蓋所描述的每一個bean. 例子:
@Configuration public class FooConfiguration{@Beanpublic Contract feignContract(){return new feign.Contract.Default(); }@Beanpublic BasicAuthRequestInterceptor basicAuthRequestInterceptor(){return new BasicAuthRequestInterceptor("user","password");} }可以替換SpringMvcContract 和 feign.Contract.Default, 并增加一個 RequestInterceptor 到 RequestInterceptor 中去.
可以通過@EnableFeignClients的屬性defaultConfiguration以同樣的方式被指定。不同之處是配置會加載到所有的feign clients。
Creating Feign Clients Manually
在一些情況下可能需要自定義Feign clients但是不能用以上的方法。所以你可以使用Feign Builder API創建clients。下面是一個例子,創建了兩個相同接口的client但是用配置了分開的攔截器。
@Import(FeignClientsConfiguration.class) class FooController {private FooClient fooClient;private FooClient adminClient;@Autowired public FooController(ResponseEntityDecoder decoder, SpringEncoder encoder, Client client) {this.fooClient = Feign.builder().client(client).encoder(encoder).decoder(decoder).requestInterceptor(new BasicAuthRequestInterceptor("user", "user")).target(FooClient.class, "http://PROD-SVC");this.adminClient = Feign.builder().client(client).encoder(encoder).decoder(decoder).requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")).target(FooClient.class, "http://PROD-SVC");} }注意:在這個例子中,FeignClientsConfiguration.class是Spring Cloud Netflix默認提供的配置。
PROD-SVC是我們提供的服務名稱,會接收相應的客戶端的請求。
Feign Hystrix Support
如果Hystrix在classpath中,默認Feign用熔斷器包裝所有方法。返回一個 com.netflix.hystrix.HystrixCommand 也是可用的。這允許你以被動模式使用(使用.toObservable()或者.observer())或者 異步調用(.queue())。
要禁用Feign 的 Hystrix支持,設置feign.hystrix.enabled=false.
要在每個客戶端上禁用 Hystrix 支持,創建一個 Feign.Builder 并將scope 設置為”prototype”,例如:
@Configuration public class FooConfiguration {@Bean@Scope("prototype")public Feign.Builder feignBuilder() {return Feign.builder();} }Feign Hystrix Fallbacks
Hystrix支持回退的概念:一段默認的代碼將會被執行當斷路器打開或者發生錯誤。要啟用回退要給@FeignClient設置fallback屬性來實現回退.
@FeignClient(name="hello",fallback=HystrixClientFallback.class) protected interface HystrixClient {@RequestMapping(Method=RequestMethod.GET,value="/hello")Hello iFailSometimes(); }static class HystrixClientFallback implements HystrixClient{@Overridepublic Hello iFailSometimes(){return new Hello("fallback");} }如果一個請求需要觸發回退,可以使用fallbackFactory屬性替換@FeignClient。
@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class) protected interface HystrixClient {@RequestMapping(method = RequestMethod.GET, value = "/hello")Hello iFailSometimes(); }@Component static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> {@Overridepublic HystrixClient create(Throwable cause) {return new HystrixClientWithFallBackFactory() {@Overridepublic Hello iFailSometimes() {return new Hello("fallback; reason was: " + cause.getMessage());}};} }警告:There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.
Feign Inheritance Support
Feign支持通過單繼承接口引用api,這允許將通用操作分組為方便的基本接口.
UserService.java public interface UserService {@RequestMapping(method = RequestMethod.GET, value ="/users/{id}") User getUser(@PathVariable("id") long id); }UserResource.java @RestController public class UserResource implements UserService {}UserClient.java package project.user;@FeignClient("users") public interface UserClient extends UserService {}注意:通常在一個server和一個client之間共享一個接口是不可取的。它引入了緊耦合,實際上它也不會spring mvc中起作用(方法參數映射不會被繼承)。
Feign request/response compression
你可能考慮對你的Feign請求啟用GZIP壓縮。你可以通過設置如下啟用:
feign.compression.request.enabled=true feign.compression.response.enabled=trueFeign提供的壓縮設置與你的Web server的設置類似:
feign.compression.request.enabled=true feign.compression.request.mime-types=text/xml,application/xml,application/json feign.compression.request.min-request-size=2048這些屬性允許你選擇要壓縮的 MIME-TYPE 和最小的請求長度。
Feign logging
每個Feign client都創建了一個logger。默認的logger的命名是Feign client的全限定名。Feign日志只響應 DEBUG 級別。
application.yml logging.level.project.user.UserClient: DEBUG你能為每個客戶端配置Logger.Level 對象,告訴Feign記錄多少日志,選項包括:
* NONE, 不記錄 (DEFAULT).
* BASIC, 僅記錄請求方式和URL及響應的狀態代碼與執行時間.
* HEADERS, 日志的基本信息與請求及響應的頭.
* FULL, 記錄請求與響應的頭和正文及元數據.
例如,下面的設置會讓 Logger.Level為FULL.
@Configuration public class FooConfiguration {@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;} }External Configuration: Archaius
Archaius是Netflix client端配置庫。它的配置可以被所有的Netflix OSS組件使用。Archaius是 Apache Commons Configuration 的項目。它允許更新配置通過輪詢或者推送到client的方式。Archaius使用動態屬性類屬性的處理屬性。
Archaius Example class ArchaiusTest {DynamicStringProperty myprop = DynamicPropertyFactory.getInstance().getStringProperty("my.prop");void doSomething() {OtherClass.someMethod(myprop.get());} }Archaius有它自己的一套配置文件和負載優先級, Spring 應用程序通常不應直接應用Archaius, 本身仍然有配置Netflix工具的需求。Spring Cloud有一個Spring Environment Bridge,所以Archaius可以通過spring environment讀取屬性。這允許spring boot項目使用配置工具鏈,while allowing them to configure the Netflix tools, for the most part, as documented.
Router and Filter: Zuul
路由是微服務架構的不可或缺的一部分。例如:/ 可能映射到你應用主頁,/api/users映射到用戶服務,/api/shop映射到購物服務。Zuul。Zuul是Netflix出品的一個基于JVM路由和服務端的負載均衡器。
Netflix uses Zuul for the following:
* Authentication
* Insights
* Stress Testing
* Canary Testing
* Dynamic Routing
* Service Migration
* Load Shedding
* Security
* Static Response handling
* Active/Active traffic management
Zuul的規則和過濾器允許使用各種基于JVM的語言,支持基于Java和Groovy。
注意:zuul.max.host.connections已經被兩個新的屬性替代:zuul.host.maxTotalConnections 和 zuul.host.maxPerRouteConnections,默認分別為200和20.
注意:默認所有routes的Hystrix隔離模式(ExecutionIsolationStrategy)是SEMAPHORE zuul.ribbonIsolationStrategy可以改為THREAD,如果這個隔離模式更好。
How to Include Zuul
org.springframework.cloud and artifact id spring-cloud-starter-zuul。See the Spring Cloud Project page for details。
Embedded Zuul Reverse Proxy
當一個UI應用想要代理調用一個或者多個后臺服務的時候,Sping cloud創建了一個嵌入的Zuul proxy很方便的開發一個簡單的案例。這個功能對于代理前端需要訪問的后端服務非常有用,避免了所有后端服務需要關心管理CORS和認證的問題.
在Spring Boot主函數上通過注解 @EnableZuulProxy 來開啟, 這樣可以讓本地的請求轉發到適當的服務. 按照約定, 一個ID為”users”的服務會收到 /users 請求路徑的代理請求(前綴會被剝離). Zuul使用Ribbon定位服務注冊中的實例, 并且所有的請求都在hystrix的command中執行, 所以失敗信息將會展現在Hystrix metrics中, 并且一旦斷路器打開, 代理請求將不會嘗試去鏈接服務.
注意:Zuul starter沒有包含服務發現的客戶端, 所以對于路由你需要在classpath中提供一個根據service IDs做服務發現的服務.(例如, eureka是一個不錯的選擇)
去忽略一個自動添加的服務,可以在服務ID表達式列表中設置 zuul.ignored-services。如果一個服務匹配到了要忽略的列表, 但是它也明確的配置在路由列表中, 將不會被忽略, 例如:
application.yml zuul:ignoredServices: '*'routes:users: /myusers/**在這個例子中,所有的服務都會被忽略,除了“users”。
增加或改變代理路由規則, 你可以添加類似下面的外部配置:
application.ymlzuul:routes:users: /myusers/**這表示,HTTP調用 “/myusers” 會轉到 “user” 服務(例如:”/myusers/101”跳轉到”/101”)。
為了更細粒度的控制一個路由, 你可以獨立指定配置路徑和服務ID:
application.ymlzuul:routes:users:path: /myusers/**serviceId: users_service這表示,HTTP調用 “/myuser”會跳轉到”users_servie”服務。路由必須配置一個可以被指定為”ant路徑匹配原則”的”path”,所以“/myusers/”只能匹配一個層級, 但”/myusers/*“可以匹配多級.(附注:Ant path 匹配原則)
后端的配置既可以是”serviceId”(對于服務發現中的服務), 也可以是”url”(物理地址), 例如:
application.ymlzuul:routes:users:path: /myusers/**url: http://example.com/users_serviceurl-routes的方式不會執行 HystrixCommand 也不會通過Ribbon負載多個URLS。要實現這些,需給這個serviceid指定一個service-route并配置一個Ribbon client(這個必須在Ribbon中禁用Eureka: see above for more information)。
application.yml zuul:routes:users:path: /myusers/**serviceId: usersribbon:eureka:enabled: falseusers:ribbon:listOfServers: example.com,google.com你可以使用regexmapper提供serviceId和routes之間的綁定. 它使用正則表達式組來從serviceId提取變量, 然后注入到路由表達式中.
@Bean public PatternServiceRouteMapper serviceRouteMapper() {return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)","${version}/${name}"); }這表示serviceId “myusers-v1” 將會被映射到 “/v1/myusers/“.任何正則表達式都可以,但是所有的命名組都必須在servicePattern和routePattern中存在。如果servicePattern沒有匹配到一個serviceId,默認的行為會被啟用。在上面的例子中,serviceId”myusers”將會映射到”/myusers/“(沒有發現版本)這個特性默認是禁用的,而且只用于發現的服務。
給所有映射添加前綴,可以設置 zuul.prefix 一個值,比如/api。這個前綴默認會刪除,在請求跳轉之前。(通過 zuul.stripPrefix=false 可以關閉這個功能)。你也可以在單個服務中關閉這個功能, 例如:
application.ymlzuul:routes:users:path: /myusers/**stripPrefix: falsezuul.stripPrefix只使用于使用了zuul.prefix配置情況下。在一個定義好了的 route’s path中不會有任何影響。
在這個例子中,”users”service的請求”/myusers/101”將會跳轉到”/myusers/101”。
zuul.routes 實際上綁定到類型為 ZuulProperties 的對象上. 如果你查看這個對象你會發現一個叫”retryable”的字段, 設置為”true”會使Ribbon客戶端自動在失敗時重試(如果你需要修改重試參數, 可以使用Ribbon client configuration)
X-Forwarder-Host請求頭默認添加到轉發請求中。設置zuul.addProxyHeaders=false禁用它。路徑前綴默認被刪除,
到后臺服務的請求會添加一個 “X-Forwarded-Prefix”(“/myusers”在上面的例子中)。
一個@EnableZuulProxy的應用可以作為單機使用如果你設置了一個默認路由(”/”),例如zuul.route.home: / 會把所有的請求(”/**”)轉到home服務。
如果需要更細粒度的忽略配置,你可以指定特殊的表達式來配置忽略規則.這些表達式從route location的開始進行匹配,意味著前綴應該被包括在匹配表達式中. 忽略表達式影響所有服務和取代任何路由的特殊配置.
application.ymlzuul:ignoredPatterns: /**/admin/**routes:users: /myusers/**這個的意思是所有請求, 比如”/myusers/101”的請求會跳轉到”users”服務的”/101”, 但包含”/admin/”的請求將不被處理.
Zuul Http Client
默認的zull的Http clietn現在是Apach HTTP Client,替代了已過期的Ribbon RestClient。想使用RestClient或使用okhttp3.OKHttpClient,可以設置ribbon.restclient.enable=true或者ribbon.okhttp.enable=true。
Cookies and Sensitive Headers
在同一個系統的多個服務之間中分享headers是可以的,但是你可能不想把一些敏感headers泄露到下游服務器。你可以指定一批忽略的headers列表在路由配置中。Cookies扮演了一個特殊的角色, 因為他們很好的在瀏覽器中定義, 而且他們總是被認為是敏感的. 如果代理的客戶端是瀏覽器, 則對于下游服務來說對用戶, cookies會引起問題, 因為他們都混在一起。(所有下游服務看起來認為他們來自同一個地方)。
如果你對于你的服務設計很細心,比如,如果只有一個下游的服務設置了cookies,你可能會讓它從后端服務一直追溯到前端調用者,如果你的代理設置了cookies而且所有你的后端服務都是同一系統的一部分,它可以很自然的共享(比如使用spring session去聯系一些共享狀態)。除此之外,任何下游服務設置的cookies可以能不會對前端調用者產生作用。所以建議對不屬于你的域名的部分在routes里將 “Set-Cookie”和“Cookie”添加到敏感headers。 即使是屬于你的域名的路由, 嘗試仔細思考在允許cookies流傳在它們和代理之間意味著什么。
每個路由中的敏感頭部信息配置按照逗號分隔, 例如:
application.ymlzuul:routes:users:path: /myusers/**sensitiveHeaders: Cookie,Set-Cookie,Authorizationurl: https://downstream敏感headers也支持全局設置 zuul.sensitiveHeaders. 如果在單個路由中設置 sensitiveHeaders 會覆蓋全局 sensitiveHeaders 設置.
注意: 這是sensitiveHeaders 的默認值, 你無需設置除非你需要不同的配置. 注意. 這是Spring Cloud Netflix 1.1的新功能(在1.0中, 用戶無法直接控制請求頭和所有cookies).
Ignored Headers
除了每個route敏感頭以外, 你可以設置一個全局的 zuul.ignoredHeaders 在下游相互調用間去丟棄這些值(包括請求和響應). 如果沒有將Spring Security 添加到運行路徑中, 他們默認是空的, 否則他們會被Spring Secuity初始化一批安全頭(例如 緩存相關). 在這種情況下, 假設下游服務也可能添加這些頭信息, 我希望從代理獲取值.
The Routes Endpoint
如果你使用 @EnableZuulProxy 同時引入了Spring Boot Actuator, 你將默認增加一個endpoint, 提供http服務的 /routes. 一個GET請求將返回路由匹配列表. 一個POST請求將強制刷新已存在的路由.(比如, 在服務catalog變化的場景中)
注意:路由列表應該自動應答服務登記變化, 但是POST是一種強制立即更新的方案.
窒息模式和本地跳轉(Strangulation Patterns and Local Forwards)
一個常見的遷移舊應用或者舊接口的方式,就是逐步的替換它的實現。 Zuul代理是一種很有用的工具, 因為你可以使用這種方式處理所有客戶端到舊接口的請求. 只是重定向了一些請求到新的接口.
實例配置:
application.ymlzuul:routes:first:path: /first/**url: http://first.example.comsecond:path: /second/**url: forward:/secondthird:path: /third/**url: forward:/3rdlegacy:path: /**url: http://legacy.example.com在這個例子中,我們替換了 “legacy” ,它映射到所有的請求,但是沒有匹配到其他任何一個請求。路徑 /first/* 指向了一個額外的URL. 并且路徑 /second/* 是一個本地跳轉. 比如, 帶有Spring注解的 @RequestMapping . 路徑 /third/** 也是一個本地跳轉, 但是屬于一個不同的前綴. (比如 /third/foo 跳轉到 /3rd/foo )。
注意:忽略表達式并不是完全的忽略請求, 只是配置這個代理不處理這些請求(所以他們也是跳轉執行本地處理)。
Uploading Files through Zuul
如果你使用 @EnableZuulProxy , 你可以使用代理路徑上傳文件, 對于小文件可以正常使用. 對于大文件有可選的路徑”/zuul/“繞過Spring DispatcherServlet (避免處理multipart). 比如對于 zuul.routes.customers=/customers/* , 你可以使用 “/zuul/customers/*” 去上傳大文件. Servlet路徑通過 zuul.servletPath 指定. 如果使用Ribbon負載均衡器的代理路由, 在 處理非常大的文件時, 仍然需要提高超時配置. 比如:
application.yml hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000 ribbon:ConnectTimeout: 3000ReadTimeout: 60000注意: 對于大文件的上傳流, 你應該在請求中使用塊編碼. (有些瀏覽器默認不這么做). 比如在命令行中:
$ curl -v -H "Transfer-Encoding: chunked" \ -F "file=@mylarge.iso" localhost:9999/zuul/simple/filePlain Embedded Zuul
你可以運行一個沒有代理功能的Zuul服務, 或者有選擇的開關部分代理功能, 如果你使用 @EnableZuulServer (替代 @EnableZuulProxy ). 你添加的任何 ZuulFilter 類型 實體類都會被自動加載, 和使用 @EnableZuulProxy 一樣, 但不會自動加載任何代理過濾器.
在以下例子中, Zuul服務中的路由仍然是按照 “zuul.routes.*”指定, 但是沒有服務發現和代理, 因此”serviceId”和”url”配置會被忽略. 比如:
application.ymlzuul:routes:api: /api/**匹配所有的 “/api/**” 給Zuul過濾器鏈.
Disable Zuul Filters
在代理和服務模式下, 對于Spring Cloud, Zuul默認加入了一批 ZuulFilter 類. 查閱 the zuul filters package 去獲取可能開啟的過濾器. 如果你想關閉其中一個, 可以簡單的設置 zuul...disable=true . 按照約定, 在 filter 后面的包是Zuul過濾器類. 比如關閉 org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter , 可設置zuul.SendResponseFilter.post.disable=true.
通過Sidecar進行多語言支持(Polyglot support with Sidecar)
你是否有多語言的需要使用Eureka,Ribbon和Config server? Spring Cloud Netflix Sidecar 受 Netflix Prana 啟發。它引入了一個簡單的HTTP API去獲取所有服務實例的信息(比如host和port)。你也可以通過依賴Eureka的嵌入式Zuul代理器代理服務調用。Spring Cloud Config Server以通過host查找或Zuul代理直接訪問。其他語言需要實現一個健康檢查器,Sidecar才可以通知eureka這個額app是上線還是下線狀態。
引入Sidecar需要org.springframework.cloud and artifact id spring-cloud-netflix-sidecar.
開啟Sidecar, 需要創建一個包含 @EnableSidecar 的Springboot應用程序. 這個注解包括了 @EnableCircuitBreaker, @EnableDiscoveryClient 和 @EnableZuulProxy。Run the resulting application on the same host as the non-jvm application.
配置Sidecar, 添加 sidecar.port and sidecar.health-uri 到 application.yml 中. 屬性 sidecar.port 配置非jvm應用正在監聽的端口. 這樣Sidecar能夠注冊應用到 Eureka. sidecar.health-uri 是一個非JVM應用程序提供模仿SpringBoot健康檢查接口的可訪問的uri. 它應該返回一個json文檔類似如下:
health-uri-document {"status":"UP" }這個是Sidecar應用程序application.yml的列子:
application.yml server:port: 5678 spring:application:name: sidecarsidecar:port: 8000health-uri: http://localhost:8000/health.jsonapi方法DiscoveryClient.getInstances()的映射是/hosts/{serviceId}。這里是一個 /hosts/customers返回的示例,它返回了兩個實例在不同的hosts。這個API對于非JVM 應用程序是可訪問的. (如果sidecar監聽在5678端口上) http://localhost:5678/hosts/{serviceId}。
/hosts/customers [{"host": "myhost","port": 9000,"uri": "http://myhost:9000","serviceId": "CUSTOMERS","secure": false},{"host": "myhost2","port": 9000,"uri": "http://myhost2:9000","serviceId": "CUSTOMERS","secure": false} ]Zuul會自動的為每一個eureka的服務添加路由映射為/,所以/customers可以訪問到customers服務。非JVM的應用可以通過http://localhost:5678/customers(假設sidecar監聽在5678)。
如果Config Server注冊到Eureka,非JVM的應用可以通過Zuul proxy訪問。如果ConfigServer的serviceId是 configserver 而且Sidecar監聽在5678端口上, 則它可以通過 http://localhost:5678/configserver 訪問到.
非JVM應用可以使用ConfigServer的功能返回YAML文檔. 比如, 調用 http://sidecar.local.spring.io:5678/configserver/default-master.yml 可以返回如下文檔:
eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/password: password info:description: Spring Cloud Samplesurl: https://github.com/spring-cloud-samplesRxJava with Spring MVC
Spring Cloud Netflix引入了Rxjava
RxJava是一個Reactive Extensions的Java VM實現:它是一個使用可觀察數據流進行異步編程的編程接口,ReactiveX結合了觀察者模式、迭代器模式和函數式編程的精華,與異步數據流交互的編程范式。
Spring Cloud Netflix提供并支持從Spring MVC Controllers返回rx.Single對象. 它還支持使用 rx.Observable 對象,可觀察的對象為 Server-sent events (SSE). 如果你的內部api已經使用RxJava這會非常的方便(可以查看spring-cloud-feign-hystrix為例)。
這里有一些使用rx.Single的列子:
@RequestMapping(method = RequestMethod.GET, value = "/single") public Single<String> single() {return Single.just("single value"); }@RequestMapping(method = RequestMethod.GET, value = "/singleWithResponse") public ResponseEntity<Single<String>> singleWithResponse() {return new ResponseEntity<>(Single.just("single value"),HttpStatus.NOT_FOUND); }@RequestMapping(method = RequestMethod.GET, value = "/singleCreatedWithResponse") public Single<ResponseEntity<String>> singleOuterWithResponse() {return Single.just(new ResponseEntity<>("single value", HttpStatus.CREATED)); }@RequestMapping(method = RequestMethod.GET, value = "/throw") public Single<Object> error() {return Single.error(new RuntimeException("Unexpected")); }如果你使用 Observable, 而不Single, 你可以使用.toSingle() 或 .toList().toSingle(). 下面是些例子:
@RequestMapping(method = RequestMethod.GET, value = "/single") public Single<String> single() {return Observable.just("single value").toSingle(); }@RequestMapping(method = RequestMethod.GET, value = "/multiple") public Single<List<String>> multiple() {return Observable.just("multiple", "values").toList().toSingle(); }@RequestMapping(method = RequestMethod.GET, value = "/responseWithObservable") public ResponseEntity<Single<String>> responseWithObservable() {Observable<String> observable = Observable.just("single value");HttpHeaders headers = new HttpHeaders();headers.setContentType(APPLICATION_JSON_UTF8);return new ResponseEntity<>(observable.toSingle(), headers, HttpStatus.CREATED); }@RequestMapping(method = RequestMethod.GET, value = "/timeout") public Observable<String> timeout() {return Observable.timer(1, TimeUnit.MINUTES).map(new Func1<Long, String>() {@Overridepublic String call(Long aLong) {return "single value";}}); }如果你有一個流端點和客戶端,SSE可能是一個選項。使用 RxResponse.sse()將rx.Observable轉換到Spring 的SseEmitter. 以下是一些例子:
@RequestMapping(method = RequestMethod.GET, value = "/sse") public SseEmitter single() {return RxResponse.sse(Observable.just("single value")); }@RequestMapping(method = RequestMethod.GET, value = "/messages") public SseEmitter messages() {return RxResponse.sse(Observable.just("message 1", "message 2", "message 3")); }@RequestMapping(method = RequestMethod.GET, value = "/events") public SseEmitter event() {return RxResponse.sse(APPLICATION_JSON_UTF8,Observable.just(new EventDto("Spring io", getDate(2016, 5, 19)),new EventDto("SpringOnePlatform", getDate(2016, 8, 1)))); }Metrics: Spectator, Servo, and Atlas
什么鬼?以后再說。。。。。
總結
以上是生活随笔為你收集整理的Spring Cloud Netflix中文文档翻译笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正则表达式-RegExp-常用正则表达式
- 下一篇: 火影推荐程序连载6-径向模糊简介