原文地址: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的实例的心跳包,如果在配置的时间片内没有接收到心跳,这个实例通常就会被注册中心移除掉。
例子:

@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);
}}

(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。 例子:

application.yml
eureka:instance:statusPageUrl:https//${eureka.hostname}/infohealthCheckUrl:https//${eureka.hostname}/healthhomePageUrl:https//${eureka.hostname}/

(注意: 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’。

application.yml
eureka:client:healthcheck:enabled:true

警告: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实现了电子断路器模块。在一个微服务架构中它一般有多个服务调用层。
Hystrix

一个底层的服务错误会引起级联错误一直反馈到用户。当调用一个特定的服务到达一定的阀值后(20 failures in 5 seconds is the default in Hystrix),回路开启然后调用也不会成功。一些错误情况下可以由程序员提供
open circuit a fallback。
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。
例如:

@SpringBootApplication
@EnableCircuitBreaker
public class Application {public static void main(String[] args) {new SpringApplicationBuilder(Application.class).web(true).run(args);}
}@Component
public class StoreIntegration{@HystrixCommand(fallbakMethod="defaultStores")public Object getStore(Map<String,Object> parameters){//do stuff that might fail}public Object defaultStores(Map<String,Object> paramters) {return /*something useful*/;}
}

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仪表盘用一种高效的方式展示了断路器的健康数据。
Dashboard

如何引入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: customers

clusterName可以使用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的顶部)。
例如:

@Configuration
@RibbonClient(name="foo",configuration=FooConfiguration.class)
public class TestConfiguration{
}

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.com

Example:Disable Eureka use in Ribbon

设置property ribbon.eureka.enable=false将会明确的让Eureka的ribbon失效。

application.yml
ribbon:eureka:enabled: false

Using 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=true

Feign提供的压缩设置与你的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_service

url-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: false

zuul.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/file

Plain 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.json

api方法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-samples

RxJava 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中文文档翻译笔记相关推荐

  1. spring cloud NetFlix 学习笔记

    spring cloud 1.前言 1.1. 概括 1.2 .常见面试题 2. 微服务概述 2.1 什么是微服务? 2.2 微服务与微服务架构 2.3 微服务优缺点 2.4 微服务技术栈有那些? 2. ...

  2. SpringCloud学习笔记(1)- Spring Cloud Netflix

    文章目录 SpringCloud学习笔记(1)- Spring Cloud Netflix 单体应用存在的问题 Spring Cloud Eureka Eureka Server代码实现 Eureka ...

  3. SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用

    1. 什么是负载均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...

  4. SpringCloud学习笔记3:Spring Cloud Netflix 组件(五大神兽)

    一.Spring Cloud Netflix有哪些组件? eureka (提供服务注册与发现功能) ribbon(提供负载均衡功能) Feign(整合了ribbon和Hystrix,具有负载均衡和熔断 ...

  5. Java学习笔记分享之Spring Cloud Netflix篇(上)

    Spring Cloud Netflix Spring Cloud 是什么 [百度百科]Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基 ...

  6. Spring Cloud Netflix 知识整理

    1. Spring Cloud生态 1.1 Spring Cloud Netflix 一站式解决方案 服务注册与发现--Netflix Eureka 负载均衡: 客户端负载均衡--Netflix Ri ...

  7. Spring Cloud 微服务实战笔记

    Spring Cloud 微服务实战笔记 微服务知识 传统开发所有业务逻辑都在一个应用中, 开发,测试,部署随着需求增加会不断为单个项目增加不同业务模块:前端展现也不局限于html视图模板的形式,后端 ...

  8. Spring Cloud Netflix之Eureka上篇

    前言:Spring Cloud NetFlix这个项目对NetFlix中一些久经考验靠谱的服务发现,熔断,网关,智能路由,以及负载均衡等做了封装,并通过注解的或简单配置的方式提供给Spring Clo ...

  9. Spring Cloud Netflix Hystrix

    目录 一. Hystrix 简介 1 什么是灾难性雪崩效应 2 什么是 Hystrix 二. 服务降级 1 修改 application service 代码 2 application client ...

最新文章

  1. java response 对象_82 Java基础 Response对象
  2. python怎样给对象赋值_Python对象赋值、浅拷贝和深拷贝
  3. css教程之列表属性
  4. 阿里巴巴产品实习生N天
  5. Solr+Hbase多条件查(优劣互补)
  6. 数位dp从会打模板到不会打模板
  7. springCloud - 第9篇 - 同步配置文件(消息总线方式)
  8. linux服务器静态,为Linux服务器设置静态IP的方法
  9. 【转】Numpy三维数组的转置与交换轴
  10. integer超出范围_BigInteger:可以让超过Integer范围内的数据进行运算
  11. Camunda工作流引擎入门
  12. SVN项目提交错误,回退版本(svn项目回退指定版本)
  13. unity3d 破解
  14. docker容器怎么设置开机启动
  15. LTE学习笔记之接口协议
  16. cocos creator飞机大战总结
  17. 「认识AI:人工智能如何赋能商业」【10】大数据基本概念
  18. b是python文件二进制打开,Python核心编程16 ----- 文件的打开(读取),修改,关闭,二进制...
  19. Jenkins使用入门笔记
  20. B2B网页付款时,出现“对不起,未检测到签名控件”,不能正常支付

热门文章

  1. iapp将音量调至最大
  2. javaweb项目实训总结_JAVAWEB实训心得体会
  3. 主语从句、宾语从句、表语从句、同位语从句
  4. H265编码视频流媒体播放器EasyPlayer.js支持9宫格视频同屏播放的写法
  5. 企业与个人短视频变现技巧
  6. 弘辽科技:如何制定淘宝店铺推广计划?店铺推广包含哪些方面?
  7. 联想计算机如何进bois,联想电脑怎么进入bios 联想进入bios方法【图文】
  8. 靠2块钱月入4万:越朴素的方法,往往越挣钱
  9. 面试官怎样面试出合格的技术人员
  10. 文章开始同步到我的微信公众号