4. Envoy 通用过滤器扩展机制:Network Filter、Access Loggers、Stats 扩展点、扩展注册与配置加载

Envoy 的扩展性是其作为云原生代理核心竞争力的关键。本章深入剖析 Envoy 的通用过滤器扩展机制,涵盖 Network Filter、Access Loggers、Stats 扩展点 以及 扩展注册与配置加载 四大核心模块。理解这些机制是开发自定义扩展(如策略即代码资源配额过滤器)的基础。

4.1 扩展点架构总览

Envoy 的扩展体系采用分层设计,允许开发者在不修改核心代码的情况下,通过插件方式注入自定义逻辑。下图展示了本章涉及的四个主要扩展点及其在数据平面与控制平面中的位置关系。

Envoy 通用过滤器扩展点架构 Envoy 核心代理 (Main) Network Filter 链 Listener Filter / Network Filter L3/L4 层数据拦截与修改 (连接级 read/write 回调) Access Loggers 请求/响应日志记录 自定义日志格式与输出 (File / gRPC / Stdout) Stats 扩展点 自定义度量指标注册 Counter / Gauge / Histogram (StatsSink 扩展) 扩展注册与配置加载 Factory 注册机制 静态/动态配置解析 (xDS / Bootstrap) 说明:所有扩展点均通过统一的 Factory 注册机制集成到 Envoy 主循环中,支持热加载与动态更新。

4.2 Network Filter 扩展机制

Network Filter 是 Envoy 最核心的扩展点之一,工作在 L3/L4 层,直接处理原始 TCP 连接上的数据流。它分为两类:Listener Filter(在连接建立前执行)和 Network Filter(在连接建立后执行)。

4.2.1 核心接口与回调

实现一个自定义 Network Filter 需要实现以下关键接口:

接口/回调 触发时机 典型用途
onNewConnection() 新 TCP 连接建立时 初始化连接上下文、执行准入控制
onData() 接收到数据时 数据解析、修改、转发决策
onWrite() 数据即将发送时 响应数据修改、注入头部
onEvent() 连接事件(关闭/重置/超时) 清理资源、记录连接终止统计

关键设计原则:Network Filter 采用链式调用(Filter Chain),每个 Filter 可以决定是否将数据传递给下一个 Filter。通过 FilterStatus 枚举(Continue、StopIteration、ResumeIteration)控制数据流。

4.2.2 配置示例

以下是一个自定义 Network Filter 的静态配置片段,展示了如何将其插入到监听器的 Filter Chain 中:

static_resources:
  listeners:
  - name: my_listener
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.my_custom_filter
        typed_config:
          "@type": type.googleapis.com/myorg.filters.network.MyCustomFilterConfig
          max_connections: 100
          quota_check_enabled: true
      - name: envoy.filters.network.tcp_proxy
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
          stat_prefix: tcp
          cluster: my_cluster

4.3 Access Loggers 扩展机制

Access Loggers 负责记录经过 Envoy 的每个请求/响应的详细信息。Envoy 提供了多种内置 Logger(如 File、gRPC、Stdout),同时也支持通过扩展机制实现自定义 Logger。

4.3.1 自定义 Access Logger 接口

实现自定义 Access Logger 需要实现 AccessLog::Instance 接口,核心方法包括:

  • log():接收 RequestInfo 和 AccessLog::AccessLogData,执行日志记录逻辑。
  • logWithFilter():支持基于过滤条件的日志记录,避免全量日志带来的性能开销。

性能建议:在实现自定义 Logger 时,建议使用异步写入或批处理机制,避免在数据路径上阻塞。对于高吞吐场景,优先考虑 gRPC Access Log Service (ALS) 而非文件写入。

4.3.2 配置示例

以下配置展示了如何启用自定义 Access Logger 并指定日志格式:

static_resources:
  listeners:
  - name: my_listener
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    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: http
          access_log:
          - name: envoy.access_loggers.my_custom_logger
            typed_config:
              "@type": type.googleapis.com/myorg.accesslog.MyCustomLoggerConfig
              log_path: "/var/log/envoy/custom_access.log"
              log_format: "%START_TIME% %REQ(X-REQUEST-ID)% %RESPONSE_CODE% %DURATION%"

4.4 Stats 扩展点

Envoy 的统计系统(Stats)是其可观测性的基石。Stats 扩展点允许开发者注册自定义度量指标,包括 Counter(计数器)、Gauge(仪表盘)和 Histogram(直方图)。

4.4.1 自定义 Stats 注册流程

  1. 获取 Stats 作用域:通过 Stats::ScopeSharedPtr 获取当前 Filter 的统计作用域。
  2. 定义指标结构体:使用 DECLARE_COUNTER、DECLARE_GAUGE 等宏声明指标。
  3. 注册指标:在 Filter 初始化时调用 scope->counterFromString() 等方法创建实例。
  4. 更新指标:在 Filter 回调中调用 counter_.inc()、gauge_.set() 等方法。

4.4.2 典型指标设计

指标名称 类型 描述
custom_filter.requests_total Counter 经过自定义 Filter 的总请求数
custom_filter.quota_rejected Counter 因配额不足被拒绝的请求数
custom_filter.active_connections Gauge 当前活跃连接数
custom_filter.request_duration_ms Histogram 请求处理耗时分布

注意:自定义指标的名称应遵循 Envoy 的命名规范,使用点号分隔层级,避免与内置指标冲突。建议在指标名称前添加自定义前缀(如 custom_filter.)。

4.5 扩展注册与配置加载

Envoy 使用 Factory 注册模式 管理所有扩展。每个扩展类型(Filter、Logger、StatsSink 等)都有一个对应的 Factory 基类,开发者需要实现该基类并注册到全局注册表中。

4.5.1 注册流程

下图展示了自定义扩展从代码实现到配置加载的完整生命周期:

扩展注册与配置加载生命周期 1. 实现 Factory 继承基类 Factory 2. 注册到 Registry REGISTER_FACTORY 宏 3. 编译链接 静态/动态库 4. 配置加载 Bootstrap/xDS 配置加载内部流程 1. Envoy 启动时扫描所有已注册的 Factory 2. 根据配置中的 name 字段匹配对应的 Factory 3. Factory 解析 typed_config 并创建扩展实例 提示:Envoy 支持通过 Wasm 扩展实现运行时动态加载,无需重新编译核心二进制。

4.5.2 代码示例:自定义 Filter Factory

以下是一个简化的自定义 Network Filter Factory 实现,展示了注册和配置解析的核心逻辑:

#include "source/extensions/filters/network/common/factory_base.h"

namespace MyOrg {
namespace Filters {
namespace Network {

class MyCustomFilterFactory : public Envoy::Extensions::NetworkFilters::Common::FactoryBase<MyCustomFilterConfig> {
public:
  MyCustomFilterFactory() : FactoryBase("myorg.filters.network.my_custom_filter") {}

private:
  Envoy::Network::FilterFactoryCb
  createFilterFactoryFromProtoTyped(const MyCustomFilterConfig& proto_config,
                                    Envoy::Server::Configuration::FactoryContext& context) override {
    auto filter = std::make_shared<MyCustomFilter>(proto_config, context);
    return [filter](Envoy::Network::FilterManager& filter_manager) -> void {
      filter_manager.addReadFilter(filter);
    };
  }
};

// 注册到全局 Registry
REGISTER_FACTORY(MyCustomFilterFactory,
                 Envoy::Server::Configuration::NamedNetworkFilterConfigFactory);

} // namespace Network
} // namespace Filters
} // namespace MyOrg

4.6 扩展点对比与选型建议

下表总结了四个扩展点的核心差异,帮助开发者在实际项目中做出正确选择:

扩展点 工作层级 数据访问粒度 典型延迟影响 适用场景
Network Filter L3/L4 连接/数据包 低(微秒级) 协议解析、访问控制、配额检查
Access Logger L7 请求/响应 极低(异步) 审计日志、流量分析、合规记录
Stats 扩展点 跨层 指标聚合 极低(原子操作) 可观测性、监控告警、容量规划
扩展注册与配置 控制面 配置元数据 仅启动/热加载时 扩展生命周期管理、动态配置

实践建议:在开发策略即代码资源配额模型时,推荐组合使用 Network Filter(执行配额检查逻辑)和 Stats 扩展点(记录配额使用指标),并通过 Access Logger 记录被拒绝的请求详情,形成完整的可观测性闭环。