envoy集群管理
集群管理
上游集群,使用cluster manager进行管理,每个cluster主要由集群名称、端点组成,支持负载均衡策略、主动健康状态检查、被动健康状态检查、断路器
可静态配置、cds api动态获取,集群中每个成员由endpoint进行标识,可由用户静态配置,也可进行eds、dns服务发现
集群预热:
集群在服务器启动或 通过cds进行初始化时需要1个预热过程,在预热过程中有以下情况:
-
初始服务发现加载(dns、eds更新等)完成之前不可用
-
配置了主动健康状态检查机制时,envoy会主动发送健康状态监测请求报文至发现的每个上游主机,于是初始的主动健康检查完成前不可用
集群初始化完成前对envoy的其他组件来说是不可见的,但对需要更新的集群,在预热完成后通过与旧集群的原子交换来确保不会发生流量中断类的错误
服务发现机制
未采用完全一致的机制,使用的是假设主机以最终一致的方式加入或离开网格,它结合主动状态检查机制来判定集群的健康状态
健康与否的决策机制以完全分布式的方式进行,因此可以很好应对网络分区
为集群启动主机健康状态检查机制后,envoy
| 发现状态 | 健康检测成功 | 健康检测失败 |
|---|---|---|
| Discovered(发现) | 正常路由 | 路由失败 |
| Absent(缺失,之前有突然不见了) | 正常路由 | 路由失败/删除 |
集群服务发现类型:
- static:静态配置
- strict dns:严格dns,envoy将持续和异步的解析指定的dns目标,并将dns结果中的返回的每个ip地址视为上游集群中可用成员
- logical dns:逻辑dns,解析dns时如果有多个ip,只使用解析到的第一个ip。适用于必须通过dns访问的大规模web服务集群(正向代理访问公网时用)
- original destination:当传入连接通过iptables的redirect或toproxy target或使用代理协议重定向到envoy时,可用原始目标集群,istio再详细介绍
- endpoint discovery service:eds是基于grpc、rest-json api的xds管理服务器获取集群成员的服务发现方式
- custom cluster:enoy支持在集群配置的cluster_type字段中指定使用自定义集群发现机制
故障处理机制
在cluster处实现的机制:
- 超时
- 重试、可变重试延迟
- 主动健康检测、异常探测
- 连接池
- 断路器
健康状态检测
如果未在集群上配置健康状态检测,则始终认为是健康的,所以应该给每个集群配置健康检测
主动:
周期性发送探测
- http
- tcp/ip
- redis(向上游发送redis ping)
配置
局部配置,参考总配置
clusters:
- name: xx
load_assignment:
endpoints:
- lb_endpoints:
- endpoint:
health_check_config:
port_value: #自定义检测的端口
health_checks:
- timeout: 时间
interval: 时间 #间隔
initial_jitter: 时间 #初始化检测时间,单位ms
interval_jitter: 时间 #间隔检测时间点,单位ms
unhealth_threshold: int #检测几次才算不成功
healthy_threshold: int #检测几次算健康,初始化检测时成功1此就算健康
http_health_check: {} #http类型检测
host: 主机 #默认空时用集群名
path: 路径 #如/health,必选
service_name_master: 集群名 #验证目标集群名
request_headers_to_add: [] #向检测报文添加自定义头
request_headers_to_remove: [] #检测报文中删除标头
expected_statuses: [] #期望的响应码列表,默认200
start: 200
end: 399
tcp_health_check: {} #tcp类型检测,空则表示仅tcp发包判断网络连接
send: {} #请求匹配
recevie: [] #响应匹配
grpc_health_check: {} #grpc专用检测
custom_health_check: {} #自定义检测
reuse_connection: 布尔值 #是否在多次检测之间重用连接,默认true
no_traffic_interval: 时间 #定义未曾调度任何流量到集群时,端点健康检测时间间隔,一旦接受流量就转为正常的时间间隔
unhealthy_interval: 时间 #标记为unhealthy状态的端点的检测间隔,一旦重新标记为healthy就转为正常时间间隔
unhealthy_edge_interval: 时间 #端点标记为unhealthy状态时的检测间隔,随后转为unhealthy_interval
healthy_edge_interval: 时间 #端点刚被标记为healthy状态的检测间隔,随后转为interval
tls_opsions: {} #tls配置
transport_socket_match_criteria: {} #
被动:
通过异常探测(outlier detection)机制
支持异常值检测的过滤器:
-
http route
-
tcp proxy
-
redis proxy
支持以下类型异常检测
- 连续5xx: 所有非http route过滤器生成的错误也在内部映射为5xx错误
- 连续网关故障: 连续5xx的子集,单纯用于502、503、504
- 连续的本地原因故障: envoy无法连接到上游主机与上游主机通信被反复中断
- 成功率: 主机的聚合成功率数据阈值
确定主机异常->若没有驱逐(弹出)主机,且已驱逐数量低于允许的阈值,则驱逐主机->主机处于驱逐状态一段时间->超出时长后自动回复
配置:
局部配置,参考总配置
clusters:
- name: xx
outlier_detection:
consecutive_5xx: int #连续5xx错误而弹出主机之前,允许出现的连续5xx响应或本地原始错误数,默认5
interval: 时间 #弹射分析扫描之间的间隔,默认10s
base_ejection_time: 时间 #主机被弹出的基准时长,实际时长=基准时长*主机已弹出次数,默认30s,如第一次弹出30s,后面又挂了又弹出则是60s
max_ejection_percet: 百分比 #默认10。集群中允许弹出的主机比率,避免所有主机都弹出
enforcing_consecutive_5xx: int #连续5xx检测到主机异常时,主机被弹出的几率,可用于禁止弹出和缓慢弹出,默认100
enforcing_seccess_rate: int #成功率检测到主机异常时,主机被弹出几率,用于禁止弹出、缓慢弹出,默认100
success_rate_minimum_hosts: int #参与评估的最少主机数,如果集群的主机数少于此就不参加评估,默认5
success_rate_requests_volume: int #检测的1次间隔中,必须收集的总请求的最小值,默认100
success_rate_stdev_factor: int #用确定成功率异常值弹出的弹射阈值的因子,弹射阈值=均值-(因子*平均成功率标准差)。如需要1.3因子,则要设为1300。因子越大弹出概率越低
consecutive_gateway_failure: int #连续网关故障弹出主机的最少连续故障数,默认5
enforcing_consecutive_gateway_failure: int #连续网关故障检测到异常状态时,弹出主机的几率,默认0(表示,出现5xx错误也不弹出主机)
split_external_local_origin_errors: 布尔值 #是否区分本地原因导致的故障和外部故障,默认为false,true时,下面3个配置才能生效
consecutive_local_origin_failure: #因本地原因的故障弹出主机的最少次数,默认5
enforcing_consecutive_local_origin_failure: #基于连续的本地故障检测异常状态而弹出主机的几率,默认100
enforcing_local_origin_success_rate: #基于连续本地故障检测的成功率统计检测到异常状态而弹出主机的几率,默认100
failure_percentage_threshold: {} #确定基于故障百分比的
enforcing_failure_percentage: {} #
enforcing_failure_percentage_local_origin: {}
faulure_percentage_minimum_hosts: {}
failure_percentage_request_volume: {}
max_ejection_time: #主机弹出的最长时间,未指定则用默认值,300s,或对比base_ejection_time的最大值
例1:
连续返回3个5xx则弹出主机30s
consecutive_5xx: '3'
base_ejection_time: '30s'
例2:
网关错误弹出,10%时间内弹出(新服务上应该用不严格的规则)
consecutive_gate_failutre: '3'
base_ejection_time: '30s'
enforcing_consecutive_gateway_failure: '10'
例3:
弹出错误率低于集群平均值1个标准差的任何端点,统计信息每10s进行1次评估(集群主机少于10,10s内少于500个请求的主机不统计在内)(高流量、稳定的服务可使用统计信息来弹出平凡异常的主机)
interval: '10s'
base_ejection_time: '30s'
success_rate_minimum_hosts: '10'
success_rate_request_volume: '500'
success_rate_stdev_factor: '1000'
负载均衡策略
2种策略:
复杂场景可混合使用2种策略,全局负载均衡通过定义高级路由优先级和权重控制同级别流量;分布式负载均衡用于对系统中的微观变动作出反应(如主动健康检测)
全局负载均衡
通过单个具有全局权限的组件来统一鞠策负载机制,envoy的控制平面是该类组件之一,可通过制定各种参数来调整应用于各端点的负载
- 优先级
- 位置权重
- 端点权重
- 端点健康状态
分布式负载均衡
- envoy自身基于上游主机(区域感知)的位置、健康状态等确定如何分配负载的端点
- 主动健康检测
- 区域感知路由
- 负载均衡算法
负载均衡算法:
适合无状态调度算法:
有状态的应该结合路由哈希
- 轮询round_robin
- 最少连接数least_request
- 随机random
加权最少请求:least request
加权最少请求算法根据主机的权重相同或不同而使用不同的算法
所有主机的权重均相同时
复杂度为O(1)调度算法,它随机选择N个(默认为2,可配置)可用主机并从中挑选具有 最少活动请求的主机
研究表明,这种称之为P2C的算法效果不亚于O(N)复杂度的全扫描算法,它确保了集群中具有最 大连接数的端点决不会收到新的请求,直到其连接数小于等于其它主机
所有主机的权重并不完全相同时
也就是集群中的两个或更多的主机具有不同的权重
调度算法将使用加权轮询调度的模式,权重将根据主机在请求时的请求负载进行动态调整,方法 是权重除以当前的活动请求计数;如,权重为2且活动请求计数为4的主机的综合权重为:
2/4 = 0.5
该算法在稳态下可提供良好的平衡效果,但可能无法尽快适应不太均衡的负载场景; 与P2C不同,主机将永远不会真正排空,即便随着时间的推移它将收到更少的请求;
配置参数
least_request_lb_config:
choice_count: "{...}" # 从健康主机中随机挑选出多少个做为样本进行最少连接数比较
环哈希:ring hash
Envoy使用ring/modulo算法对同一集群中的上游主机实行一致性哈希算法,但它需要依赖于在路由中定义了相应的哈希策略时方才有效
- 通过散列其地址的方式将每个主机映射到一个环上
- 然后,通过散列请求的某些属性后将其映射在环上,并以顺时针方式找到最接近的对应主机从而完 成路由;
- 该技术通常也称为“ Ketama” 散列,并且像所有基于散列的负载平衡器一样,仅在使用协议路由指 定要散列的值时才有效;
为了避免环偏斜,每个主机都经过哈希处理,并按其权重成比例地放置在环上。最佳做法是显式设置:
-
minimum_ring_size
-
maximum_ring_size
并监视2个指标以确保请求的能得到良好的均衡 :
- min_hashes_per_host
- max_hashes_per_host
配置参数
ring_hash_lb_config:
minimum_ring_size: "{...}" #哈希环的最小值,环越大调度结果越接近权重酷比,默认为1024,最在值为8M
hash_function: "..." #哈希算法,支持XX_HASH和MURMUR_HASH_2两种,默认为前一种
maximum_ring_size: "{...}" #哈希环的最大值,默认为8M;不过,值越大越消耗计算资源
磁悬浮环哈希:maglev
Maglev是环哈希算法的一种特殊形式,它使用固定为65537的环大小,在需要一致哈希的任何地方,Maglev都可以取代环哈希(性能更好,更快的表查找建立时间、主机选择时间,但稳定性弱于环哈希)
环构建算法将每个主机按其权重成比例地放置在环上,直到环完全填满为止;例如:
主机A的权重为1,主机A将具有21,846项
主机B的权重为2,主机B将具有43,691项
总计65,537项
磁悬浮算法会尝试,将每个主机至少放置一次在表中(不管配置的主机和位置权重如何),因此在某些极端情况下,实际比例可能与配置的权重不同。最佳做法是监视2个指标以确保没有主机出现异常配置:
- min_entries_per_host
- max_entries_per_host
路由哈希策略
用于在路由中指定hash的内容,将请求报文的哪部分属性进行哈希运算并 映射至主机的哈希环上以完成路由
注意:
- 需配合集群hash才能实现效果
- 哈希策略的配置列表中,如果有配置多个规则,每个规则都是单独匹配,匹配完成后再进行合并
- 如果配置了路由哈希,但请求的内容,不能匹配到哈希规则,则不会按规则来,而是随机访问
- 若哈希策略将“terminal”属性设置为true,并且已经生成了哈希,则哈希算法将立即返 回,而忽略哈希策略列表的其余部分
适合场景:会话保持
- http标头哈希
- cookie哈希
- 源ip哈希
配置
局部配置,参考总配置
clusters:
- name:
...
load_assignment:
cluster_name:
endpoints:
- locality:
region: str
zone: str
sub_zone: str
lb_endpoints:
- endpoint: {}
load_balance_weight: str
metadata: {}
health_status: str
load_balance_weight: str
priority: str #优先级
policy: #负载均衡策略
drop_overloads: [] #过载保护机制,丢弃过载流量的机制
overprovisioning_factor: #整数值,超配因子(百分比),默认值为140,即1.4
endpoint_stale_after: 0 #过期时长,过期前未收到任何新流量分配的端点会被视为过时,并标记为不健康,默认0为永不过时
least_request_lb_config:
choice_count: 2 #选择指定数量主机进行对比,默认为2
lb_subset_lb_config: #负载均衡器子集
failback_policy: 回退策略 #默认NO_FAILBACK
default_subset: #使用回退策略DEFAULT_SUBSET时,使用的默认子集
k1: v1
subset_selectors: #子集选择器
- key: [A,B] #选择器中元数据的键列表,元数据中必须有A、B标签的
ring_hash_lb_config:
minimum_ring_size: 1024 #哈希环最小值,环越大结果越接近权重比,默认1024
maximum_ring_size: 8M #哈希环最大值,默认8M。值越大计算越消耗资源
hash_function: 算法 #支持xx_hash、murmum_hash,默认前一个
original_dst_lb_config: {}
common_lb_config:
healthy_panic_threshold: 50 #健康的恐慌阈值,默认50%,配置时生效,要禁用紧急模式,请设置为 0%
zone_aware_lb_config: {} #区域感知路由负载均衡的相关配置
routing_enabled: 100 #百分比,用于配置在大比例的请求流量上启用区域感知路由机制,默认为100%
min_cluster_size: 6 #配置区域感知路由需要的最小上游集群大小、上游集群大小小于指定的值时,即使配置区域感知路由也不会执行,默认值为6,取值范围:64位整数
locality_weighted_lb_config: {} #位置加权负载均衡,为特定区域加权,空就是开启,没有子参数。位置加权负载均衡与区域感知负载均衡互斥
ignore_new_hosts_until_first_hc: 布尔值 #是否在新加入的主机经历第一次健康检测前不做负载均衡
update_merge_window:
节点优先级及优先级调度
eds中,属于某个特定位置的1组端点为locality lb endpoints,有相同的:
- locality位置
- load_balancing_weight权重
- priority优先级
不同的权重、优先级,端点可以处理的流量比例就不同
优先级调度
envoy调度时仅挑选最高优先级的1组端点,并且只有当前优先级的所有端点均不可用时才进行故障切换,如:
- 最高优先级的端点不健康时,其中20%端点不可用,就将20%的流量转移到下一级优先级端点
超配因子
为1组端点配置,实现部分端点故障时,仍将大部分流量导向到本组内的端点
一般符合:1 < ? < 2
计算公式:
转移的流量=100%-健康端点比例超配因子
9=100-801.4 #仅转移9%流量
例:1.4的因子,20%故障比例时,所有流量继续保持在本组,当健康端点比例低于72%时,才将部分流量转移到次优先级端点
作用:A集群离客户区域近,部分端点故障后,优先用A集群,除非大部分不可用,才转到B集群区域
健康评分
当前优先级别可以处理流量的能力称为健康评分(健康主机比例*超配因子,上限为100%)
如果各个优先级的健康评分总和(总健康状态)小于100,则envoy会认为没有足够的健康端点来分配所有待处理的流量,此时,各级别会根据自身健康分值的比例重新分配100%的流量。
如:具有{20,30}健康评分的2个组(总健康状态为50),会被标准化,负载均衡比例为40%和60%
端点降级机制
同一个优先级内部的端点降级(备用端点)。工作方式类似在2个不同优先级之间的端点分配流量
非降级端点健康比例 * 超配因子 >= 100% 时,降级端点不承接流量
非降级端点健康比例 * 超配因子 > 100% 时,降级端点承接与100%差额部分流量
流量转移场景计算:
超配因子为:1.2,有3个优先级端点:0、1、2,各50%端点故障
- 0优先级端点,转移流量(100-50*1.2=40),健康评分(50*1.2=60)转移40%流量到1优先级端点
- 1优先级端点,转移流量(100-50*1.2=40),健康评分(50*1.2=60),转移40%流量到2优先级端点
- 2优先级端点,转移流量(100-50*1.2=40),健康评分(50*1.2=60),由于没有可用端点承接流量,且所有端点的健康评小于100,进行重新分配
- 所有级别重新分配100%的流量,确保3个优先级,能处理所有流量,可能0会承接80%,1和2会承接剩下20%
painc阈值
调度期间,envou仅考虑上游主机列表中的可用端点,如果可用端点较低时,会忽略所有端点健康状态,并将流量调度给所有端点(如50个端点,25个不可用,但避免引起雪崩,仍按50个端点调度),这个百分比就是painc阈值,也叫恐慌阈值,默认painc阈值为50%
用于避免在流量增长时导致主机故障进入级联状态。painc可与优先级一起使用
- 给定优先级中的可用端点数量下降时,envoy将部分流量转移到低优先级的端点,若在低优先级中找到的可以承接所有流量的端点,则忽略恐慌阈值;
- 否则envoy在所有优先级之间分配流量,并在给定优先级的可用性低于恐慌阈值时仍按所有主机可用的情况进行流量
位置加权负载均衡
为特定的locality做权重,所有区域的endpoint均可用时,则根据位置权重,做轮询调度
如:A区域权重为1,B区域权重为2,流量分配比例为:1:2,33%:67%
如果区域中部分端点不可用时envoy会按比例动态调整区域权重(端点也可配置超配因子,默认1.4),有效权重计算方式:
健康评分=140 * 可用端点 / 总端点
有效权重=自身权重 * min(100,健康评分) #取100和健康评分之间最小值,100代表不用转移流量到下级,小于100就要流量转移
流量比例=有效权重 / 总权重
如:区域A权重1,区域B权重2,B健康端点50%时,动态调整后权重:2*(1.4*0.5)=1.4,所以B区域流量分配为 1:1.4
同时配置优先级和权重时,调度步骤:
- 选最高优先级
- 最高优先级中最高权重区域
- 最高权重区域中选端点

注:位置加权和区域感知路由互斥(locality_weight_lb_config和zone_aware_lb_config二选一)
负载均衡器子集
envoy支持在1个集群中基于子集实现更细粒度的流量分发
先在集群的上游主机添加元数据(kv对),并使用子集选择器(分类元数据)将上游划分为子集,然后在路由配置中指定负载均衡器可以选择的且必须匹配的元数据的上游主机。实现向特定子集的路由
各子集内的主机间的负载均衡采用集群定义的策略(lb_policy)
回退策略
当配置了子集,但路由并未指定元数据或不存在指定元数据匹配的子集时,则子集负载均衡为其应用回退策略
- no_faillback,请求失败,类似集群中不存在任何主机,默认策略
- any_endpoint,在所有主机间进行调度,不再考虑主机元数据
- default_subset,调度到默认的子集,默认子集需要提前定义好
配置
必须先在集群配置元数据标签
...
routes:
- match:
route:
metadata_match: #子集负载均衡器使用的端点远忽局匹配条件。入股用了weighted_clusters,且内部定义了metadata_match,则元数据将被合并,weighted_cluster中定义的值优先。过滤器名称应使用envoy.lb
filter_metadata:
envoy.lb:
k1: v1
weighted_clusters: #加权负载均衡,允许流量做比例发给不同子集
clusters: #为每个目标集群定义专用的元数据匹配
- name: xx
weight: 权重
metadata_match: {}
clusters:
- name: xx
load_assignment:
cluster_name: xx
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: eds-1,port_value: 80 }
metadata:
filter_metadata:
envoy.lb:
version: '1.0'
stage: 'prod'
lb_subset_lb_config: #负载均衡器子集
failback_policy: 回退策略 #默认NO_FAILBACK
default_subset: #使用回退策略DEFAULT_SUBSET时,使用的默认子集
k1: v1
subset_selectors: #子集选择器
- key: [stage,version] #选择器中元数据的键列表,元数据中必须有stage,version标签的
failback_policy: 回退策略 #当前选择器专用的回退策略
locality_weight_aware: 布尔值 #是否将请求路由到子集时考虑端点的位置和位置权重(有一些bug)
scale_locality_weight: 布尔值 #是否将子集与主机中的主机比率来缩放每个位置的权重
panic_mode_any: 布尔值 #是否在配置回退策略,且其相应的子集无法找到主机时尝试从整个集群中选择主机
list_as_any: str
例:金丝雀流量分配
流量路由到有元数据是prod的线上环境,并且根据权重路由路由,90%流量到v1集群,10%流量到v2集群
...
routes:
- match:
prefix: '/'
route:
weighted_clusters:
clusters:
- name: v1_cluster
weight: 90
metadata_match:
filter_metadata:
envoy.lb:
version: '1.0'
- name: v2_cluster
weight: 10
metadata_match:
filter_metadata:
envoy.lb:
version: '2.0'
metadata_match:
filter_metadata:
envoy.lb:
stage: prod
区域感知路由
区域感知路由(zone aware routing)用于尽可能的向上游集群中的本地区域发送流量,并大致确保流量均衡分配至上游相关的所有端点,依赖于以下几个先决条件:
- 始发集群(客户端)和上游集群(服务端)都未处于恐慌模式
- 启用区域感知路由
- 始发集群和上游集群具有相同数量的区域
- 上游集群具有能承载所有请求流量的主机
envoy将流量路由到本地区域,还是跨区路由取决于始发集群和上游集群健康中健康主机百分比:
- 始发集群的本地区域百分比大于上游集群中本地区域的百分比:envoy计算可以直接路由到上游集群的本地区域的请求百分比,其余的请求被路由到其他区域
- 始发集群本地区域百分比小于上游集群中的本地区域百分比:可实现所有请求的本地区域路由,并可承载一部分其他区域的跨区路由
注:
- 目前区域感知路由仅支持0优先级
- 始发集群和上游集群属于不同区域的部署中,envoy执行区域感知路由(集群跨机房、多异地时好用)
- 与位置加权负载均衡互斥
熔断机制
上游服务(被调用端)因压力过大变得响应慢时,下游服务(调用者)通过暂时切断对上游的请求调用达到局部牺牲,保全上游或系统整体
熔断是分布式应用常用的流量管理模式,可让应用程序免受上游服务失败、延迟峰值等网络异常侵害
envoy在网络级别强制进行断路限制,不用独立配置和编码每个应用程序
熔断状态:
工作:请求到达时,如果访问失败,熔断器打开,等待30s时间,进入半打开状态,再允许部分请求进入,请求成功则恢复到关闭状态,否则继续恢复到打开状态
- 熔断打开:在固定时间窗口内,检测到失败指标达到指定的阈值时启动熔断
- 半熔断:断路器在工作一段时间后自动切换到半打开状态,并根据下次请求的返回结果判定状态切换。成功则关闭熔断,失败则切回熔断打开
- 熔断关闭:一定时长后,上游服务可能变得再次可用,下游即可关闭熔断

服务雪崩
多服务调度场景中,某上游服务因网络排故障或服务繁忙无法响应请求的时可能会导致多级上游调用者大规模级联故障,进而导致整个系统不可用,此为服务雪崩效应,如原调用链路为C-->B-->A,当A不可用,导致B也不可用,最后B不可用,C也不可用
断路器:
envoy支持多种类型的完全分布式断路机制,达到由其定义的阈值时,响应的断路器就会溢出,包括:
- 集群最大连接数: envoy同上游集群建立的最大连接数,仅适用http1.1,因为http2可以链路复用
- 集群最大请求数:在给定的时间,集群中的所有主机未完成的最大请求数,仅用途http2
- 集群可挂起的最大请求数:连接池满载时,允许的等待队列最大长度
- 集群活动并发重试次数:给定时间内集群中所有主机可执行的最大并发重试次数
- 集群最大并发连接池:可同时实例化出的最大连接池数量
每个断路器都可在每个集群及每个优先级的基础上进行配置和跟踪,可分别配置不同的设定
注:在Istio中,熔断的功能通过连接池和故障实例隔离(异常点检测)进行定义,而envoy的断路器仅对应于istio中的连接池功能
连接池和熔断器
熔断是基于连接池的,必须达到连接池定义的阈值,断路器才能触发
连接池常用指标:
- 最大连接数:在给定时间内,envoy与上游集群建立的最大连接数,仅用于http1.1
- 每个连接最大请求数:在给定时间内,上游集群中所有主机可处理的最大请求数,若设为1则禁言会话保持特性
- 最大请求重试次数:在指定时间内对目标主机最大重试次数
- 连接超时时间:tcp连接超时时间,最小值必须大于1ms。最大连接数和连接超时时间是对tcp和http都有效的通用连接设置
- 最大等待请求数:断路器溢出时,集群的upstream_rq_pending_overflow计数器会递增
熔断器的常用指标(istio上下文)
- 连续错误响应数:在1个检查周期内,连续出现5xx错误的个数,例502、503状态码
- 检查周期:周期内筛选响应码
- 隔离实例比例:上游实例中,允许被隔离的最大比例,采用向上取整,如有10个实例,13%则最多会隔离2个实例
- 最短隔离时间:实例第一次被隔离时间,之后每次隔离时间为:隔离次数*隔离时间
配置
clusters:
- name: xx
#连接池配置2项
connect_timeout: 10 #tcp超时时间,合理的配置可以改善服务调用导致的整个链接变慢的情况
max_requests_per_connection: 1024 #每个连接最大可承载的最大请求数,http1.1和2的连接池都受限于此配置(小于等于此处),无设置为无限制,1为禁用持久连接
#断路器配置
circuit_breakers: #熔断相关配置
threasholds: #适用于特定路由优先级的相关指标及阈值的列表
- priority: 优先级 #当前断路器的路由优先级
max_connections: 1024 #可发往上游集群的最大并发连接数,仅使用与http1,默认为1024,超过指定配置的连接将视为短路
max_pending_requests: 1024 #允许请求服务时,可挂起的最大请求数,默认为1024,超过配置值则短路。组合:当max_connections和此处都配置为1时,如果超过1个连接发起请求,envoy就会熔断,阻止后续的请求或连接
max_requests: 1024 #envoy可调度给上游集群的最大并发请求数,默认1024,仅用于http2
max_retries: 3 #最大重试次数,默认为3
track_remaining: false #为true时将公布统计数据显示断路器打开前所有剩余的资源数量,默认false
max_connection_pools: int #每个集群可同时打开的最大连接池数量,默认无限制
配置
...
route_config:
virtual_hosts:
- name: xx
routes:
- match:
route:
hash_policy: #路由hash策略,实现高级hash,当cluster使用hash时,需在此处配合使用。header、
- header:
header_name: 首部 #需要hash的首部名称
- cookie:
name: cookie名 #必选项
ttl: 时间 #过期时间,不存在带有ttl的cookie会自动生成,若ttl存在且为0,则生成的cookie是会话cookie
path: 路径 #cookie路径
- connection_properties:
source_ip: 布尔值 #是否源地址哈希
terminal: 布尔值 #是否启用哈希算法的短路标志,一旦当前策略生成哈希值,将不再考虑列表中后续的其他哈希策略(如源地址hash和首部哈希,其中一个满足就不再继续哈希)
metadata_match: #子集负载均衡器使用的端点的匹配条件。如果用了weighted_clusters,且内部定义了metadata_match,则匹配将被合并(与关系),weighted_cluster中定义的值优先。过滤器名称应使用envoy.lb
filter_metadata:
envoy.lb:
k1: v1
weighted_clusters: #基于权重的方式,路由到多个集群,可根据元数据标签匹配做流量分割,如90%流量到v1版本,10%流量到v2
clusters: #为每个目标集群定义专用的元数据匹配
- name: xx
weight: 权重
metadata_match:
filter_metadata:
envoy.lb:
k1: v1
clusters:
- name: xx #集群唯一名称,未提供alt_stat_name时会被用于统计信息中
alt_state_name: str #统计信息中使用的集群名称
type: 类型 #解析集群的类型
#static
#strict_dns
#logical_dns
#eds
#original_dst
dbs_lookup_family: V4_ONLY
connect_timeout: 10 #tcp超时时间,合理的配置可以改善服务调用导致的整个链接变慢的情况
max_requests_per_connection: 1024 #每个连接最大可承载的最大请求数,http1.1和2的连接池都受限于此配置(小于等于此处),无设置为无限制,1为禁用持久连接
circuit_breakers: #熔断相关配置
threasholds: #适用于特定路由优先级的相关指标及阈值的列表
- priority: 优先级 #当前断路器的路由优先级
max_connections: 1024 #可发往上游集群的最大并发连接数,仅使用与http1,默认为1024,超过指定配置的连接将视为短路
max_pending_requests: 1024 #允许请求服务时,可挂起的最大请求数,默认为1024,超过配置值则短路。组合:当max_connections和此处都配置为1时,如果超过1个连接发起请求,envoy就会熔断,阻止后续的请求或连接
max_requests: 1024 #envoy可调度给上游集群的最大并发请求数,默认1024,仅用于http2
max_retries: 3 #最大重试次数,默认为3
track_remaining: false #为true时将公布统计数据显示断路器打开前所有剩余的资源数量,默认false
max_connection_pools: int #每个集群可同时打开的最大连接池数量,默认无限制
lb_policy: 算法
#round_robin,加权轮询
#least_request,加权最少请求,所有主机权重相同时默认每次从2个节点对比,最空闲的处理请求(可修改对比节点数)。权重不同时,计算方法:权重为2,活动请求4,综合权重为2/4=0.5
#ring_hash,环哈希。一致性哈希。为避免环倾斜,最好设置环的大小,并监视min_hashes_per_host、max_hashed_per_host指标
#maglev,磁悬浮,类似环哈希,但哈希环固定为65537,如A权重为1,B权重为2,则A接管21486项,B接管43691项,会根据权重将整个环分配干净。需要监视前面所说2个指标。效率比环哈希快,稳定性差一点
#random,未配置健康检测策略时,随机算法比轮询好
#original_dst_lb,原始目标集群负载均衡,仅使用于原始目标集群调度
load_assignment: #为static、strict_dns、logical_dns类型的集群指定成员获取方式。eds类型使用eds_cluster_config配置
cluster_name: xx #负载均衡cluster中的端点,关联的集群,一般关联上文集群
endpoints: #可定义集群中不同区域下,多个端点
- locality: #定义节点位置,标识上游主机所处的位置
region:
zone:
sub_zone:
lb_endpoint: #属于指定位置的端点列表
- endpoint_name: 端点名
endpoint: #端点定义
socket_address: {address: ip或域名, port_value: 端口, protocol: 协议 } #端点地址标识
health_check_config:
port_value: int #自定义检测的端口
load_balancing_weight: 权重 #权重
metadata: {} #基于匹配的侦听器、过滤器、路由、端点等为过滤器提供额外信息的元数据,常用于提供服务配置、辅助负载均衡
filter_metadata:
envoy.lb:
version: '1.0'
stage: 'prod'
health_status: str #端点是eds发现时,用于管理式设定端点的健康状态,可用值有:unkown、healthy、unhealthy、draining、timeout、defraded
load_balancing_weight: 权重 #区域或优先级的权重,最小值为1。
priority: int #优先级,默认0为最高优先级
policy: #负载均衡策略
drop_overloads: [] #过载保护机制,丢弃过载流量的机制
overprovisioning_factor: #整数值,超配因子(百分比),默认值为140,即1.4
endpoint_stale_after: 0 #过期时长,过期前未收到任何新流量分配的端点会被视为过时,并标记为不健康,默认0为永不过时
least_request_lb_config:
choice_count: 2 #选择指定数量主机进行对比,默认为2
lb_subset_lb_config: #负载均衡器子集
failback_policy: 回退策略 #默认NO_FAILBACK
default_subset: #使用回退策略DEFAULT_SUBSET时,使用的默认子集
k1: v1
subset_selectors: #子集选择器
- key: [A,B] #选择器中元数据的键列表,元数据中必须有A、B标签的
failback_policy: 回退策略 #当前选择器专用的回退策略
locality_weight_aware: 布尔值 #是否将请求路由到子集时考虑端点的位置和位置权重(有一些bug)
scale_locality_weight: 布尔值 #是否将子集与主机中的主机比率来缩放每个位置的权重
panic_mode_any: 布尔值 #是否在配置回退策略,且其相应的子集无法找到主机时尝试从整个集群中选择主机
list_as_any: str
ring_hash_lb_config:
minimum_ring_size: 1024 #哈希环最小值,环越大结果越接近权重比,默认1024,最佳值为8M
maximum_ring_size: 8M #哈希环最大值,默认8M。值越大计算越消耗资源
hash_function: 算法 #支持xx_hash、murmum_hash,默认前一个
original_dst_lb_config: {}
common_lb_config:
healthy_panic_threshold: 50 #恐慌阈值,默认50%
zone_aware_lb_config: {} #区域感知路由负载均衡的相关配置
routing_enabled: 100 #百分比,用于配置在大比例的请求流量上启用区域感知路由机制,默认为100%
min_cluster_size: 6 #配置区域感知路由需要的最小上游集群大小、上游集群大小小于指定的值时,即使配置区域感知路由也不会执行,默认值为6,取值范围:64位整数
locality_weighted_lb_config: {} #位置加权负载均衡,为特定区域加权,空就是开启,没有子参数。位置加权负载均衡与区域感知负载均衡互斥
ignore_new_hosts_until_first_hc: 布尔值 #是否在新加入的主机经历第一次健康检测前不做负载均衡
update_merge_window:
transport_socket_matches: []
cluster_type: '{...}'
eds_cluster_config: '{...}'
per_connection_buffer_limit_bytes: '{...}'
health_checks: #主动健康状态监测
- timeout: 时间
interval: 时间 #间隔
initial_jitter: 时间 #初始化检测时间,单位ms
interval_jitter: 时间 #间隔检测时间点,单位ms
unhealth_threshold: int #检测几次才算不成功
healthy_threshold: int #检测几次算健康,初始化检测时成功1此就算健康
http_health_check: {} #http类型检测
host: 主机 #默认空时用集群名
path: 路径 #如/health,必选
service_name_master: 集群名 #验证目标集群名
request_headers_to_add: [] #向检测报文添加自定义头
request_headers_to_remove: [] #检测报文中删除标头
expected_statuses: [] #期望的响应码列表,默认200
start: 200
end: 399
tcp_health_check: {} #tcp类型检测,空则表示仅tcp发包判断网络连接
send: {} #请求匹配
recevie: [] #响应匹配
grpc_health_check: {} #grpc专用检测
custom_health_check: {} #自定义检测
reuse_connection: 布尔值 #是否在多次检测之间重用连接,默认true
no_traffic_interval: 时间 #定义未曾调度任何流量到集群时,端点健康检测时间间隔,一旦接受流量就转为正常的时间间隔
unhealthy_interval: 时间 #标记为unhealthy状态的端点的检测间隔,一旦重新标记为healthy就转为正常时间间隔
unhealthy_edge_interval: 时间 #端点标记为unhealthy状态时的检测间隔,随后转为unhealthy_interval
healthy_edge_interval: 时间 #端点刚被标记为healthy状态的检测间隔,随后转为interval
tls_opsions: {} #tls配置
transport_socket_match_criteria: {}
upstream_http_protocol_options: '{...}'
common_http_protocol_options: '{...}'
http_protocol_options: '{...}'
http2_protocol_options: '{...}'
typed_extension_protocol_options: '{...}'
dns_refresh_rate: '{...}'
dns_failure_refresh_rate: '{...}'
respect_dns_ttl: ...
dns_lookup_family: ...
dns_resolvers: []
use_tcp_for_dns_lookups: ...
outlier_detection: #异常点检测(被动检测),熔断相关
consecutive_5xx: int #连续5xx错误而弹出主机之前,允许出现的连续5xx响应或本地原始错误数,默认5
interval: 时间 #弹射分析扫描之间的间隔,默认10s
base_ejection_time: 时间 #主机被弹出的基准时长,实际时长=基准时长*主机已弹出次数,默认30s,如第一次弹出30s,后面又挂了又弹出则是60s
max_ejection_percet: 百分比 #默认10。集群中允许弹出的主机比率,避免所有主机都弹出
enforcing_consecutive_5xx: int #连续5xx检测到主机异常时,主机被弹出的几率,可用于禁止弹出和缓慢弹出,默认100
enforcing_seccess_rate: int #成功率检测到主机异常时,主机被弹出几率,用于禁止弹出、缓慢弹出,默认100
success_rate_minimum_hosts: int #参与评估的最少主机数,如果集群的主机数少于此就不参加评估,默认5
success_rate_requests_volume: int #检测的1次间隔中,必须收集的总请求的最小值,默认100
success_rate_stdev_factor: int #用确定成功率异常值弹出的弹射阈值的因子,弹射阈值=均值-(因子*平均成功率标准差)。如需要1.3因子,则要设为1300。因子越大弹出概率越低
consecutive_gateway_failure: int #连续网关故障弹出主机的最少连续故障数,默认5
enforcing_consecutive_gateway_failure: int #连续网关故障检测到异常状态时,弹出主机的几率,默认0
split_external_local_origin_errors: 布尔值 #是否区分本地原因导致的故障和外部故障,默认为false,true时,下面3个配置才能生效
consecutive_local_origin_failure: #因本地原因的故障弹出主机的最少次数,默认5
enforcing_consecutive_local_origin_failure: #基于连续的本地故障检测异常状态而弹出主机的几率,默认100
enforcing_local_origin_success_rate: #基于连续本地故障检测的成功率统计检测到异常状态而弹出主机的几率,默认100
failure_percentage_threshold: {} #确定基于故障百分比的
enforcing_failure_percentage: {} #
enforcing_failure_percentage_local_origin: {}
faulure_percentage_minimum_hosts: {}
failure_percentage_request_volume: {}
max_ejection_time: #主机弹出的最长时间,未指定则用默认值,300s,或对比base_ejection_time的最大值
cleanup_interval: '{...}'
upstream_bind_config: '{...}'
lb_subset_config: '{...}'
maglev_lb_config: '{...}'
transport_socket: '{...}'
metadata: '{...}'
upstream_connection_options: '{...}'
close_connections_on_host_health_failure: ...
ignore_health_on_host_removal: ...
filters: []
track_timeout_budgets: ...
upstream_config:
healthy_panic_threshold: int #恐慌阈值,默认50%
use_http2:
use_http3:
zone_routing: #区域感知负载均衡
enabled: #将路由到同一上游区域的请求的百分比。默认为 100% 的请求
min_cluster_size:
track_cluster_stats: '{...}'
preconnect_policy: '{...}'
connection_pool_per_downstream_connection: ...
案例
例1: http+tcp主动健康检测

1)front-envoy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: web_cluster_01 }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: myservice, port_value: 80 }
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
http_health_check:
path: /livez
expected_statuses:
start: 200
end: 399
2)front-envoy-with-tcp-check.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: web_cluster_01 }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: myservice, port_value: 80 }
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
tcp_health_check: {}
3)envoy-sidecar-proxy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: local_cluster }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: local_cluster
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8080 }
4)docker-compose.yaml
version: '3.3'
services:
envoy:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./front-envoy.yaml:/etc/envoy/envoy.yaml
# - ./front-envoy-with-tcp-check.yaml:/etc/envoy/envoy.yaml
networks:
envoymesh:
ipv4_address: 172.31.18.2
aliases:
- front-proxy
depends_on:
- webserver01-sidecar
- webserver02-sidecar
webserver01-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: red
networks:
envoymesh:
ipv4_address: 172.31.18.11
aliases:
- myservice
webserver01:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver01-sidecar"
depends_on:
- webserver01-sidecar
webserver02-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: blue
networks:
envoymesh:
ipv4_address: 172.31.18.12
aliases:
- myservice
webserver02:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver02-sidecar"
depends_on:
- webserver02-sidecar
networks:
envoymesh:
driver: bridge
ipam:
config:
- subnet: 172.31.18.0/24
5)测试
#测试访问,2个后端正常
for i in 1 2;do curl 172.31.18.2 ;done
curl 172.31.18.2/livez ;echo
#模拟故障
curl -X POST -d 'livez=err' 172.31.18.12/livez
#再次测试访问
for i in 1 2;do curl 172.31.18.2 ;done


模拟故障后再访问,发现后端2已经被删除了

例2: 被动健康检测

1)front-envoy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: web_cluster_01 }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: myservice, port_value: 80 }
outlier_detection:
consecutive_5xx: 3
base_ejection_time: 10s
max_ejection_percent: 10
2)envoy-sidecar-proxy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: local_cluster }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: local_cluster
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8080 }
3)docker-compose.yaml
version: '3.3'
services:
envoy:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./front-envoy.yaml:/etc/envoy/envoy.yaml
networks:
envoymesh:
ipv4_address: 172.31.20.2
aliases:
- front-proxy
depends_on:
- webserver01-sidecar
- webserver02-sidecar
- webserver03-sidecar
webserver01-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: red
networks:
envoymesh:
ipv4_address: 172.31.20.11
aliases:
- myservice
webserver01:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver01-sidecar"
depends_on:
- webserver01-sidecar
webserver02-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: blue
networks:
envoymesh:
ipv4_address: 172.31.20.12
aliases:
- myservice
webserver02:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver02-sidecar"
depends_on:
- webserver02-sidecar
webserver03-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: green
networks:
envoymesh:
ipv4_address: 172.31.20.13
aliases:
- myservice
webserver03:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver03-sidecar"
depends_on:
- webserver03-sidecar
networks:
envoymesh:
driver: bridge
ipam:
config:
- subnet: 172.31.20.0/24
4)测试
#测试访问
while :;do curl 172.31.20.2/livez ; sleep 0.5;echo;done
#模拟故障
curl -X POST -d 'livez=err' 172.31.20.11/livez
错误3次后自动弹出了主机,10s后再次自动检测,再错误再弹出

例3:加权最少请求调度
轮询配置类似

1)front-envoy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: web_cluster_01 }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: LEAST_REQUEST
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: red
port_value: 80
load_balancing_weight: 1
- endpoint:
address:
socket_address:
address: blue
port_value: 80
load_balancing_weight: 3
- endpoint:
address:
socket_address:
address: green
port_value: 80
load_balancing_weight: 5
2)envoy-sidecar-proxy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: local_cluster }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: local_cluster
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8080 }
3)docker-compose.yaml
version: '3.3'
services:
envoy:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./front-envoy.yaml:/etc/envoy/envoy.yaml
networks:
envoymesh:
ipv4_address: 172.31.22.2
aliases:
- front-proxy
depends_on:
- webserver01-sidecar
- webserver02-sidecar
- webserver03-sidecar
webserver01-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: red
networks:
envoymesh:
ipv4_address: 172.31.22.11
aliases:
- myservice
- red
webserver01:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver01-sidecar"
depends_on:
- webserver01-sidecar
webserver02-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: blue
networks:
envoymesh:
ipv4_address: 172.31.22.12
aliases:
- myservice
- blue
webserver02:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver02-sidecar"
depends_on:
- webserver02-sidecar
webserver03-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: green
networks:
envoymesh:
ipv4_address: 172.31.22.13
aliases:
- myservice
- green
webserver03:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver03-sidecar"
depends_on:
- webserver03-sidecar
networks:
envoymesh:
driver: bridge
ipam:
config:
- subnet: 172.31.22.0/24
4)send-request.sh
用于发送测试请求,用法:
sh send-request.sh ip地址
#!/bin/bash
declare -i red=0
declare -i blue=0
declare -i green=0
#interval="0.1"
counts=300
echo "Send 300 requests, and print the result. This will take a while."
echo ""
echo "Weight of all endpoints:"
echo "Red:Blue:Green = 1:3:5"
for ((i=1; i<=${counts}; i++)); do
if curl -s http://$1/hostname | grep "red" &> /dev/null; then
# $1 is the host address of the front-envoy.
red=$[$red+1]
elif curl -s http://$1/hostname | grep "blue" &> /dev/null; then
blue=$[$blue+1]
else
green=$[$green+1]
fi
# sleep $interval
done
echo ""
echo "Response from:"
echo "Red:Blue:Green = $red:$blue:$green"
例4:环哈希+路由哈希
1)front-envoy.yaml
其余配置文件参考例3
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: web_cluster_01
hash_policy:
# - connection_properties:
# source_ip: true
- header:
header_name: User-Agent
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.5s
type: STRICT_DNS
lb_policy: RING_HASH
ring_hash_lb_config:
maximum_ring_size: 1048576
minimum_ring_size: 512
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: myservice
port_value: 80
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
http_health_check:
path: /livez
expected_statuses:
start: 200
end: 399
例5:位置权重调度

1)front-envoy.yaml
其余配置文件参考例3
admin:
access_log_path: "/dev/null"
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- address:
socket_address: { address: 0.0.0.0, port_value: 80 }
name: listener_http
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: webcluster1
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: webcluster1
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: webcluster1
policy:
overprovisioning_factor: 140
endpoints:
- locality:
region: cn-north-1
priority: 0
load_balancing_weight: 10
lb_endpoints:
- endpoint:
address:
socket_address: { address: webservice1, port_value: 80 }
- locality:
region: cn-north-2
priority: 0
load_balancing_weight: 20
lb_endpoints:
- endpoint:
address:
socket_address: { address: webservice2, port_value: 80 }
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 1
http_health_check:
path: /livez
expected_statuses:
start: 200
end: 399
例6:负载均衡子集

1)front-envoy.yaml
admin:
access_log_path: "/dev/null"
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- address:
socket_address: { address: 0.0.0.0, port_value: 80 }
name: listener_http
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
headers:
- name: x-custom-version
exact_match: pre-release
route:
cluster: webcluster1
metadata_match:
filter_metadata:
envoy.lb:
version: "1.2-pre"
stage: "dev"
- match:
prefix: "/"
headers:
- name: x-hardware-test
exact_match: memory
route:
cluster: webcluster1
metadata_match:
filter_metadata:
envoy.lb:
type: "bigmem"
stage: "prod"
- match:
prefix: "/"
route:
weighted_clusters:
clusters:
- name: webcluster1
weight: 90
metadata_match:
filter_metadata:
envoy.lb:
version: "1.0"
- name: webcluster1
weight: 10
metadata_match:
filter_metadata:
envoy.lb:
version: "1.1"
metadata_match:
filter_metadata:
envoy.lb:
stage: "prod"
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: webcluster1
connect_timeout: 0.5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: webcluster1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: e1
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "prod"
version: "1.0"
type: "std"
xlarge: true
- endpoint:
address:
socket_address:
address: e2
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "prod"
version: "1.0"
type: "std"
- endpoint:
address:
socket_address:
address: e3
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "prod"
version: "1.1"
type: "std"
- endpoint:
address:
socket_address:
address: e4
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "prod"
version: "1.1"
type: "std"
- endpoint:
address:
socket_address:
address: e5
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "prod"
version: "1.0"
type: "bigmem"
- endpoint:
address:
socket_address:
address: e6
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "prod"
version: "1.1"
type: "bigmem"
- endpoint:
address:
socket_address:
address: e7
port_value: 80
metadata:
filter_metadata:
envoy.lb:
stage: "dev"
version: "1.2-pre"
type: "std"
lb_subset_config:
fallback_policy: DEFAULT_SUBSET
default_subset:
stage: "prod"
version: "1.0"
type: "std"
subset_selectors:
- keys: ["stage", "type"]
- keys: ["stage", "version"]
- keys: ["version"]
- keys: ["xlarge", "version"]
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 1
http_health_check:
path: /livez
expected_statuses:
start: 200
end: 399
2)docker-compose.yaml
version: '3'
services:
front-envoy:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./front-envoy.yaml:/etc/envoy/envoy.yaml
networks:
envoymesh:
ipv4_address: 172.31.33.2
expose:
# Expose ports 80 (for general traffic) and 9901 (for the admin server)
- "80"
- "9901"
e1:
image: ikubernetes/demoapp:v1.0
hostname: e1
networks:
envoymesh:
ipv4_address: 172.31.33.11
aliases:
- e1
expose:
- "80"
e2:
image: ikubernetes/demoapp:v1.0
hostname: e2
networks:
envoymesh:
ipv4_address: 172.31.33.12
aliases:
- e2
expose:
- "80"
e3:
image: ikubernetes/demoapp:v1.0
hostname: e3
networks:
envoymesh:
ipv4_address: 172.31.33.13
aliases:
- e3
expose:
- "80"
e4:
image: ikubernetes/demoapp:v1.0
hostname: e4
networks:
envoymesh:
ipv4_address: 172.31.33.14
aliases:
- e4
expose:
- "80"
e5:
image: ikubernetes/demoapp:v1.0
hostname: e5
networks:
envoymesh:
ipv4_address: 172.31.33.15
aliases:
- e5
expose:
- "80"
e6:
image: ikubernetes/demoapp:v1.0
hostname: e6
networks:
envoymesh:
ipv4_address: 172.31.33.16
aliases:
- e6
expose:
- "80"
e7:
image: ikubernetes/demoapp:v1.0
hostname: e7
networks:
envoymesh:
ipv4_address: 172.31.33.17
aliases:
- e7
expose:
- "80"
networks:
envoymesh:
driver: bridge
ipam:
config:
- subnet: 172.31.33.0/24
3)test.sh
#!/bin/bash
declare -i v10=0
declare -i v11=0
for ((counts=0; counts<200; counts++)); do
if curl -s http://$1/hostname | grep -E "e[125]" &> /dev/null; then
# $1 is the host address of the front-envoy.
v10=$[$v10+1]
else
v11=$[$v11+1]
fi
done
echo "Requests: v1.0:v1.1 = $v10:$v11"
4)测试
sh test.sh 172.31.33.2
例7:熔断与被动异常检测

1)front-envoy.yaml
admin:
access_log_path: "/dev/null"
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- address:
socket_address: { address: 0.0.0.0, port_value: 80 }
name: listener_http
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/livez"
route:
cluster: webcluster2
- match:
prefix: "/"
route:
cluster: webcluster1
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: webcluster1
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: webcluster1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: webservice1
port_value: 80
circuit_breakers:
thresholds:
max_connections: 1
max_pending_requests: 1
max_retries: 3
- name: webcluster2
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: webcluster2
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: webservice2
port_value: 80
outlier_detection:
interval: "1s"
consecutive_5xx: "3"
consecutive_gateway_failure: "3"
base_ejection_time: "10s"
enforcing_consecutive_gateway_failure: "100"
max_ejection_percent: "30"
success_rate_minimum_hosts: "2"
2)envoy-sidecar-proxy.yaml
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: local_cluster }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: local_cluster
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8080 }
circuit_breakers:
thresholds:
max_connections: 1
max_pending_requests: 1
max_retries: 2
3)docker-compose.yaml
version: '3'
services:
front-envoy:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./front-envoy.yaml:/etc/envoy/envoy.yaml
networks:
- envoymesh
expose:
# Expose ports 80 (for general traffic) and 9901 (for the admin server)
- "80"
- "9901"
webserver01-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: red
networks:
envoymesh:
ipv4_address: 172.31.35.11
aliases:
- webservice1
- red
webserver01:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver01-sidecar"
depends_on:
- webserver01-sidecar
webserver02-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: blue
networks:
envoymesh:
ipv4_address: 172.31.35.12
aliases:
- webservice1
- blue
webserver02:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver02-sidecar"
depends_on:
- webserver02-sidecar
webserver03-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: green
networks:
envoymesh:
ipv4_address: 172.31.35.13
aliases:
- webservice1
- green
webserver03:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver03-sidecar"
depends_on:
- webserver03-sidecar
webserver04-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: gray
networks:
envoymesh:
ipv4_address: 172.31.35.14
aliases:
- webservice2
- gray
webserver04:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver04-sidecar"
depends_on:
- webserver04-sidecar
webserver05-sidecar:
image: envoyproxy/envoy-alpine:v1.18-latest
volumes:
- ./envoy-sidecar-proxy.yaml:/etc/envoy/envoy.yaml
hostname: black
networks:
envoymesh:
ipv4_address: 172.31.35.15
aliases:
- webservice2
- black
webserver05:
image: ikubernetes/demoapp:v1.0
environment:
- PORT=8080
- HOST=127.0.0.1
network_mode: "service:webserver05-sidecar"
depends_on:
- webserver05-sidecar
networks:
envoymesh:
driver: bridge
ipam:
config:
- subnet: 172.31.35.0/24
4)send-requests.sh
#!/bin/bash
#
if [ $# -ne 2 ]
then
echo "USAGE: $0 <URL> <COUNT>"
exit 1;
fi
URL=$1
COUNT=$2
c=1
#interval="0.2"
while [[ ${c} -le ${COUNT} ]];
do
#echo "Sending GET request: ${URL}"
curl -o /dev/null -w '%{http_code}\n' -s ${URL} &
(( c++ ))
# sleep $interval
done
wait
5)测试
#发300g
sh send-requests.sh http://172.31.35.2/ 300


浙公网安备 33010602011771号