FEATURED · 精选文章

Envoy 原始目的地址(Original Destination)负载均衡:透明代理下按需集群成员的选取、覆盖与清理机制

发布时间 / 2026/9/14 8:25:07
来源 / 创域科博编辑部
栏目 / 资讯中心
Envoy 原始目的地址(Original Destination)负载均衡:透明代理下按需集群成员的选取、覆盖与清理机制 Envoy 原始目的地址Original Destination负载均衡透明代理下按需集群成员的选取、覆盖与清理机制【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文围绕 Envoy 的 Original Destination 负载均衡器展开它是唯一可与ORIGINAL_DST集群类型搭配使用的专用负载均衡策略上游主机不再来自任何显式配置或发现机制而是依据下游连接的原始目的地址“按需”动态加入集群并由集群周期性清理长期无流量的主机。读完本文你将掌握 Original Destination 的典型部署场景iptables REDIRECT/TPROXY 透明代理、Proxy Protocol、完整可运行的代理配置、请求头与 Filter State 两种目的地址覆盖方式以及其底层“按需建主、周期清理”的线程安全实现原理。一、Original Destination 负载均衡器是什么Original destination 是一个专用负载均衡器只能与 original destination 集群配合使用。Envoy 根据下游连接的元数据选取上游主机即连接会发往该入站连接在被重定向到 Envoy 之前的那个目的地址。这一机制的核心特征是按需添加主机新的目的地址由负载均衡器在选取时动态创建并加入集群无需任何上游服务发现配置周期性清理集群通过cleanup_interval字段定期清退不再使用的主机cleanup_interval未配置时默认值为 5000ms策略独占ORIGINAL_DST集群不能使用任何其他负载均衡策略其他lb_policy一律非法详见 集群工厂校验逻辑。从 服务发现架构文档 可知该集群的典型使用前提是入站连接通过iptables 的 REDIRECT 或 TPROXY 目标、或Proxy Protocol被重定向到 Envoy。此时请求被路由到 original destination 集群后会直接按重定向上下文携带的地址信息转发整个过程中不需要显式主机配置或上游主机发现。若原始目的地址不可获取则不会打开任何上游连接。此外当上游为 HTTP 协议时建议将idle_timeout设置为 5 分钟以限制上游 HTTP 连接的存活时长。二、完整配置示例listener filter ORIGINAL_DST 集群仓库中 configs/original-dst-cluster/proxy_config.yaml 提供了一个可直接参考的最小配置核心结构如下static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 10000 traffic_direction: OUTBOUND 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 route_config: name: local_service virtual_hosts: - name: backend domains: [*] routes: - match: prefix: / route: cluster: cluster1 http_filters: - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.Router codec_type: AUTO listener_filters: - name: envoy.filters.listener.original_dst # 关键捕获原始目的地址的监听器过滤器 typed_config: type: type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst clusters: - name: cluster1 type: ORIGINAL_DST # 集群类型原始目的地址 connect_timeout: 6s lb_policy: CLUSTER_PROVIDED # 必须负载均衡器由集群自身提供 dns_lookup_family: V4_ONLY admin: address: socket_address: address: 127.0.0.1 port_value: 9901要点说明listener_filters中的envoy.filters.listener.original_dst在连接建立阶段从连接上下文中恢复原始目的地址其实现位于 source/extensions/filters/listener/original_dst/original_dst.cctype: ORIGINAL_DSTlb_policy: CLUSTER_PROVIDED这是强制组合。OriginalDstClusterFactory::createClusterImpl 会显式校验lb_policy不是CLUSTER_PROVIDED时直接返回InvalidArgument错误集群若配置了load_assignment即显式主机列表同样会报错——“ORIGINAL_DST clusters must have no load assignment configured”。三、负载均衡器如何选主机四种来源的优先级负载均衡逻辑全部实现在 OriginalDstCluster::LoadBalancer::chooseHost。从源码结构看目的地址的选取遵循严格的优先级链取到第一个非空来源即停止优先级来源提取函数说明1Filter State 覆盖filterStateOverrideHost读取 Filter State 对象请求级与连接级 StreamInfo 均会检查2动态元数据覆盖metadataOverrideHost按metadata_key从 dynamic metadata 中取字符串值3HTTP 请求头覆盖requestOverrideHost读取配置的请求头默认x-envoy-original-dst-host4下游连接本地地址chooseHost内联逻辑当localAddressRestored()为 true 时如 TPROXY 恢复场景使用下游连接的 local address确定目的地址后若配置了upstream_port_override会用 Network::Utility::getAddressWithPort 替换端口号。随后进入集群内部的地址→主机映射表host_map_若地址已存在对应主机直接复用并置位used_标记若不存在则当场创建一个 HostImpl 立即返回保证本次请求可路由同时通过dispatcher_.post把主机添加操作投递到主线程执行 addHost从而同步给所有工作线程若目的地址既不是 IP 又无从恢复负载均衡器打印original_dst_load_balancer: No downstream connection or no original_dst.警告并返回空主机——对应文档所述“若原始目的地址不可用则不打开上游连接”。多线程下的主机去重HostsForAddress由于多个工作线程可能对同一地址并发新建主机HostsForAddress 结构为此设计host_是第一个完成添加的主机primary host所有工作线程共享读取hosts_保存并发添加产生的重复主机同地址、不同HostSharedPtr仅主线程访问源码注释明确指出并发添加的多个主机“都会最终超时被清理”即它们会在后续清理轮次中作为一个整体一起移除。此外addHost 中受运行时开关envoy.reloadable_features.skip_partition_original_dst_hosts控制由于该负载均衡器始终从host_map_中按精确地址选主机、并不查询健康分区开启该特性后所有主机会被直接保留在healthy_hosts中避免分区逻辑造成不可路由的主机缺失。四、周期性清理cleanup_interval 与 used_ 标记集群构造时OriginalDstCluster 构造函数读取cleanup_interval默认 5000ms并启动cleanup_timer_。cleanup 每轮对host_map_中每个地址按“组”判定去留若该地址的本轮used_原子标记为 true本周期内被负载均衡器选中过保留该组主机并把used_复位为 false留待下一轮再判定否则检查该组内所有主机primary 及并发添加的hosts_列表是否仍被任一连接池持有host-used()只要有一个在用即保留两者都不满足的主机整体移出映射表并通过priority_set_.updateHosts从集群主机集合中删除最后重新武装定时器。源码注释解释了一个微妙的竞态防护保留used_位是为了在“负载均衡器选中主机”与“连接池真正取得该主机句柄”之间留出至少一个cleanup_interval的缓冲窗口避免主线程在此期间把主机误删。五、覆盖方式一x-envoy-original-dst-host 请求头Envoy 还可以从 HTTP 请求头x-envoy-original-dst-host中获取原始目的地址。注意该头必须携带完全解析后的 IP 地址例如请求要路由到 IP10.195.16.237的 8888 端口头值必须写为10.195.16.237:8888而不能是域名。结合源码与 original_dst.proto 的配置该能力有以下细节需显式开启use_http_header: truecreateClusterWithConfig 会校验设置了http_header_name但use_http_header为 false 的配置直接判为非法http_header_name留空时默认使用x-envoy-original-dst-host若配置了自定义头名构造函数 会以Http::LowerCaseString形式加载实现大小写不敏感匹配头值通过 Network::Utility::parseInternetAddressAndPortNoThrow 解析为 IP:port解析失败时不会抛出异常而是打 debug 日志并使流量统计项original_dst_host_invalid_自增见 requestOverrideHost随后继续回落到更低优先级的来源安全警告proto 注释原文强调该头默认不做清洗sanitization开启此特性意味着 HTTP 客户端可以把流量路由到任意主机和任意端口可能带来严重安全后果只应在可信网络边界内启用多头同名请求只取第一个值源码中override_header[0]。六、覆盖方式二动态元数据与 upstream_port_override除请求头外OriginalDstCluster 配置还提供更强的控制项metadata_key指定一个 dynamic metadata 键负载均衡器依次检查请求级、连接级元数据取字符串值作为覆盖地址若值路径指向列表取列表第一个元素。解析失败同样计入original_dst_host_invalid_统计upstream_port_overrideUInt32Value类型校验规则限制 65535。与元数据不同该端口覆盖优先级最高——在最终确定目的地址后统一应用会覆盖 Filter State 或请求头中携带的端口适合“地址跟随透明代理、端口统一收敛”的场景如将所有上游流量统一导向某个标准服务端口。七、覆盖方式三Filter State 对象隧道到中间代理文档指出的第三种机制是自定义扩展可以通过 Filter State 对象envoy.network.transport_socket.original_dst_address覆盖目的地址典型用途是把流量隧道到一个中间代理而不是直连原始目的地。从源码看该机制的实现闭环非常清晰Filter State 的工厂在 original_dst_cluster.cc 末尾注册OriginalDstClusterFilterStateFactory以 OriginalDstClusterFilterStateKey即字符串常量envoy.network.transport_socket.original_dst_address为名注册为AddressObject类型的 Filter State 工厂自定义网络过滤器或 transport socket 在请求/连接生命周期内向 StreamInfo 写入该地址对象负载均衡器在 filterStateOverrideHost 中以最高优先级读取它先查请求级 StreamInfo再查下游连接级存在则直接作为目的地址使用。由于 Filter State 由 Envoy 进程内部扩展写入、无法被外部客户端直接注入它比请求头覆盖更适合需要精确控制上游目标的隧道场景。八、配置约束与实现要点小结约束 / 行为依据lb_policy必须为CLUSTER_PROVIDED且不得配置load_assignmentcreateClusterImpl 校验cleanup_interval默认 5000ms构造函数默认值支持新的cluster_type路径与旧版original_dst_lb_config字段两种配置写法旧字段会在工厂内翻译为统一的OriginalDstClusterprotocreateClusterImpl 兼容分支集群销毁必须发生在主线程故引入OriginalDstClusterHandle包一层析构时通过 dispatcher post 保证线程正确性Handle 析构逻辑预连接preconnect、连接池复用选择不适用peekAnotherHost固定返回空LoadBalancer 接口声明HTTP 上游建议将idle_timeout设为 5 分钟服务发现文档建议综合来看Original Destination 负载均衡器把“服务发现”这一职责从控制面整体下放到数据面连接本身携带了目的地址Envoy 只负责把地址安全地转化为可路由的集群主机并通过映射表 周期清理控制内存增长。理解其“Filter State → 元数据 → 请求头 → 连接本地地址”的选取优先级、use_http_header的安全边界以及cleanup_interval的保留窗口设计是正确部署与排障例如观察original_dst_host_invalid_统计定位非法覆盖值的关键。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻