Envoy 中 TCP 网络连接实现分析

Envoy 的 TCP 网络连接实现是一个高度优化的事件驱动架构,提供了高性能、可靠性和可扩展性。核心组件包括:

  1. TcpListenerImpl - 负责接受新连接

  2. ConnectionImpl - 负责处理单个连接的数据流

  3. ConnectionImplBase - 提供连接的通用功能

  4. BaseListenerImpl - 提供监听器的通用功能

这种架构设计使得 Envoy 能够在处理大量并发 TCP 连接时保持低延迟和高吞吐量,是其作为云原生代理的核心优势之一。

  1. 概述

Envoy 作为云原生代理,其核心功能之一就是处理大量的 TCP 连接。本文旨在深入分析 Envoy 中 TCP 网络连接的实现细节,基于最新的代码结构和设计理念,涵盖监听器、连接管理、数据流处理及流量控制等关键环节。

  1. 监听器实现 - ListenerImpl 与连接接收流程

Envoy 的监听器负责接收来自下游(Downstream)的新连接。在较新的版本中,TcpListenerImpl 的功能已被整合进 ListenerImpl 中,它通过事件驱动的方式高效地处理新连接。

2.1 核心功能:监听与接收

当 Envoy 启动时,会为每个配置的监听器创建 ListenerImpl 对象。它会绑定到指定的 IP 地址和端口,并注册一个回调函数到事件循环(Dispatcher)中。

当一个新的 TCP 连接到达时,内核(如果开启了 SO_REUSEPORT)会选择一个工作线程(Worker),然后触发该线程中的 libevent 回调。这个回调的核心逻辑在 ListenerImpl::onSocketEvent(或类似的 onAccept 方法)中。

简化的连接接受流程:

  1. 接受连接:调用 accept() 系统调用,从监听套接字中获取一个新的已连接套接字(fd)。

  2. 设置套接字选项:为新的套接字设置非阻塞、TCP_NODELAY 等选项。

  3. 获取原始目标地址:如果配置了 use_original_dst,Envoy 会通过 getsockopt 获取 SO_ORIGINAL_DST。这对于透明代理至关重要,因为它能获取到 iptables 重定向前数据包的真实目标地址。

  4. 应用监听器过滤器(Listener Filters):在创建完整的连接对象之前,Envoy 会先执行配置的监听器过滤器链。例如,OriginalDstFilter 会使用上一步获取的原始目标地址来查找或创建对应的监听器,实现连接的"重定向"。另一个常见的过滤器是 TlsInspector,它会尝试读取客户端的首个数据包以判断是否为 TLS 流量,并解析出 SNI (Server Name Indication) 信息。

  5. 创建连接对象:一旦通过了监听器过滤器,Envoy 就会为该新连接创建一个 ConnectionImpl 对象,并将其移交给 ConnectionHandler 进行管理。

  6. 连接实现 - ConnectionImpl

ConnectionImpl 是 Envoy 中所有网络连接(包括下游和上游)的核心抽象。它封装了一个非阻塞的套接字(fd)及其相关的事件、缓冲区和状态机。

3.1 核心功能

· 连接生命周期管理:管理连接的建立、读写使能、关闭等状态。

· 事件处理:通过 FileEvent 监听套接字的读写事件,并调用 onReadReady() 和 onWriteReady() 等回调函数。

· 数据缓冲:拥有读缓冲区(read_buffer_)和写缓冲区(write_buffer_),用于暂存从套接字读取或即将写入套接字的数据。

· 流量控制:实现高/低水位线(High/Low Watermark)机制,用于在连接层面实现背压(Backpressure),防止快速的数据发送方压垮慢速的接收方。

3.2 数据流处理细节

3.2.1 读操作处理 (onReadReady)

  1. 数据读取:

当套接字可读时,onReadReady 方法被触发。它会调用 transport_socket_->doRead(),从内核缓冲区读取数据到 read_buffer_ 中。为了避免阻塞事件循环,读取过程是循环进行的,直到内核缓冲区数据被读完(返回 EAGAIN 错误)或达到一次读取的硬性限制(如 1MB)为止。

  1. 数据分发:

数据成功读入 read_buffer_ 后,onReadReady 会调用 onRead()。onRead() 的核心职责是将 read_buffer_ 中的数据传递给连接的过滤器链(Filter Chain)进行处理。

  1. 流量控制:

如果处理过程中,read_buffer_ 的大小超过了配置的高水位线(read_buffer_high_watermark_),Envoy 会自动调用 readDisable(true),暂停从套接字读取数据,直到缓冲区大小因下游处理而回落到低水位线以下。

3.2.2 写操作处理 (onWriteReady)

  1. 数据发送:

当套接字可写,并且 write_buffer_ 中有待发送的数据时,onWriteReady 会被触发。它调用 transport_socket_->doWrite(),将 write_buffer_ 中的数据写入内核的发送缓冲区。

  1. 缓冲区管理:

写入成功后,已发送的数据会从 write_buffer_ 中移除(drain)。如果 write_buffer_ 变空,Envoy 可能会禁用写事件以节省 CPU 资源。

  1. 流量控制:

如果 write_buffer_ 的大小超过了其高水位线,表示 Envoy 发送数据的速度慢于上游或下游接收数据的速度。此时,Envoy 会通过回调通知上层应用(如过滤器),上层应用可以决定暂停生成更多数据。

  1. 过滤器链 (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 连接处理中的关键一环。它的核心是缓冲区的高/低水位线机制,确保系统的任何一环都不会因数据积压而耗尽内存,并将压力有效地反向传递给数据发送方。

  1. 总结

Envoy 的 TCP 网络连接实现是一个基于现代操作系统特性(如 SO_REUSEPORT)、事件驱动、非阻塞 I/O 的高性能典范。

· 高效的事件驱动模型:基于 libevent 的事件循环是高性能的基石。

· 精细的流量控制:通过水位线机制,在连接的每一层实现背压,保证了系统的稳定性和资源使用的可预测性。

· 模块化的过滤器架构:网络过滤器和监听器过滤器的设计,让 Envoy 具备了处理各种协议(如 HTTP、MySQL、Redis)和实现复杂功能(如认证、限流、协议转换)的能力。

正是这些精妙的设计,使得 Envoy 能够在处理海量并发 TCP 连接时,依然保持出色的稳定性和低延迟,成为云原生时代服务网格中不可或缺的数据平面组件。

6.ER图(实体关系图)

备注:实体之间的连线表示关系,例如 Listener ||--o{ ConnectionSocket 表示一个 Listener 可以接受零个或多个 ConnectionSocket。

  1. Listener:监听器,负责接受新的 TCP 连接

  2. ConnectionSocket:连接套接字,代表原始套接字信息

  3. ConnectionImpl:连接实现,管理实际的连接状态

  4. Socket:套接字,封装操作系统级别的网络操作

  5. ListenerCallbacks:监听器回调,处理连接建立事件

  6. Connection:连接接口,提供统一的连接操作方法

  7. FileEvent:文件事件,管理套接字的读/写事件

  8. EventLoop:事件循环,基于 libevent 的事件驱动机制

  9. ConnectionHandler:连接处理器,管理所有活动连接

  10. ActiveConnections:活动连接池,管理连接池和复用

7.协作图

  1. Client:客户端,发起 TCP 连接请求

  2. TcpListenerImpl:TCP 监听器,接受连接请求

  3. ConnectionSocketImpl:连接套接字,封装原始套接字信息

  4. DispatcherImpl:调度器,管理事件循环和连接创建

  5. ConnectionCallbacks:连接回调,处理连接建立事件

  6. 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 请求

· 建立隧道连接到上游服务器

相关推荐
IpdataCloud2 小时前
米哈游黑产案解析:游戏账号批量注册如何用IP查询识别外挂与多开用户?操作指南
网络协议·tcp/ip·游戏
Deitymoon2 小时前
linux——TCP编程
linux·服务器
walkerLing2 小时前
Docker_Day1
运维·docker·容器
不吃鱼的猫7482 小时前
【音视频流媒体进阶:从网络到 WebRTC】第04篇-流媒体场景下的网络优化
网络·音视频·webrtc
格林威2 小时前
Windows 实时性补丁(RTX / WSL2)
linux·运维·人工智能·windows·数码相机·计算机视觉·工业相机
xuxie992 小时前
N22 key驱动
linux·运维·服务器
大地的一角2 小时前
(计算机网络)网络层原理与网络大致结构
服务器·网络·tcp/ip
TK云大师-KK2 小时前
2026年4月TikTok矩阵运营系统横向评测TOP5
大数据·网络·人工智能·矩阵·自动化·新媒体运营
c++逐梦人2 小时前
Linux多线程
linux·服务器