Envoy 的 TCP 网络连接实现是一个高度优化的事件驱动架构,提供了高性能、可靠性和可扩展性。核心组件包括:
-
TcpListenerImpl - 负责接受新连接
-
ConnectionImpl - 负责处理单个连接的数据流
-
ConnectionImplBase - 提供连接的通用功能
-
BaseListenerImpl - 提供监听器的通用功能
这种架构设计使得 Envoy 能够在处理大量并发 TCP 连接时保持低延迟和高吞吐量,是其作为云原生代理的核心优势之一。
- 概述
Envoy 作为云原生代理,其核心功能之一就是处理大量的 TCP 连接。本文旨在深入分析 Envoy 中 TCP 网络连接的实现细节,基于最新的代码结构和设计理念,涵盖监听器、连接管理、数据流处理及流量控制等关键环节。
- 监听器实现 - ListenerImpl 与连接接收流程
Envoy 的监听器负责接收来自下游(Downstream)的新连接。在较新的版本中,TcpListenerImpl 的功能已被整合进 ListenerImpl 中,它通过事件驱动的方式高效地处理新连接。
2.1 核心功能:监听与接收
当 Envoy 启动时,会为每个配置的监听器创建 ListenerImpl 对象。它会绑定到指定的 IP 地址和端口,并注册一个回调函数到事件循环(Dispatcher)中。
当一个新的 TCP 连接到达时,内核(如果开启了 SO_REUSEPORT)会选择一个工作线程(Worker),然后触发该线程中的 libevent 回调。这个回调的核心逻辑在 ListenerImpl::onSocketEvent(或类似的 onAccept 方法)中。
简化的连接接受流程:
-
接受连接:调用 accept() 系统调用,从监听套接字中获取一个新的已连接套接字(fd)。
-
设置套接字选项:为新的套接字设置非阻塞、TCP_NODELAY 等选项。
-
获取原始目标地址:如果配置了 use_original_dst,Envoy 会通过 getsockopt 获取 SO_ORIGINAL_DST。这对于透明代理至关重要,因为它能获取到 iptables 重定向前数据包的真实目标地址。
-
应用监听器过滤器(Listener Filters):在创建完整的连接对象之前,Envoy 会先执行配置的监听器过滤器链。例如,OriginalDstFilter 会使用上一步获取的原始目标地址来查找或创建对应的监听器,实现连接的"重定向"。另一个常见的过滤器是 TlsInspector,它会尝试读取客户端的首个数据包以判断是否为 TLS 流量,并解析出 SNI (Server Name Indication) 信息。
-
创建连接对象:一旦通过了监听器过滤器,Envoy 就会为该新连接创建一个 ConnectionImpl 对象,并将其移交给 ConnectionHandler 进行管理。
-
连接实现 - ConnectionImpl
ConnectionImpl 是 Envoy 中所有网络连接(包括下游和上游)的核心抽象。它封装了一个非阻塞的套接字(fd)及其相关的事件、缓冲区和状态机。
3.1 核心功能
· 连接生命周期管理:管理连接的建立、读写使能、关闭等状态。
· 事件处理:通过 FileEvent 监听套接字的读写事件,并调用 onReadReady() 和 onWriteReady() 等回调函数。
· 数据缓冲:拥有读缓冲区(read_buffer_)和写缓冲区(write_buffer_),用于暂存从套接字读取或即将写入套接字的数据。
· 流量控制:实现高/低水位线(High/Low Watermark)机制,用于在连接层面实现背压(Backpressure),防止快速的数据发送方压垮慢速的接收方。
3.2 数据流处理细节
3.2.1 读操作处理 (onReadReady)
- 数据读取:
当套接字可读时,onReadReady 方法被触发。它会调用 transport_socket_->doRead(),从内核缓冲区读取数据到 read_buffer_ 中。为了避免阻塞事件循环,读取过程是循环进行的,直到内核缓冲区数据被读完(返回 EAGAIN 错误)或达到一次读取的硬性限制(如 1MB)为止。
- 数据分发:
数据成功读入 read_buffer_ 后,onReadReady 会调用 onRead()。onRead() 的核心职责是将 read_buffer_ 中的数据传递给连接的过滤器链(Filter Chain)进行处理。
- 流量控制:
如果处理过程中,read_buffer_ 的大小超过了配置的高水位线(read_buffer_high_watermark_),Envoy 会自动调用 readDisable(true),暂停从套接字读取数据,直到缓冲区大小因下游处理而回落到低水位线以下。
3.2.2 写操作处理 (onWriteReady)
- 数据发送:
当套接字可写,并且 write_buffer_ 中有待发送的数据时,onWriteReady 会被触发。它调用 transport_socket_->doWrite(),将 write_buffer_ 中的数据写入内核的发送缓冲区。
- 缓冲区管理:
写入成功后,已发送的数据会从 write_buffer_ 中移除(drain)。如果 write_buffer_ 变空,Envoy 可能会禁用写事件以节省 CPU 资源。
- 流量控制:
如果 write_buffer_ 的大小超过了其高水位线,表示 Envoy 发送数据的速度慢于上游或下游接收数据的速度。此时,Envoy 会通过回调通知上层应用(如过滤器),上层应用可以决定暂停生成更多数据。
- 过滤器链 (Filter Chain) 处理流程
Envoy 的强大之处在于其高度模块化的过滤器架构。对于新建立的连接,数据会依次通过其配置的过滤器链。
4.1 网络过滤器 (Network Filters)
网络过滤器在 ConnectionImpl 的上下文中处理原始数据。当 onRead() 被调用时,它会将 read_buffer_ 传递给过滤器链中的第一个网络过滤器。
一个典型的网络过滤器是 Envoy HTTP 连接管理器 (HCM, HTTP Connection Manager)。HCM 本身就是一个网络过滤器,它的职责是将原始的 TCP 数据流解析为 HTTP 协议(HTTP/1.1, HTTP/2 等)的请求和响应,并将这些应用层消息分发给后续的 HTTP 过滤器链。
4.2 流量控制 (Flow Control) 实现
如 3.2.1 和 3.2.2 所述,流量控制是 Envoy 连接处理中的关键一环。它的核心是缓冲区的高/低水位线机制,确保系统的任何一环都不会因数据积压而耗尽内存,并将压力有效地反向传递给数据发送方。
- 总结
Envoy 的 TCP 网络连接实现是一个基于现代操作系统特性(如 SO_REUSEPORT)、事件驱动、非阻塞 I/O 的高性能典范。
· 高效的事件驱动模型:基于 libevent 的事件循环是高性能的基石。
· 精细的流量控制:通过水位线机制,在连接的每一层实现背压,保证了系统的稳定性和资源使用的可预测性。
· 模块化的过滤器架构:网络过滤器和监听器过滤器的设计,让 Envoy 具备了处理各种协议(如 HTTP、MySQL、Redis)和实现复杂功能(如认证、限流、协议转换)的能力。
正是这些精妙的设计,使得 Envoy 能够在处理海量并发 TCP 连接时,依然保持出色的稳定性和低延迟,成为云原生时代服务网格中不可或缺的数据平面组件。
6.ER图(实体关系图)

备注:实体之间的连线表示关系,例如 Listener ||--o{ ConnectionSocket 表示一个 Listener 可以接受零个或多个 ConnectionSocket。
-
Listener:监听器,负责接受新的 TCP 连接
-
ConnectionSocket:连接套接字,代表原始套接字信息
-
ConnectionImpl:连接实现,管理实际的连接状态
-
Socket:套接字,封装操作系统级别的网络操作
-
ListenerCallbacks:监听器回调,处理连接建立事件
-
Connection:连接接口,提供统一的连接操作方法
-
FileEvent:文件事件,管理套接字的读/写事件
-
EventLoop:事件循环,基于 libevent 的事件驱动机制
-
ConnectionHandler:连接处理器,管理所有活动连接
-
ActiveConnections:活动连接池,管理连接池和复用
7.协作图

-
Client:客户端,发起 TCP 连接请求
-
TcpListenerImpl:TCP 监听器,接受连接请求
-
ConnectionSocketImpl:连接套接字,封装原始套接字信息
-
DispatcherImpl:调度器,管理事件循环和连接创建
-
ConnectionCallbacks:连接回调,处理连接建立事件
-
Envoy 官方网站配置与功能
8.1 TCP 代理过滤器配置
```yaml
envoy.yaml 配置示例
static_resources:
listeners:
- name: tcp_listener
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
filter_chains:
-
filters:
-
name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: tcp_stats
cluster: upstream_cluster
idle_timeout: 300s
max_connect_attempts: 3
```
核心配置
stat_prefix :字符串, 统计信息前缀
cluster :字符串 ,上游集群名称
weighted_clusters :对象, 权重集群配置(支持流量分配)
idle_timeout :时间, 连接空闲超时时间(默认 1 小时)
max_connect_attempts :整数, 最大连接尝试次数(默认 1)
高级配置
metadata_match 对象 端点元数据匹配
hash_policy 数组 哈希策略(用于负载均衡)
tunneling_config 对象 隧道配置(如 HTTP CONNECT 隧道)
max_downstream_connection_duration 时间 最大连接持续时间
on_demand 对象 按需集群发现配置
access_log 数组 访问日志配置
8.2 监听器配置
```yaml
监听器配置示例
static_resources:
listeners:
- name: tcp_listener
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
per_connection_buffer_limit_bytes: 1048576
tcp_fast_open_queue_length: 100
bind_to_port: true
use_original_dst: false
transparent: false
freebind: false
connection_balance_config:
exact_balance: {}
filter_chains:
-
filters:
-
name: envoy.filters.network.tcp_proxy
typed_config:
...
```
per_connection_buffer_limit_bytes: 整数, 每个连接的缓冲区限制(默认 1MiB)
tcp_fast_open_queue_length :整数, TCP 快速打开队列长度
bind_to_port: 布尔值, 是否绑定到特定端口
use_original_dst :布尔值, 是否使用原始目标地址
transparent: 布尔值, 是否启用透明代理
freebind :布尔值, 是否允许绑定到未配置的 IP 地址
connection_balance_config :对象 ,连接平衡配置(如精确平衡)
8.3 对应功能实现
8.3.1 连接超时管理
配置:
```yaml
idle_timeout: 300s
max_downstream_connection_duration: 3600s
```
实现位置:
· /envoy/source/common/network/connection_impl.cc
· 使用 TimerImpl 实现超时逻辑
· 定期检查连接状态并关闭超时连接
8.3.2 连接重试机制
配置:
```yaml
max_connect_attempts: 3
```
实现位置:
· /envoy/source/common/network/connection_impl.cc
· 在 connect() 方法中实现重试逻辑
· 处理连接失败和重试计数
8.3.3 流量分配(权重集群)
配置:
```yaml
weighted_clusters:
clusters:
- name: cluster1
weight: 75
- name: cluster2
weight: 25
```
实现位置:
· /envoy/source/common/upstream/load_balancer_impl.cc
· 使用加权随机或加权轮询算法
· 根据配置分配流量
8.3.4 TCP 隧道(HTTP CONNECT)
配置:
```yaml
tunneling_config:
hostname: "%REQUESTED_SERVER_NAME%:443"
use_post: false
headers_to_add:
- header: { key: "X-Proxy", value: "Envoy" }
```
实现位置:
· /envoy/source/common/network/tcp_proxy_filter.cc
· 处理 HTTP CONNECT 请求
· 建立隧道连接到上游服务器