上一篇说明连接钉在 Worker、配置以 TLS 快照可读。连接一旦被 accept,下一问是:哪一条 filter chain 来伺候这条连接? 选错的表现往往不是「upstream 挂了」,而是 TLS 握手失败、明文撞上只收 TLS 的链、或 HTTP 编解码从第一字节就崩。
本文沿官方 Listeners / Listener
filters(v1.39.0)与 API v3
FilterChainMatch,钉住 accept → listener
filters → match → 实例化 network filters 的路径,以及
wrong-chain 的归因方法。
本文是「Envoy / 数据面代理内核」系列第 3 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 2 篇 · Main / Worker 连接绑定与配置快照 第 3 篇 · Listener Match listener filters 与 FilterChainMatch 第 4 篇 · Network Filter 字节流与 TCP Proxy / HCM 分叉 第 5 篇 · HCM Codec 选对链之后的 HTTP 入口
版本锚定:Envoy v1.39.0 Listeners、Listener filters、API v3
config.listener.v3.FilterChainMatch/TlsInspector;tag v1.39.0 源码在source/server/listener_manager*、source/extensions/filters/listener/。
一、Listener:命名接入点与多链
官方术语:Listener 是下游可连接的命名网络位置(端口、UDS 等)。单进程可挂任意多个 listener;文档建议「每机一个 Envoy 进程、多 listener」,便于运维与统计聚合。
TCP listener 上配置若干
filter_chains;每条
filter_chain 含有序的
network(L3/L4)filters。新连接到达后,按 match
选出一条链,再实例化该链的连接局部 filter
栈。UDP listener 另有 listener filters /
SO_REUSEPORT 会话语义,本篇以 TCP
接入为主。
可选
default_filter_chain:无匹配时走默认;未配置默认则关闭连接——这是黑洞的第一嫌疑点。
二、Accept 路径:先 enrich,再选链
flowchart TD
Accept["Worker accept"] --> LF["Listener filters"]
LF -->|"metadata: SNI ALPN dest"| Match["FilterChainMatch / matcher"]
Match -->|"most specific / named chain"| Inst["Instantiate network filters"]
Match -->|"no match"| Def["default_filter_chain or close"]
Inst --> Net["TCP Proxy or HCM ..."]
Listener filters 在 network filters 之前运行,操作刚 accept 的 socket,目的是操纵连接元数据,影响后续选链或处理。过滤器可停止再继续迭代,以便插入限流等旁路。官方动机:把「系统集成」从核心拆出,并让多特性交互更显式。
与 network filter 的分工:listener filter 改的是选哪条链的输入;network filter 处理的是已选定链上的字节与连接事件。
三、常见 listener filters
| Filter | 作用 | 典型下游字段 |
|---|---|---|
| TLS Inspector | 判断是否像 TLS;若是则窥探 ClientHello 中的 SNI / ALPN | transport_protocol=tls、server_names、application_protocols |
| Proxy Protocol | 解析 HAProxy PROXY 头,恢复真实客户端地址 | 下游地址 / 元数据(供日志与 match) |
| original_dst | 取原始目的地址(透明代理 / TPROXY 场景) | 目的 IP/端口,供 match 或上游 |
TLS
Inspector(envoy.filters.listener.tls_inspector)是选链的枢纽:无它,依赖
SNI / ALPN / transport_protocol: tls 的 match
往往得不到检测值。文档给出的 stats 包括
tls_found /
tls_not_found、sni_found、alpn_found、client_hello_too_large
等——归因「是否 TLS / 是否带
SNI」时应先看这些计数语义,而不是先怀疑 Router。
注意边界:ClientHello
过大或解析失败时,默认可能被当成明文路径;close_connection_on_client_hello_parse_error
等开关会改变失败语义(以 v1.39.0 proto
文档为准)。不要把「探测失败」静默当成「明文业务」。
Proxy Protocol 与 original_dst 常一起出现在「前面还有 LB / TPROXY」的拓扑:前者恢复真实客户端,后者恢复被 DNAT 改写前的目的地址。缺一则 FilterChainMatch 或访问日志里的地址语义会与运维假设错位——表现为「策略按错 IP 生效」,而不是 codec 报错。
四、FilterChainMatch:规则与特异性
API v3 FilterChainMatch
要求:一条链被选中当且仅当其全部条件被满足。条件可包括(节选):
server_names(SNI)transport_protocol(如 TLS Inspector 设置的tls)application_protocols(ALPN,如h2、http/1.1)- 目的 / 源地址与端口范围、直接源类型等
对范围与通配,选用最具体的匹配(例如
SNI:www.example.com 优于
*.example.com 优于无 server_names
的链)。官方警告:互联网上 ALPN 以外的值易假阴性;匹配非
h2 时须确认客户端都会发 ALPN。
较新的 Filter chain matcher
API(Matching Filter Chains in
Listeners)用命名链 + matcher tree 替代/补充传统
filter_chain_match:action 指向链名;无匹配可
on_no_match 到默认名,或拒绝。Matcher
更新与「仅 filter chain 内容更新」的 drain
语义不同——配置热更新细节见第 11
篇;本篇只记住:匹配失败会关连接或掉进错误的默认链。
示意配置(结构示意,非完整可运行文件):
listener_filters:
- name: envoy.filters.listener.tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
- filter_chain_match:
transport_protocol: tls
server_names: ["api.example.com"]
application_protocols: ["h2"]
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
# ...
- filter_chain_match:
transport_protocol: raw_buffer
filters:
- name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
# ...五、Wrong-chain 失败模式
| 现象 | 常见根因 | 核对方向 |
|---|---|---|
| 连接立刻断开,无上游日志 | 无匹配且无 default_filter_chain |
listener 匹配条件 vs Inspector 是否装上 |
| TLS 握手失败 / 证书名不对 | SNI 落到另一条链的证书 | server_names 特异性;多证书链顺序 |
| 明文 HTTP 被当 TLS(或相反) | transport_protocol 与 Inspector
结果不一致 |
tls_found / tls_not_found |
| h2 客户端异常、h1 正常 | ALPN match 过严或过松 | application_protocols;客户端是否发
ALPN |
| 透明代理打到错误上游 | 未装 original_dst 或 match 未用原目的 |
iptables / TPROXY 与 listener 地址 |
谱系与争论:早期「单 listener 单栈」足够简单;多租户网关把 SNI / ALPN 多链 变成一等公民后,失败从「端口错了」变成「同端口语义分叉」。社区同时推进 matcher API,争论点是:声明式 match 字段是否仍够用,还是应全面迁到通用 matching API——工程上两者可并存,排障时先确认用的是哪套配置表面。
开放问题:大规模 listener + 大量 SNI 链时,匹配成本与配置推送粒度如何平衡(链到 LDS warming,第 11 篇);HTTP/3 / QUIC 监听与 TCP 路径的 filter 组合分叉(第 5、16 篇边界)。
实操检查顺序(无实测输出,只给归因顺序):
- 连接是否被 accept(listener 级连接计数语义)。
- Inspector 是否看到预期的 tls / SNI / ALPN。
- 是否命中预期 chain 名(或是否掉进 default / 被关)。
- 此后才进入 network filter / HCM 日志。
跳过前三步直接查 upstream,是本层最常见的排障浪费。
六、与下一篇的衔接
选中 chain 之后,真正读写字节的是 network filters。链尾常见分叉:
tcp_proxy:L4 1:1 转发;http_connection_manager:进入编解码与 HTTP filter。
listener filter 阶段的错误不会变成漂亮的 HTTP 503——往往连 HCM 都到不了。
热更新时,官方区分「仅 filter chain 变更」与「整 listener 变更」:前者可按链排水;若 listener 元数据等字段变了,可能整 listener 排水。匹配规则改了但链名未变时,在途连接是否仍走旧语义,要以当版 Filter chain only update 叙述为准——排障「改完 SNI 规则旧连接还在」时,先问排水范围,再问 RDS。
七、参考资料
规范 / 官方文档(A)
- Envoy Proxy, Listeners / Listener filters,docs v1.39.0。
- Envoy Proxy, API v3
config.listener.v3.FilterChainMatch;extensions.filters.listener.tls_inspector.v3.TlsInspector。 - Envoy Proxy, Matching Filter Chains in Listeners(matcher API 与默认链行为)。
源码(A)
envoyproxy/envoytag v1.39.0:source/extensions/filters/listener/、source/server/(listener 管理与选链)。
站内对照
实验台账
- 本篇无伪造
config_dump/ stats 输出;仅描述官方计数语义。
八、小结
- Listener filters 先 enrich,FilterChainMatch 再选链;顺序反了就会配出「永远匹配不到」的链。
- TLS Inspector 是
SNI/ALPN/
tls匹配的常见前提;探测失败有独立语义,不可默认当明文成功。 - 无匹配且无默认链 → 关连接;选错链 → 协议层失败,不是典型 upstream 503。
- 下一篇进入 network filter:字节、水印、以及 TCP Proxy 与 HCM 的分叉。
→ 上一篇:Main / Worker · 系列目录 · 下一篇:Network filter 与 Connection
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Envoy 数据面】数据面全景:从 Listener 到 xDS 的可编程代理内核
定位 Envoy 相对 Nginx/HAProxy 静态配置代理与 Mesh 选型叙事的生态位;钉住请求路径、配置快照、FilterChainMatch、xDS warming、上游资源五条坐标系,并给出与 network/57 的分工及 16 篇阅读路线。
【Envoy 数据面】Main / Worker 与配置快照:事件循环、TLS 与几乎无锁热路径
钉住 Envoy 单进程多线程模型:Main 管 xDS/Admin,Worker 绑连接终生;Event::Dispatcher 与 Thread Local Storage 如何把配置变成每线程可读快照,以及快照解决什么、解决不了什么。
【Envoy 数据面】Network filter 与 Connection:字节流、水印与 TCP Proxy / HCM 分叉
在 FilterChain 已选定之后,说明 network filter 如何在连接字节流上工作、读写水印如何反压、连接生命周期事件,以及 TCP Proxy 相对 HTTP Connection Manager 的路径分叉。
【Envoy 数据面】HCM 与 Codec:HTTP/1·2·3、流生命周期与编解码错误
说明 HttpConnectionManager 如何把字节变成协议无关的 stream 事件;HTTP/1/2/3 codec 的职责边界;流与连接生命周期差异;以及 codec 错误与半关闭语义的失败模式。