微服务中的网络相关组件

网关 - Zuul

Filter

Zuul组件结构
Zuul 基于 Netty 开发,使用 filters 包含了核心业务逻辑,Filter 是使用 Groovy 写的,主要是为了提供动态编译加载的能力,filters 主要包含了三类:

  • Inbound Filters execute before routing to the origin and can be used for things like authentication, dynamic routing, rate limiting, DDoS protection, metrics and decorating the request.
  • Endpoint Filters can be used to return static responses, otherwise the built-in ProxyEndpoint filter will route the request to the origin.
  • Outbound Filters execute after getting the response from the origin and can be used for metrics, decorating the response to the user or adding custom headers.
  • Async
    Filter 可以被同步执行或异步执行。
    如果 Filter 没有做太重的工作,可以通过继承HttpInboundSyncFilterHttpOutboundSyncFilter来实现一种同步 Filter,例子见Zuul 源码中的Routes.groovy
    反之,如果需要从其他服务、缓存获取数据,或做一些复杂的计算工作,则最好继承HttpInboundFilterHttpOutboundFilter,例子见Zuul 源码中的SampleServiceFilter.groovy

Filter属性

Type: most often defines the stage during the routing flow when the Filter will be applied (although it can be any custom string)
Async: define if the filter is sync or async, generally meaning do you need to make an external call or just doing work on-box
Execution Order: applied within the Type, defines the order of execution across multiple Filters
Criteria: the conditions required in order for the Filter to be executed
Action: the action to be executed if the Criteria is met

其他的一些例子

这些例子是zuul-sample中的代码。

  • DebugRequest - look for a query param to add extra debug logging for a request
  • Healthcheck - simple static endpoint filter that returns 200, if everything is bootstrapped correctly
  • ZuulResponseFilter - add informational headers to provide extra details on routing, request execution, status and error cause
  • GZipResponseFilter - can be enabled to gzip outbound responses
  • SurgicalDebugFilter - can be enabled to route specific requests to different hosts for debugging

缓存请求体

默认情况下 Zuul 不会缓存请求体,因为 Filter 一般用到请求头就够了,但是如果需要在 inbound 中用到请求头或在 outbound 中用到响应头,则需要明确指定 Zuul 缓存,可以重写 Filter 的needsBodyBuffered()

1
2
3
4
@Override
boolean needsBodyBuffered(HttpResponseMessage input) {
return true
}

网络协议

Zuul 支持修改暴露服务时使用的协议,使用方法见 sample 项目中的SampleServerStartup

其他功能

Core Features

Push Messaging

Push Messaging 机制可以支持从 Server 端推送消息到 Client 端,支持两种协议:WebSocketsServer Sent Events (SSE)
Push Messaging
TODO

负载均衡 - Ribbon

使用

原生 API 如何使用见:Netflix / ribbon - Getting Started
如果是搭配 Spring Boot,可以参考 Spring Could 文档。

组件结构及实现

Rule

a logic component to determine which server to return from a list

  • RoundRobinRule
    简单的轮询策略
  • AvailabilityFilteringRule
    这个 Rule 会跳过那些疑似“电路跳闸”或并发连接数已经很高的服务器。
    比如客户端的最后 3 次连接失败,客户端会认为该服务实例已经出现了类似“电路跳闸”的问题而导致无法提供服务,于是在接下来的 30 秒内均保持这种状态,如果之后还是连接失败,这个等待时间会指数增长(1min、2min、4min…)。
  • WeightedResponseTimeRule
    每个 Server 会根据其平均响应时间计算出一个权重,响应时间越长、比重越小,该 Rule 选择 Server 时会根据该权重来计算概率。

Ping

a component running in background to ensure liveness of servers

ServerList

this can be static or dynamic. If it is dynamic (as used by DynamicServerListLoadBalancer), a background thread will refresh and filter the list at certain interval

  • 静态的 Server 列表
    可以在程序里写一个静态列表,将该列表设置到BaseLoadBalancer.setServerList()中。
  • ConfigurationBasedServerList
    默认的 ServerList 实现,可以通过 Archaius ConfigurationManager来设置 Server 列表。
  • DiscoveryEnabledNIWSServerList
    可以通过 Eureka Client 获取服务器列表,服务器集群必须通过 VipAddress 来定义:
    1
    2
    3
    myClient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 
    # the server must register itself with Eureka server with VipAddress "myservice"
    myClient.ribbon.DeploymentContextBasedVipAddresses=myservice

ServerListFilter

ServerListFilter 是DynamicServerListLoadBalancer的组件,用于过滤从ServerList返回的服务器列表,现在有两种实现:

  • ZoneAffinityServerListFilter
    过滤掉不在同一个 zone 内的服务器,除非 zone 内没有可用的服务器,这个 Filter 可以通过设置如下属性来启用(假设客户端名为 myclient、客户端的属性空间为 ribbon):
    1
    myclient.ribbon.EnableZoneAffinity=true
  • ServerListSubsetFilter
    可以保证客户端只能看到ServerList返回的全体服务器的一个固定子集,如果有服务器可用性较弱,则可以定期用新服务器替换老服务器。可以通过设置以下属性启用该Filter:
    1
    2
    3
    4
    5
    6
    myClient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 
    # the server must register itself with Eureka server with VipAddress "myservice"
    myClient.ribbon.DeploymentContextBasedVipAddresses=myservice
    myClient.ribbon.NIWSServerListFilterClassName=com.netflix.loadbalancer.ServerListSubsetFilter
    # only show client 5 servers. default is 20.
    myClient.ribbon.ServerListSubsetFilter.size=5

源码

com.netflix.loadbalancer.DynamicServerListLoadBalancer#updateListOfServers
com.netflix.loadbalancer.ServerList#getUpdatedListOfServers
com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList#obtainServersViaDiscovery
TODO

参考

常见实现

  1. Netflix/zuul
  2. Netflix/ribbon
  3. Netflix / Turbine