负载均衡
当过滤器需要获取到上游群集中主机的连接时,群集管理器使用负载平衡策略来确定选择哪个主机。 负载平衡策略是可插入的,并且在配置中以每个上游集群为基础进行指定。 请注意,如果没有为群集配置活动的运行状况检查策略,则所有上游群集成员都认为是正常的。
支持的负载平衡器
循环赛(Round robin)
这是一个简单的策略,每个健康的上游主机按循环顺序选择。
加权最低要求
请求最少的负载均衡器使用O(1)算法来选择两个随机健康主机,并挑选出活动请求较少的主机。 (研究表明,这种方法几乎与O(N)全扫描一样好)。如果群集中的任何主机的负载均衡权重大于1,则负载均衡器将转换为随机选择主机,然后使用该主机<权重>次的模式。这个算法对于负载测试来说简单而充分。在需要真正的加权最小请求行为的情况下(通常如果请求持续时间可变且长度较长),不应使用它。我们可能会在将来添加一个真正的全扫描加权最小请求变体来覆盖这个用例。
环哈希
环/模哈希负载平衡器对上游主机执行一致的哈希。该算法基于将所有主机映射到一个圆上,使得从主机集添加或移除主机的更改仅影响1 / N个请求。这种技术通常也被称为“ketama”哈希。一致的散列负载均衡器只有在使用指定要散列的值的协议路由时才有效。目前唯一实现的机制是通过HTTP路由器过滤器中的HTTP头值进行散列。默认的最小铃声大小是在运行时指定的。最小环大小控制环中每个主机的复制因子。例如,如果最小环大小为1024,并且有16个主机,则每个主机将被复制64次。环哈希负载平衡器当前不支持加权。
当使用基于优先级的负载均衡时,优先级也由散列选择,所以当后端集合稳定时,选定的端点仍然是一致的。
随机
随机负载均衡器选择一个随机的健康主机。如果没有配置健康检查策略,那么随机负载均衡器通常比循环更好。随机选择可以避免在发生故障的主机之后对集合中的主机造成偏见。
原始目的地
这是一个特殊用途的负载平衡器,只能与原始目标群集一起使用。上游主机是基于下游连接元数据选择的,即,连接被打开到与连接被重定向到特使之前传入连接的目的地地址相同的地址。新的目的地由负载均衡器按需添加到集群,并且集群定期清除集群中未使用的主机。原始目标群集不能使用其他负载平衡类型。
恐慌阈值
在负载均衡期间,Envoy通常只考虑上游群集中的健康主机。但是,如果集群中健康主机的比例过低,特使就会忽视所有主机的健康状况和平衡。这被称为恐慌阈值。默认的恐慌阈值是50%。这可以通过运行时配置。恐慌阈值用于避免主机故障在负载增加时在整个集群中级联的情况。
优先级
在负载均衡期间,Envoy通常只考虑配置在最高优先级的主机。对于每个EDS LocalityLbEndpoints,还可以指定一个可选的优先级。当最高优先级(P = 0)的端点健康时,所有的流量都将落在该优先级的端点上。由于最高优先级的端点变得不健康,交通将开始慢慢降低优先级。
目前,假定每个优先级级别由1.4的(硬编码)因子过度配置。因此,如果80%的终点是健康的,那么优先级依然被认为是健康的,因为80 * 1.4> 100。随着健康终点的数量下降到72%以下,优先级的健康状况低于100。的流量相当于P = 0的健康状态将进入P = 0,剩余的流量将流向P = 1。
假设一个简单的设置有2个优先级,P = 1 100%健康
P=0 healthy endpoints | Percent of traffic to P=0 | Percent of traffic to P=1 |
---|---|---|
100% | 100% | 0% |
72% | 100% | 0% |
71% | 99% | 1% |
50% | 70% | 30% |
25% | 35% | 65% |
0% | 0% | 100% |
如果P = 1变得不健康,它将继续从P = 0接受溢出负荷,直到健康P = 0 P = 1的总和低于100为止。此时,健康将被放大到“有效”健康 的100%。
P=0 healthy endpoints | P=1 healthy endpoints | Traffic to P=0 | Traffic to P=1 |
---|---|---|---|
100% | 100% | 100% | 0% |
72% | 72% | 100% | 0% |
71% | 71% | 99% | 1% |
50% | 50% | 70% | 30% |
25% | 100% | 35% | 65% |
25% | 25% | 50% | 50% |
随着更多的优先级被添加,每个级别消耗等于其“缩放”有效健康的负载,因此如果P = 0 P = 1的组合健康小于100,则P = 2将仅接收业务。
P=0 healthy endpoints | P=1 healthy endpoints | P=2 healthy endpoints | Traffic to P=0 | Traffic to P=1 | Traffic to P=2 |
---|---|---|---|---|---|
100% | 100% | 100% | 100% | 0% | 0% |
72% | 72% | 100% | 100% | 0% | 0% |
71% | 71% | 100% | 99% | 1% | 0% |
50% | 50% | 100% | 70% | 30% | 0% |
25% | 100% | 100% | 35% | 65% | 0% |
25% | 25% | 100% | 25% | 25% | 50% |
用伪算法来总结这一点:
代码语言:javascript复制
代码语言:javascript复制load to P_0 = min(100, health(P_0) * 100 / total_health)
代码语言:javascript复制health(P_X) = 140 * healthy_P_X_backends / total_P_X_backends
代码语言:javascript复制total_health = min(100, Σ(health(P_0)...health(P_X))
代码语言:javascript复制
代码语言:javascript复制load to P_X = 100 - Σ(percent_load(P_0)..percent_load(P_X-1))
代码语言:javascript复制
区域感知路由
我们使用以下术语:
- 始发/上游集群:特使将来自原始集群的请求路由到上游集群。
- 本地区域:包含始发和上游群集中的主机子集的同一区域。
- 区域感知路由:尽力将请求路由到本地区域中的上游群集主机。
在原始和上游群集中的主机属于不同区域的部署中,Envoy执行区域感知路由。在区域感知路由可以执行之前有几个先决条件:
- 发起和上游集群都不处于恐慌状态。
- 区域感知路由已启用。
- 原始群集与上游群集具有相同的区域数量。
- 上游集群有足够的主机。浏览此处获取更多信息。
区域感知路由的目的是尽可能多地向上游群集中的本地区域发送流量,同时在所有上游主机(每个上游主机(取决于负载平衡策略))上每秒大致保持相同数量的请求。
只要维持上游集群中每台主机的请求数量大致相同,特使就会尝试尽可能多地将流量推送到本地上游区域。决定Envoy路由到本地区域还是执行跨区域路由取决于本地区域中始发群集和上游群集中健康主机的百分比。在原始和上游集群之间的本地区的百分比关系有两种情况:
- 源群集本地区域百分比大于上游群集中的百分比。在这种情况下,我们不能将来自原始集群的本地区域的所有请求路由到上游集群的本地区域,因为这将导致所有上游主机的请求不平衡。相反,Envoy会计算可以直接路由到上游群集的本地区域的请求的百分比。其余的请求被路由到跨区域。特定区域是根据区域的剩余容量(该区域将获得一些本地区域业务量并且可能具有特使可用于跨区域业务量的额外容量)来选择。
- 发起群集本地区域百分比小于上游群集中的百分比。在这种情况下,上游集群的本地区域可以获得来自原始集群本地区域的所有请求,并且还有一定的空间允许来自发起集群中其他区域的流量(如果需要)。
请注意,使用多个优先级时,区域感知路由当前仅支持P = 0。
负载平衡器子集
特使可能被配置为根据附加到主机的元数据将上游集群中的主机划分为子集。路由然后可以指定主机必须匹配的元数据以便由负载平衡器选择,并且可以选择回退到预定义的一组主机(包括任何主机)。
子集使用集群指定的负载平衡器策略。原来的目标策略可能不能与子集一起使用,因为上游主机事先不知道。子集与区域感知路由兼容,但请注意,使用子集可能很容易违反上述的最小主机条件。
如果子集已配置且路由未指定元数据或没有与元数据匹配的子集,则子集负载均衡器将启动其后备策略。默认策略是NO_ENDPOINT,在这种情况下,请求失败,就好像群集没有主机一样。相反,ANY_ENDPOINT后备策略会在群集中的所有主机之间进行负载均衡,而不考虑主机元数据。最后,DEFAULT_SUBSET会导致回退在与特定元数据集匹配的主机之间进行负载均衡。
子集必须预定义为允许子集负载均衡器有效地选择正确的主机子集。每个定义都是一组键,可以转换为零个或多个子集。从概念上讲,每个具有定义中所有键的元数据值的主机都将被添加到特定于其键值对的子集中。如果没有主机拥有所有的密钥,那么定义就不会产生子集。可以提供多个定义,并且如果单个主机匹配多个定义,则其可以出现在多个子集中。
在路由期间,路由的元数据匹配配置用于查找特定的子集。如果存在具有由路由指定的确切密钥和值的子集,则该子集用于负载平衡。否则,使用回退策略。因此,集群的子集配置必须包含与给定路由具有相同密钥的定义,以便发生子集负载平衡。
此功能只能使用V2配置API启用。而且,主机元数据仅在使用群集的EDS发现类型时才受支持。子集负载平衡的主机元数据必须放在过滤器名称“envoy.lb”下。同样,路由元数据匹配条件使用“envoy.lb”过滤器名称。主机元数据可以是分层的(例如,顶级密钥的值可以是结构化值或列表),但子集负载平衡器仅比较顶级密钥和值。因此,当使用结构化值时,如果主机的元数据中出现相同的结构化值,那么路线的匹配条件只会匹配。
代码语言:javascript复制
例子
我们将使用所有值都是字符串的简单元数据。 假定定义了以下主机并将其与集群关联:
Host | Metadata |
---|---|
host1 | v: 1.0, stage: prod |
host2 | v: 1.0, stage: prod |
host3 | v: 1.1, stage: canary |
host4 | v: 1.2-pre, stage: dev |
集群可以启用子集负载平衡,如下所示:
代码语言:javascript复制---name: cluster-nametype: EDSeds_cluster_config:
eds_config:
path: '.../eds.conf'connect_timeout:
seconds: 10lb_policy: LEAST_REQUESTlb_subset_config:
fallback_policy: DEFAULT_SUBSET
default_subset:
stage: prod
subset_selectors:
- keys:
- v
- stage
- keys:
- stage
下表介绍了一些路由及其在集群中的应用结果。 通常,匹配标准将与匹配请求的特定方面的路由一起使用,例如路径或报头信息。
Match Criteria | Balances Over | Reason |
---|---|---|
stage: canary | host3 | Subset of hosts selected |
v: 1.2-pre, stage: dev | host4 | Subset of hosts selected |
v: 1.0 | host1, host2 | Fallback: No subset selector for “v” alone |
other: x | host1, host2 | Fallback: No subset selector for “other” |
(none) | host1, host2 | Fallback: No subset requested |
元数据匹配标准也可以在路由的加权群集上指定。 来自所选加权群集的元数据匹配条件将与路线中的条件合并并覆盖该条件:
Route Match Criteria | Weighted Cluster Match Criteria | Final Match Criteria |
---|---|---|
stage: canary | stage: prod | stage: prod |
v: 1.0 | stage: prod | v: 1.0, stage: prod |
v: 1.0, stage: prod | stage: canary | v: 1.0, stage: canary |
v: 1.0, stage: prod | v: 1.1, stage: canary | v: 1.1, stage: canary |
(none) | v: 1.0 | v: 1.0 |
v: 1.0 | (none) | v: 1.0 |
具有元数据的示例主机
具有主机元数据的EDS LbEndpoint:
代码语言:javascript复制---endpoint:
address:
socket_address:
protocol: TCP
address: 127.0.0.1
port_value: 8888metadata:
filter_metadata:
envoy.lb:
version: '1.0'
stage: 'prod'
具有元数据标准的示例路线
具有元数据匹配标准的RDS路由:
代码语言:javascript复制---match:
prefix: /route:
cluster: cluster-name
metadata_match:
filter_metadata:
envoy.lb:
version: '1.0'
stage: 'prod'