微服务中的网络相关组件
网关 - Zuul
Filter
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 没有做太重的工作,可以通过继承HttpInboundSyncFilter
或HttpOutboundSyncFilter
来实现一种同步 Filter,例子见Zuul 源码中的Routes.groovy
;
反之,如果需要从其他服务、缓存获取数据,或做一些复杂的计算工作,则最好继承HttpInboundFilter
或HttpOutboundFilter
,例子见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 | @Override |
网络协议
Zuul 支持修改暴露服务时使用的协议,使用方法见 sample 项目中的SampleServerStartup
。
其他功能
Push Messaging
Push Messaging 机制可以支持从 Server 端推送消息到 Client 端,支持两种协议:WebSockets
和 Server 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
3myClient.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
6myClient.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