打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
spring cloud

启动应用示例:

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

Netflix路由库提供@HystrixCommand调用 "javanica". Spring Cloud 在这个注解下自动包裹Spring beans进一个代理里面,被连接到了一个Hystrix断路由。断路器计算何时打开和关闭电路,并在失败的情况下做什么。

你可以使用commandProperties参数和@HystrixProperty注解的集合来配置@HystrixCommand。请见 here 更多细节. 请见 the Hystrix wiki 有关可用的属性。

传播安全上下文或使用 Spring Scopes(Propagating the Security Context or using Spring Scopes)

如果你想一些线程的本地的上下文传播到一个@HystrixCommand,默认声明将不会工作,因为他在线程池里执行命令。(在超时的情况下)。你可以切换Hystrix去使用同个线程让调用者使用一些配置,或直接在注解中,让它去使用不同的“隔离策略”。举例:

@HystrixCommand(fallbackMethod = "stubMyService",    commandProperties = {      @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")    })...

如果你使用@SessionScope@RequestScope同样适用。你会知道你要这么做,因为一个runtime异常说他不能找到作用域上下文。

健康指标(Health Indicator)

连接的断路器的状态也暴露在呼叫应用程序的/health端点中。

{    "hystrix": {        "openCircuitBreakers": [            "StoreIntegration::getStoresByLocationLink"        ],        "status": "CIRCUIT_OPEN"    },    "status": "UP"}

Hystrix 指标流(Hystrix Metrics Stream)

使Hystrix指标流包括依赖于spring-boot-starter-actuator。这将使/hystrix.stream流作为一个管理端点。

 <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-actuator</artifactId>    </dependency>

断路器: Hystrix 仪表盘(Circuit Breaker: Hystrix Dashboard)

Hystrix的主要作用是会采集每一个HystrixCommand的信息指标,把每一个断路器的信息指标显示的Hystrix仪表盘上。

运行Hystrix仪表板需要在spring boot主类上标注@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=<CLUSTERNAME>,如果集群的名称是default,集群参数可以忽略)。这个cluster参数必须和turbine.aggregator.clusterConfig匹配。从eureka返回的值都是大写的,因此我们希望下面的例子可以工作,如果一个app使用eureka注册,并且被叫做"customers":

turbine:  aggregator:    clusterConfig: CUSTOMERS  appConfig: customers

clusterName可以使用SPEL表达式定义,在turbine.clusterName。 默认值是appName,意思是eureka服务ID最终将作为集群的key,例如customers的 InstanceInfo有一个CUSTOMERS的appName。另外一个例子是turbine.clusterName=aSGName,将从AWS ASG name获取集群名称。作者例子:

turbine:  aggregator:    clusterConfig: SYSTEM,USER  appConfig: customers,stores,ui,admin  clusterName: metadata['cluster']

在这种情况下,集群名称从4个服务从其元数据映射,期望包含“SYSTEM”和“USER

所有的app使用default,你需要一个文字表达式(使用单引号):

turbine:  appConfig: customers,stores  clusterName: "'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.portturbine.stream.port 任一个,如果你使用了 spring-boot-starter-webspring-boot-starter-actuator ,那么你可以提供(使用Tomcat默认情况下) management.port 不同的端口,并打开这个单独的执行器端口

你可以把Dashboard指向Turbine Stream Server来代替个别Hystrix streams。如果Tubine Stream 使用你本机的8989端口运行,然后把 http://myhost:8989在流输入字段Hystrix仪表板 Circuits 将由各自的 serverId关缀,紧随其后的是一个点,然后是circuit 名称

Spring Cloud提供了一个 spring-cloud-starter-turbine-stream,包括了运行 Turibine Stream Server运行所需要的所有依赖,如spring-cloud-starter-stream-rabbit. 因为使用了Netty-based,所以你需要Java 8 运行此应用

客户端负载均衡器(Client Side Load Balancer: Ribbon)

在Ribbon一个核心概念是命名的客户端.每个负载 平衡器是共同组件的集合的一部分,通过远程服务器联系, 你把它作为应用程序开发者(例如,使用 @FeignClient注解)的名称,Spring Cloud创建一个新的整体使用RibbonClientConfiguration为每一个客户端命名的 ApplicationContext,这包含(除其他事项外)的ILoadBalancer,一个RestClient 实现和ServerListFilter

Spring clound 使用额外的配置(RibbonClientConfiguration)可以让你充分控制客户端, 使用@RibbonClient. 例子:

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

在这种情况下客户端组件由 RibbonClientConfiguration 和一些 FooConfiguration组成 (通常后者会覆盖前者)

FooConfiguration 必须有 @Configuration,而不是由主应用程序@ComponentScan收集,其他情况下会被 @RibbonClients共享,如果你使用@ComponentScan@SpringBootApplication,那么你应放入单独的,非同名的包下或明确@ComponentScan扫描的指定包。

Spring Cloud Netflix ribbon默认提供了以下beans (BeanType beanName: ClassName):

  • IClientConfig ribbonClientConfig: DefaultClientConfigImpl

  • IRule ribbonRule: ZoneAvoidanceRule

  • IPing ribbonPing: NoOpPing

  • ServerList<Server> ribbonServerList: ConfigurationBasedServerList

  • ServerListFilter<Server> ribbonServerListFilter: ZonePreferenceServerListFilter

  • ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer

创建一个bean来自其中一个类型,并把它放在一个@RibbonClient的配置(比如上面的FooConfiguration ), 允许你覆盖一个描述的Bean. 例:

@Configurationpublic class FooConfiguration {    @Bean    public IPing ribbonPing(IClientConfig config) {        return new PingUrl();    }}

这里用PingUrl替换NoOpPing.

在Eureka中使用Ribbon(Using Ribbon with Eureka)

当 Eureka 和 Ribbon 的 ribbonServerList 一起使用来自Eureka中被覆盖且扩展的 DiscoveryEnabledNIWSServerList服务器列表,它用IPing接口 和 NIWSDiscoveryPing 委托给Eureka来确保服务器是否启动,安装在ServerList缺省值为 DiscoveryEnabledNIWSServerList 这样的目的是使用物理元数据提供给负载均衡器,而无需使用AWS AMI元数据(这是Netflix的依赖),默认情况下,服务器列表将由“区域”中提供的信息实例元数据(远程客户端设置eureka.instance.metadataMap.zone),如果缺少它可以使用从服务器主机名作为区域代理的域名(如标志approximateZoneFromHostname设置)。一旦该区域信息可用它可以在一个ServerListFilter使用。默认情况下,将被使用在同一区域定位服务器作为客户端,因为默认是ZonePreferenceServerListFilter。的区域客户被确定相同的方式由缺省远程实例即通过eureka.instance.metadataMap.zone

NOTE:规范的 "archaius" 方式去设置客户端区,可以使用配置属性"@zone", Spring Cloud 将优先于所有的其他设置(注意:该重点将在 YAML 配置被引用)

NOTE:如果没有其他来源的区域数据则由基于客户机的配置(而不是实例配置).我们把 eureka.client.availabilityZones, 这是一个从区域名称映射到区域的列表,并拿出第一个区为实例自己的区域(即eureka.client.region, 默认为"us-east-1" 与 原生的Netflix comatibility)

示例: 没有Eureka时如何使用Ribbon(Example: How to Use Ribbon Without Eureka)

Eureka 是一种很方便的抽象方式去发现远程服务器,所以你不需要硬编码他们的客户端URL,但如果你不喜欢使用它,Ribbon 和 Feign 仍然经得起检验,假设你已经声明了 @RibbonClient 为 "stores", 与 Eureka 是不使用(甚至不能在类路径). Ribbon 客户端默认配置的服务器列,并且可以提供这样的配置

application.yml
stores:  ribbon:    listOfServers: example.com,google.com

禁用Eureka使用Ribbon(Example: Disable Eureka use in Ribbon)

设置属性ribbon.eureka.enabled = false, 使用Ribbon时禁用Eureka

application.yml
ribbon:  eureka:   enabled: false

直接使用Ribbon的API(Using the Ribbon API Directly)

你也可以直接使用 LoadBalancerClient,例子:

public class MyClass {    @Autowired    private LoadBalancerClient loadBalancer;    public void doStuff() {        ServiceInstance instance = loadBalancer.choose("stores");        URI storesUri = URI.create(String.format("http://%s:%s", instance.getHost(), instance.getPort()));        // ... do something with the URI    }}

声明REST Client:Feign(Declarative REST Client: Feign)

Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign.

Example spring boot app

@Configuration@ComponentScan@EnableAutoConfiguration@EnableEurekaClient@EnableFeignClientspublic class Application {    public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }}StoreClient.java@FeignClient("stores")public interface StoreClient {    @RequestMapping(method = RequestMethod.GET, value = "/stores")    List<Store> getStores();    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
 Store update(@PathVariable("storeId") Long storeId, Store store);}

 

在“@FeignClient”注解字符串值(上边的“stores”)是任意客户端名称,用于创建一个带负载均衡器(see< < spring-cloud-ribbon,支持> >)。您还可以指定一个URL使用的URL属性(绝对值或只是一个主机名)。应用程序上下文中的bean的名称是接口的完全有资格的名称。还创建一个别名就是“名称”属性加上“FeignClient”。在上面的示例中,“@qualifier(“storesFeignClient”)“可以用来指示bean。

Ribbon Client 想要发现上边提到 "stores" 服务的物理地址, 如果你的应用程序是 Eureka client的 则将在 Eureka 服务仓库里解决服务的注册, 如果你不想用Eureka, 你可以简单配置服务列表above for example).

覆盖Feign默认(Overriding Feign Defaults)

在Spring Cloud’s 的Feign支持的一个核心概念是命名的客户端.每个feign客户端是共同组件的集合的一部分,通过远程服务器联系, 你把它作为应用程序开发者(例如,使用 @FeignClient注解)的名称,Spring Cloud创建一个新的整体使用FeignClientsConfiguration为每一个客户端命名的 ApplicationContext,这包含(除其他事项外)的feign.Decoder,一个feign.Encoderfeign.Contract

Spring Cloud 可以在@FeignClient使用额外的配置(在FeignClientsConfiguration)完全控制feign客户端,例:

@FeignClient(name = "stores", configuration = FooConfiguration.class)public interface StoreClient {    //..}

在这种情况下,客户端是由组件已经在FeignClientsConfiguration连同任何FeignClientsConfiguration(后者将会覆盖前者)。

WARNING:FooConfiguration必须是@ Configuration但照顾它不是在@ ComponentScan为主要应用程序上下文,否则将被用于每个@ FeignClient。如果你使用@ComponentScan(或@ SpringBootApplication),你需要采取一些措施来避免它被列入(比如把它放在一个单独的,非重叠的包,或者指定包在@ComponentScan明确扫描

serviceId 已经过时,建议使用 name 属性

以前,使用 url 属性,则 name 不是必须的,但现在是必须的.

占位符支持 nameurl 属性.

@FeignClient(name = "${feign.name}", url = "${feign.url}")public interface StoreClient {    //..}

Spring Cloud Neflix Feign 默认提供了以下 Bean (BeanType beanName: ClassName):

  • Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)

  • Encoder feignEncoder: SpringEncoder

  • Logger feignLogger: Slf4jLogger

  • Contract feignContract: SpringMvcContract

  • Feign.Builder feignBuilder: HystrixFeign.Builder

Spring Coud Netflix Feign 默认不提以下Bean, 但仍可以从应用的上下文中查找以下类型创建 Feign 客户端.

  • Logger.Level

  • Retryer

  • ErrorDecoder

  • Request.Options

  • Collection<RequestInterceptor>

创建这些类型的一个bean可以放在@FeignClient配置中(如上FooConfiguration),允许你覆盖所描述的每一个bean. 例 子:

@Configurationpublic class FooConfiguration {    @Bean    public Contract feignContract() {        return new feign.Contract.Default();    }    @Bean    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {        return new BasicAuthRequestInterceptor("user", "password");    }}

可以替换SpringMvcContractfeign.Contract.Default, 并增加一个 RequestInterceptorRequestInterceptor 中去.

默认配置可在 @EnableFeignClients 属性, defaultConfiguration 通过类似的方式与上述被指定,不同的是,该结构将适用于 所有的 Feign 客户端.

Feign Hystrix Support

如果 Hystrix 在 classPath下, 默认情况下 将包括 Feign 与 断路器所有的方法。 返回一个 com.netflix.hystrix.HystrixCommand 去使用,允许您使用反应模式 ( 调用.toObservable().observe() 或异步使用 ( .queue()).

要禁用Feign 的 Hystrix支持,设置feign.hystrix.enabled=false.

要在每个客户端上禁用 Hystrix 支持,创建一个 Feign.Builder 并将scope 设置为"prototype",例如:

@Configurationpublic 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 {    @Override    public Hello iFailSometimes() {        return new Hello("fallback");    }}

有一个局限性,Feign的回退实现与Hystrix的回退一起工作, Fallbacks 目前不支持返回com.netflix.hystrix.HystrixCommand and rx.Observable的方法

Feign Inheritance Support

Feign 支持通过单继承接口样板的API。 这使得分组常见的操作方便的进入基本接口.

UserService.java
UserService.javapublic interface UserService {    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")    User getUser(@PathVariable("id") long id);}UserResource.java@RestControllerpublic class UserResource implements UserService {}UserClient.javapackage project.user;@FeignClient("users")public interface UserClient extends UserService {}

它通常是不可取的共享服务器和客户机之间的接口。它引入了紧耦合,也其实并不在其目前的形式与Spring MVC的工作(方法参数映射不继承)。

Feign 请求/响应 压缩(Feign request/response compression)

你可考虑启用请求或响应的 GZIP 压缩 Feign 的请求, 你可以通过启用一个属性做到这一点:

feign.compression.request.enabled=truefeign.compression.response.enabled=true

Feign 请求压缩设置和您的web服务器请求压缩设置类似。

feign.compression.request.enabled=truefeign.compression.request.mime-types=text/xml,application/xml,application/jsonfeign.compression.request.min-request-size=2048

 

用这些属性可以有选择性的对压缩介质和最低要求的阈值。

Feign logging

日志是为每个创建Feign客户端创建, 默认的日志名称是用于创建Feign客户端接口的完整类名,Feign日志只响应 DEBUG 级别。

application.ymllogging.level.project.user.UserClient: DEBUG

你能为每个客户端配置Logger.Level 对象,记录许多的日志,选项包括:

  • NONE, No logging (DEFAULT).

  • BASIC, Log only the request method and URL and the response status code and execution time.

  • HEADERS, Log the basic information along with request and response headers.

  • FULL, Log the headers, body, and metadata for both requests and responses.

  • NONE, 不记录 (DEFAULT).

  • BASIC, 仅记录请求方式和URL及响应的状态代码与执行时间.

  • HEADERS, 日志的基本信息与请求及响应的头.

  • FULL, 记录请求与响应的头和正文及元数据.

例如:以下设置Logger.LevelFULL:

@Configurationpublic class FooConfiguration {    @Bean    Logger.Level feignLoggerLevel() {        return Logger.Level.FULL;    }}

外部配置: Archaius(External Configuration: Archaius)

Archaius Exampleclass ArchaiusTest {    DynamicStringProperty myprop = DynamicPropertyFactory            .getInstance()            .getStringProperty("my.prop");    void doSomething() {        OtherClass.someMethod(myprop.get());    }}

Archaius有它自己的一套配置文件和负载优先级, Spring 应用程序通常不应直接应用Archaius, 本身仍然有配置Netflix工具的需求, Spring Cloud 环境以桥接方式让Archaius要以阅读Spring 的环境属性, 在大多数情况下,这允许 Spring boot项目中使用正常的配置工具链,同时让他们配置Netflix工具,作为记录

路由和过滤器:Zuul(Router and Filter: Zuul)

路由是微服务架构中不可或缺的一部分。比如,/ 可能需要映射到你的web应用, /api/users 映射到用户服务, /api/shop 映射到商城服务. 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

  • 认证

  • Insights

  • 压力测试

  • 金丝雀测试

  • 动态路由

  • 服务迁移

  • 负载削减

  • 安全

  • 静态响应处理

  • 主动/主动交换管理

Zuul的规则引擎允许通过任何JVM语言来编写规则和过滤器, 支持基于Java和Groovy的构建。

配置属性 zuul.max.host.connections 已经被两个新的配置属性替代, zuul.host.maxTotalConnectionszuul.host.maxPerRouteConnections, 默认值分别是200和20.

嵌入Zuul反向代理(Embedded Zuul Reverse Proxy)

Spring Cloud创建了一个嵌入式Zuul代理来缓和急需一个UI应用程序来代理调用一个或多个后端服务的通用需求, 这个功能对于代理前端需要访问的后端服务非常有用, 避免了所有后端服务需要关心管理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.yml zuul:  routes:    users: /myusers/**

这个意味着http请求"/myusers"将被转发到"users"服务(比如 "/myusers/101" 将跳转到 "/101")

为了更细致的控制一个路由, 你可以直接配置路径和服务ID:

application.yml zuul:  routes:    users:      path: /myusers/**      serviceId: users_service

这个意味着HTTP调用"/myusers"被转发到"users_service"服务. 路由必须配置一个可以被指定为ant风格表达式的"path", 所以“/myusers/*”只能匹配一个层级, 但"/myusers/**"可以匹配多级.

后端的配置既可以是"serviceId"(对于服务发现中的服务而言), 也可以是"url"(对于物理地址), 例如:

application.yml zuul:  routes:    users:      path: /myusers/**      url: http://example.com/users_service

这个简单的"url-routes"不会按照 HystrixCommand 执行, 也无法通过Ribbon负载均衡多个URLs. 为了实现这一指定服务路由和配置Ribbon客户端(这个必须在Ribbon中禁用Eureka: 具体参考更多信息), 例如:

application.ymlzuul:  routes:    users:      path: /myusers/**      serviceId: usersribbon:  eureka:    enabled: falseusers:  ribbon:    listOfServers: example.com,google.com

你可以使用regexmapper提供serviceId和routes之间的绑定. 它使用正则表达式组来从serviceId提取变量, 然后注入到路由表达式中.

ApplicationConfiguration.java
@Beanpublic PatternServiceRouteMapper serviceRouteMapper() {    return new PatternServiceRouteMapper(        "(?<name>^.+)-(?<version>v.+$)",        "${version}/${name}");}

这个意思是说"myusers-v1"将会匹配路由"/v1/myusers/**". 任何正则表达式都可以, 但是所有组必须存在于servicePattern和routePattern之中. 如果servicePattern不匹配服务ID,则使用默认行为. 在上面例子中,一个服务ID为“myusers”将被映射到路径“/ myusers/**”(没有版本被检测到),这个功能默认是关闭的,并且仅适用于服务注册的服务。

设置 zuul.prefix 可以为所有的匹配增加前缀, 例如 /api . 代理前缀默认会从请求路径中移除(通过 zuul.stripPrefix=false 可以关闭这个功能). 你也可以在指定服务中关闭这个功能, 例如:

application.yml
 zuul:  routes:    users:      path: /myusers/**      stripPrefix: false

在这个例子中, 请求"/myusers/101"将被跳转到"users"服务的"/myusers/101"上.

zuul.routes 实际上绑定到类型为 ZuulProperties 的对象上. 如果你查看这个对象你会发现一个叫"retryable"的字段, 设置为"true"会使Ribbon客户端自动在失败时重试(如果你需要修改重试参数, 直接使用Ribbon客户端的配置)

X-Forwarded-Host 请求头默认在跳转时添加. 通过设置 zuul.addProxyHeaders = false 关闭它. 前缀路径默认剥离, 并且对于后端的请求通过请求头"X-Forwarded-Prefix"获取(上面的例子中是"/myusers")

通过 @EnableZuulProxy 应用程序可以作为一个独立的服务, 如果你想设置一个默认路由("/"), 比如 zuul.route.home: / 将路由所有的请求(例如: "/**")到"home"服务.

如果需要更细力度的忽略, 你可以指定特殊的表达式来配置忽略. 这些表达式从路由位置的头开始匹配, 意味着前缀应该被包括在匹配表达式中. 忽略表达式影响所有服务和取代任何路由的特殊配置.

application.yml
 zuul:  ignoredPatterns: /**/admin/**  routes:    users: /myusers/**

这个的意思是所有请求, 比如"/myusers/101"的请求会跳转到"users"服务的"/101", 但包含"/admin/"的请求将不被处理.

Cookies和敏感HTTP头(Cookies and Sensitive Headers)

在同一个系统中服务间共享请求头是可行的, 但是你可能不想敏感的头信息泄露到内部系统的下游。 你可以在路由配置中指定一批忽略的请求头列表。 Cookies扮演了一个特殊的角色, 因为他们很好的被定义在浏览器中, 而且他们总是被认为是敏感的. 如果代理的客户端是浏览器, 则对于下游服务来说对用户, cookies会引起问题, 因为他们都混在一起。(所有下游服务看起来认为他们来自同一个地方)。

你得小心你的服务设计, 比如即使只有一个下游服务设置cookies, 你都必须让他们回溯设置所有的调用路线. 当然, 如果你的代理设置cookies和你所有后端服务是同一个系统的一部分, 它可以自然的被简单分享(例如, 使用spring session去将它们联系在一起共享状态). 除此之外, 任何被下游设置的cookies可能不是很有用, 推荐你对于不属于你域名部分的路由添加(至少)"Set-Cookie"和"Cookie" 到敏感头. 即使是属于你的域名的路由, 尝试仔细思考在允许cookies流传在它们和代理之间的意义

每个路由中的敏感头部信息配置按照逗号分隔, 例如:

application.yml zuul:  routes:    users:      path: /myusers/**      sensitiveHeaders: Cookie,Set-Cookie,Authorization      url: https://downstream

敏感头部也支持全局设置 zuul.sensitiveHeaders. 如果在单个路由中设置 sensitiveHeaders 会覆盖全局 sensitiveHeaders 设置.

注意: 这是sensitiveHeaders 的默认值, 你无需设置除非你需要不同的配置. 注. 这是Spring Cloud Netflix 1.1的新功能(在1.0中, 用户无法直接控制请求头和所有cookies).

除了per-route敏感头以外, 你可以设置一个全局的 zuul.ignoredHeaders 在下游相互调用间去丢弃这些值(包括请求和响应). 如果没有将Spring Security 添加到运行路径中, 他们默认是空的, 否则他们会被Spring Secuity初始化一批安全头(例如 缓存相关). 在这种情况下, 假设下游服务也可能添加这些头信息, 我希望从代理获取值.

路由Endpoint(The Routes Endpoint)

如果你使用 @EnableZuulProxy 同时引入了Spring Boot Actuator, 你将默认增加一个endpoint, 提供http服务的 /routes. 一个GET请求将返回路由匹配列表. 一个POST请求将强制刷新已存在的路由.(比如, 在服务catalog变化的场景中)

路由列表应该自动应答服务登记变化, 但是POST是一种强制立即更新的方案.

窒息模式和本地跳转(Strangulation Patterns and Local Forwards)

逐步替代旧的接口是一种通用的迁移现有应用程序或者API的方式, 使用不同的具体实现逐步替换它们. Zuul代理是一种很有用的工具, 因为你可以使用这种方式处理所有客户端到旧接口的请求. 只是重定向了一些请求到新的接口.

Example configuration:

配置样例:

application.yml
zuul:  routes:    first:      path: /first/**      url: http://first.example.com    second:      path: /second/**      url: forward:/second    third:      path: /third/**      url: forward:/3rd    legacy:      path: /**      url: http://legacy.example.com

在这个例子中我们逐步替换除了部分请求外所有到"legacy"应用的请求. 路径 /first/** 指向了一个额外的URL. 并且路径 /second/** 是一个跳转, 所以请求可以被本地处理. 比如, 带有Spring注解的 @RequestMapping . 路径 /third/** 也是一个跳转, 但是属于一个不同的前缀. (比如 /third/foo 跳转到 /3rd/foo )

忽略表达式并不是完全的忽略请求, 只是配置这个代理不处理这些请求(所以他们也是跳转执行本地处理)

通过Zuul上传文件(Uploading Files through Zuul)

如果你使用 @EnableZuulProxy , 你可以使用代理路径上传文件, 它能够一直正常工作只要小文件. 对于大文件有可选的路径"/zuul/*"绕过Spring DispatcherServlet (避免处理multipart). 比如对于 zuul.routes.customers=/customers/** , 你可以使用 "/zuul/customers/*" 去上传大文件. Servlet路径通过 zuul.servletPath 指定. 如果使用Ribbon负载均衡器的代理路由, 在 处理非常大的文件时, 仍然需要提高超时配置. 比如:

application.ymlhystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000ribbon:  ConnectTimeout: 3000  ReadTimeout: 60000

注意: 对于大文件的上传流, 你应该在请求中使用块编码. (有些浏览器默认不这么做). 比如在命令行中:

$ curl -v -H "Transfer-Encoding: chunked"     -F "file=@mylarge.iso" localhost:9999/zuul/simple/file

简单的嵌入Zuul(Plain Embedded Zuul)

你可以运行一个没有代理功能的Zuul服务, 或者有选择的开关部分代理功能, 如果你使用 @EnableZuulServer (替代 @EnableZuulProxy ). 你添加的任何 ZuulFilter 类型 实体类都会被自动加载, 和使用 @EnableZuulProxy 一样, 但不会自动加载任何代理过滤器.

在以下例子中, Zuul服务中的路由仍然是按照 "zuul.routes.*"指定, 但是没有服务发现和代理, 因此"serviceId"和"url"配置会被忽略. 比如:

application.yml
 zuul:  routes:    api: /api/**

匹配所有路径 "/api/**" 给Zuul过滤器链.

关闭Zuul过滤器(Disable Zuul Filters)

在代理和服务模式下, 对于Spring Cloud, Zuul默认加入了一批 ZuulFilter 类. 查阅 the zuul filters package 去获取可能开启的过滤器. 如果你想关闭其中一个, 可以简单的设置 zuul.<SimpleClassName>.<filterType>.disable=true . 按照约定, 在 filter 后面的包是Zuul过滤器类. 比如关闭 org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter , 可设置zuul.SendResponseFilter.post.disable=true.

通过Sidecar进行多语言支持(Polyglot support with Sidecar)

你是否有非jvm语言应用程序需要使用Eureka, Ribbon和Config Server的功能? Spring Cloud Netflix Sidecar 受 Netflix Prana 启发. 它包含一个简单的HTTP API去获取所有注册的实例信息(包括host和port信息). 你也可以通过依赖Eureka的嵌入式Zuul代理器代理服务调用. The Spring Cloud Config Server可以通过host查找 或Zuul代理直接进入. 非JVM应用程序提供健康检查实现即可让Sidecar向eureka同步应用程序up还是down.

为了开启Sidecar, 创建一个包含 @EnableSidecar 的Springboot应用程序. 这个注解包括了 @EnableCircuitBreaker, @EnableDiscoveryClient@EnableZuulProxy . 运行这个程序在非jvm程序的同一台主机上.

配置Sidecar, 添加 sidecar.port and sidecar.health-uriapplication.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: 5678spring:  application:    name: sidecarsidecar:  port: 8000  health-uri: http://localhost:8000/health.json

DiscoveryClient.getInstances() 方法的API是 /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中的服务, 路径为 /<serviceId> , 也就是customers服务可以通过 /customers 代理到. 非JVM应用程序可以通过 http://localhost:5678/customers 访问customer服务(假设sidecar监听在5678端口上).

如果配置服务已经在eureka里注册, 非JVM应用可以通过Zuul代理访问到它. 如果ConfigServer的serviceId是 configserver 和Sidecar监听在5678端口上, 则它可以通过 http://localhost:5678/configserver 访问到.

非JVM应用可以使用ConfigServer的功能返回YAML文档. 比如, 调用 http://sidecar.local.spring.io:5678/configserver/default-master.yml 可以返回如下文档:

client:    serviceUrl:      defaultZone: http://localhost:8761/eureka/  password: passwordinfo:  description: Spring Cloud Samples  url: https://github.com/spring-cloud-samples

RxJava 与 Spring MVC(RxJava with Spring MVC)

RxJava是一个Java VM实现http://reactivex.io /(Reactive Extensions):是一个使用可观察数据流进行异步编程的编程接口,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 = "/throw")public Single<Object> error() {    return Single.error(new RuntimeException("Unexpected"));}

如果你有一个 Observable, 而不是单一的, 你可以使用.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>() {        @Override        public 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))    ));}

指标: Spectator, Servo, and Atlas(Metrics: Spectator, Servo, and Atlas)

当Spectator/Servo 和 Atlas一起使用时, 提供一个接近实时操作的平台.

Spectator 和 Servo 的metrics的标准收集库. Atlas 是 Netflix 的一个后端指标 管理多维时间序列数据。

Servo为netflix服务多年,仍然是可用的,但逐渐被淘汰,取而代之的是Spectator ,仅仅是为了与java8工作, Spring Cloud Netflix 两者都支持, 但使用java8的推荐使用Spectator.

Dimensional vs. Hierarchical Metrics

Spring Boot Actuator指标等级和指标是分开的,这些名字常常遵循命名约定,嵌入key/value attribute 隔着时间的名称。考虑以下指标为两个端点,root 和 star-star:

{    "counter.status.200.root": 20,    "counter.status.400.root": 3,    "counter.status.200.star-star": 5,}

第一个指标为我们提供了一个规范化的成功请求的时间单位根节点. 归一化计算对根节点成功请求的时间. 但是如果系统有20个节点和你想要一个对所有节点成功请求的计数呢? 分级指标后端将允许您指定一个 counter.status.200. 阅读所有20个指标和聚合的结果.或者,你可以提供一个 HandlerInterceptorAdapter 拦截和记录所有成功的请求无论节点 counter.status.200.all , 但是现在你必须写20多个不同的指标。同样的如果你想知道所有节点成功请求服务的总数, y您可以指定一个通配符 counter.status.2.*.

即使后端参次指标支持它的存在,命名一致性是很困难的. 特别是这些标签的位置名称字符串可以随着时间的推移,打破查询. 例如, 假设我们为HTTP方法上面的分级指标添加一个额外的dimension . 然后“counter.status.200.root”成为“counter.status.200.method.get.root”等等。我们的“counter.status.200 *’突然不再具有相同的语义。 此外 , 如果新dimension不是整个代码库应用均匀,某些查询可能会变得不可能。这很快就会失控。

Netflix metrics 标记 (又名 dimensional). 每个指标都有一个名字,但这一命名metric 可以包含多个数据和“标签”键/值对,允许更多查询的灵活性. 事实上, 数据本身是记录在一个特殊的标记中的.

记录Netflix Servo 或 Spectator, 一个计时器根节点上包含4统计和状态码,Spring Boot Actuator’s 计数的统计数据时相同的. 迄今为止如果我们遇到 HTTP 200 and 400 ,将会有8种可用数据点

{    "root(status=200,stastic=count)": 20,    "root(status=200,stastic=max)": 0.7265630630000001,    "root(status=200,stastic=totalOfSquares)": 0.04759702862580789,    "root(status=200,stastic=totalTime)": 0.2093076914666667,    "root(status=400,stastic=count)": 1,    "root(status=400,stastic=max)": 0,    "root(status=400,stastic=totalOfSquares)": 0,    "root(status=400,stastic=totalTime)": 0,}

 

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Spring Cloud netflix概览和架构设计
Spring Cloud微服务+SpringBoot视频教程
微服务框架
Spring Cloud全家桶主要组件及简要介绍
Spring Cloud架构的各个组件的原理分析
Spring Cloud 2021.0.1 移除了Hystrix、Zuul等Netflix组件
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服