3. Envoy HTTP 过滤器扩展机制:生命周期、回调与工厂模式

Envoy 的 HTTP 过滤器扩展机制是构建可编程七层网关的核心。理解过滤器的生命周期、回调接口以及配置解析的工厂模式,是开发自定义扩展的前提。本章将深入剖析这些底层机制,为后续集成策略即代码(Policy as Code)资源配额模型奠定基础。

3.1 HTTP Filter 生命周期

每个 HTTP 过滤器实例都遵循一个严格的生命周期,从创建到销毁,确保资源被正确管理。生命周期由 Envoy 的 FilterChain 管理,并在 Worker 线程中执行。

核心阶段: 初始化 → 配置加载 → 回调注册 → 请求处理 → 销毁
阶段 触发时机 关键行为
1. 工厂创建 Listener 配置加载时 Envoy 根据配置中的 typed_config 或 config 字段,调用对应的 NamedHttpFilterConfigFactory 创建过滤器实例。
2. 配置解析 工厂创建后立即执行 工厂解析 Protobuf 配置消息,生成不可变的 FilterConfig 对象。
3. 实例化 每个新 HTTP 请求/流开始时 工厂为每个请求流创建一个新的 StreamFilter 实例,传入 FilterConfig 和 FilterCallbacks。
4. 请求处理 请求/响应生命周期内 过滤器通过 Decoder/Encoder 回调处理数据,并调用 FilterCallbacks 与下游/上游交互。
5. 销毁 请求/流结束后 Envoy 自动销毁 StreamFilter 实例,释放关联资源(如定时器、连接池引用)。
HTTP Filter 生命周期状态机 工厂创建 配置解析 实例化 请求处理 销毁 生命周期关键约束 • 工厂和配置是全局单例,线程安全。 • StreamFilter 实例是请求级别的,非线程安全,无需加锁。 • 销毁阶段必须同步清理所有异步操作,防止内存泄漏。

3.2 Stream / Decoder / Encoder 回调

Envoy 的 HTTP 过滤器基于 Stream 模型,将请求和响应处理拆分为 Decoder(解码器,处理入站数据)和 Encoder(编码器,处理出站数据)两个方向。过滤器通过实现特定的回调接口来介入数据处理。

3.2.1 核心回调接口

接口 方向 主要回调方法 用途
StreamDecoderFilter 请求(下游 → 上游) decodeHeaders(), decodeData(), decodeTrailers() 拦截、修改或终止请求头、体和尾部。
StreamEncoderFilter 响应(上游 → 下游) encodeHeaders(), encodeData(), encodeTrailers() 拦截、修改或终止响应头、体和尾部。
StreamFilterBase 双向 onDestroy() 流销毁时的清理回调。

3.2.2 回调执行顺序

在一个典型的请求-响应周期中,回调的执行顺序如下:

  1. 请求阶段(Decoder): decodeHeaders() → decodeData()(可能多次) → decodeTrailers()(可选)。
  2. 上游处理: Envoy 将请求转发给上游集群。
  3. 响应阶段(Encoder): encodeHeaders() → encodeData()(可能多次) → encodeTrailers()(可选)。
  4. 流结束: onDestroy() 被调用。
最佳实践: 在 decodeHeaders() 中执行策略决策(如配额检查),因为此时可以高效地拒绝请求,避免不必要的上游连接和数据传输。
Decoder / Encoder 回调执行流程 下游客户端 Decoder 过滤器 上游集群 Encoder 过滤器 响应 decodeHeaders() decodeData() decodeTrailers() encodeHeaders() encodeData() encodeTrailers() onDestroy()

3.3 配置解析与工厂模式

Envoy 使用 工厂模式 来解耦过滤器的配置定义与实例创建。每个过滤器扩展必须实现 NamedHttpFilterConfigFactory 接口,该接口负责解析 Protobuf 配置并生成过滤器实例。

3.3.1 工厂接口核心方法

方法 职责 返回值
createFilterFactoryFromProto() 解析 Protobuf 配置消息,返回一个工厂函数。 FilterFactoryCb(回调函数)
createFilterFactoryFromProtoTyped() 解析类型化的 Protobuf 配置(推荐方式)。 FilterFactoryCb
name() 返回过滤器的唯一名称(如 envoy.filters.http.my_filter)。 std::string
configType() 返回配置消息的 Protobuf 描述符。 ProtobufTypes::MessagePtr

3.3.2 配置解析流程

  1. 配置加载: Envoy 读取静态或动态 xDS 配置,找到 HTTP 过滤器列表。
  2. 工厂查找: 根据过滤器名称(如 envoy.filters.http.quota),在注册的工厂映射表中查找对应的 NamedHttpFilterConfigFactory。
  3. 配置反序列化: 调用 createFilterFactoryFromProtoTyped(),将 typed_config 中的 JSON/YAML 反序列化为具体的 Protobuf 配置对象。
  4. 配置验证: 工厂对配置进行语义验证(如检查必填字段、值范围)。
  5. 工厂函数生成: 返回一个 FilterFactoryCb,该回调在每次新请求到来时被调用,用于创建 StreamFilter 实例。
注意: 配置对象(FilterConfig)在工厂创建后即被共享,必须是不可变的(const)。任何可变状态都应放在请求级别的 StreamFilter 实例中。

3.3.3 代码示例:工厂模式骨架

// 1. 定义 Protobuf 配置(.proto 文件)
message MyFilterConfig {
  string policy_name = 1;
  uint32 max_quota = 2;
}

// 2. 实现工厂类
class MyFilterFactory : public Server::Configuration::NamedHttpFilterConfigFactory {
public:
  // 返回过滤器名称
  std::string name() const override {
    return "envoy.filters.http.my_filter";
  }

  // 返回配置类型
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
    return std::make_unique<MyFilterConfig>();
  }

  // 核心工厂方法
  Http::FilterFactoryCb createFilterFactoryFromProtoTyped(
      const MyFilterConfig& proto_config,
      const std::string& stats_prefix,
      Server::Configuration::FactoryContext& context) override {

    // 解析并验证配置
    auto shared_config = std::make_shared<MyFilterConfig>(proto_config);

    // 返回工厂回调
    return [shared_config](Http::FilterChainFactoryCallbacks& callbacks) {
      // 每次请求创建新的 StreamFilter
      auto filter = std::make_shared<MyStreamFilter>(shared_config);
      callbacks.addStreamDecoderFilter(filter);
    };
  }
};

3.4 本章小结

  • 生命周期: 过滤器遵循“工厂创建 → 配置解析 → 实例化 → 请求处理 → 销毁”的严格流程,确保线程安全与资源隔离。
  • 回调机制: StreamDecoderFilter 和 StreamEncoderFilter 分别处理请求和响应,onDestroy() 负责清理。
  • 工厂模式: 通过 NamedHttpFilterConfigFactory 解耦配置与实例化,配置不可变,实例按需创建。
  • 扩展点: 开发者只需实现回调接口和工厂类,即可将自定义逻辑无缝集成到 Envoy 的 HTTP 处理管道中。