`
m635674608
  • 浏览: 4931007 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Zuul:智能路由和过滤(译)

 
阅读更多

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.yml
 zuul:
  routes:
    users: /myusers/**

这表示,HTTP调用 “/myusers” 会转到 “user” 服务(例如:”/myusers/101”跳转到”/101”)。

为了更细粒度的控制一个路由, 你可以独立指定配置路径和服务ID:

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

这表示,HTTP调用 “/myuser”会跳转到”users_servie”服务。路由必须配置一个可以被指定为”ant路径匹配原则”的”path”,所以“/myusers/”只能匹配一个层级, 但”/myusers/*“可以匹配多级.(附注:Ant path 匹配原则

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

application.yml
 zuul:
  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: users

ribbon:
  eureka:
    enabled: false

users:
  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.yml
 zuul:
  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.yml
 zuul:
  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.yml
 zuul:
  routes:
    users:
      path: /myusers/**
      sensitiveHeaders: Cookie,Set-Cookie,Authorization
      url: 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.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 )。

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

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: 3000
  ReadTimeout: 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.yml
 zuul:
  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.

 

http://blog.csdn.net/chenqipc/article/details/53322830

 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics