envoy扩展技术Envoy External Processing

envoy是基于C++开发的,虽然提供了很完善的功能实现,但是还是会存在一些定制化的功能不支持的情况,而直接二次开发envoy 的门槛比较高,所以envoy提供了ext这种扩展技术。

1. ext_proc 是什么?

   External Processing (ext_proc) 是 Envoy 提供的一个 HTTP 过滤器,它允许将请求和响应的处理逻辑委托给一个外部 gRPC 服务。这个外部服务被称为“外部处理器”(External Processor),可以运行在独立的进程中,甚至可以是完全独立的容器或服务。

      与编写 C++ 原生扩展或 Wasm 插件不同,ext_proc 是一种进程外集成机制,旨在将复杂的业务逻辑从数据面解耦,实现灵活的流量处理。

2. 解决的核心问题

传统网关在应对复杂业务需求时面临三大困境:

1)功能耦合问题:

扩展逻辑需编译进网关二进制,迭代周期长

 ext方式优势:逻辑完全外置,可独立开发、部署和升级

2)资源隔离问题:

   自定义逻辑异常可能导致整个网关崩溃 ext方式优势:外部服务故障不影响 Envoy 主进程稳定性

3)语言限制问题:

多数网关仅支持特定语言(如 Lua)开发扩展 

ext方式优势:任何支持 gRPC 的语言(Go/Java/Python/Node.js 等)均可实现

典型适用场景:

· 复杂认证授权:

多因素认证、RBAC 等需与外部系统交互的场景

· 实时流量分析:

请求/响应数据的实时处理、用户行为追踪、异常检测

· 深度内容检查:

DLP(数据防泄漏)、病毒扫描、敏感信息过滤

· 动态路由调整:

根据请求内容或外部系统状态实现灰度发布、A/B 测试

· 协议转换与适配:

在 HTTP 与 gRPC 或 Legacy 系统协议间转换

3. 工作原理

3.1 架构与通信流程

ext_proc 过滤器与外部服务之间通过双向 gRPC 流(Bidirectional gRPC Stream) 进行通信。每个 HTTP 请求都会创建其专属的 gRPC 流,确保请求级隔离。

完整处理流程:

3.2 处理阶段与模式

ext_proc 支持最多六个独立处理阶段,每个阶段可通过 processing_mode 单独控制是否启用:

不同阶段介绍:

1)Request Headers 

方向: 入站 

描述: 在请求到达上游前检查或修改请求头

2)Request Body

方向: 入站 

描述:检查或修改请求体

3)Request Trailers 

方向:入站 

描述:检查或修改 HTTP/2 请求尾部

4)Response Headers 

方向:出站 

描述:在响应返回下游前检查或修改响应头

5)Response Body

方向: 出站

 描述:检查或修改响应体

6)Response Trailers 

方向:出站 

描述:检查或修改 HTTP/2 响应尾部

Body 处理模式:

模式 特点 适用场景 内存占用 延迟

1)STREAMED 

特点:流式传输 

适用场景:body 片段 大文件上传/下载 

内存占用:低 

延迟:低(首包)

2)BUFFERED 

特点:缓存完整 body 后处理 

适用场景:小请求体(如 JSON) 

内存占用:高 

延迟:高(等待完整 body)

3)BUFFERED_PARTIAL 

特点:缓存超限则截断 

适用场景:未知大小的中等请求 

内存占用:中 

延迟:中

4)NONE 

适用场景:不发送 body 仅需处理 headers 的场景

内存占用: 无

延迟: 无

4. 使用方式

4.1 开发外部处理服务

需要先实现一个 gRPC 服务,满足 Envoy 定义的 ExternalProcessor 接口。

以下是一个 Go 语言示例,在请求头和响应头中添加自定义字段:

```go

package main

import (

    "log"

    "net"

    "io"

    "google.golang.org/grpc"

    "google.golang.org/grpc/codes"

    "google.golang.org/grpc/status"

    corePb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"

    extProcPb "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3"

)

type extProcServer struct {

    extProcPb.UnimplementedExternalProcessorServer

}

func (s *extProcServer) Process(srv extProcPb.ExternalProcessor_ProcessServer) error {

    for {

        req, err := srv.Recv()

        if err == io.EOF {

            return nil

        }

        if err != nil {

            return status.Errorf(codes.Unknown, "recv error: %v", err)

        }

        resp := &extProcPb.ProcessingResponse{}

        switch v := req.Request.(type) {

   case *extProcPb.ProcessingRequest_RequestHeaders:

            // 处理请求头:添加自定义 header

            resp = &extProcPb.ProcessingResponse{

            Response: &extProcPb.ProcessingResponse_RequestHeaders{

                    RequestHeaders: &extProcPb.HeadersResponse{

                        Response: &extProcPb.CommonResponse{

                            HeaderMutation: &extProcPb.HeaderMutation{

                                SetHeaders: []*corePb.HeaderValueOption{

                                    {

                                        Header: &corePb.HeaderValue{

                                            Key:      "x-ext-proc-handled",

                                            RawValue: []byte("true"),

                                        },

                                    },

                                },

                            },

                            Status: extProcPb.CommonResponse_CONTINUE,

                        },

                    },

                },

            }

 case *extProcPb.ProcessingRequest_ResponseHeaders:

            // 处理响应头:添加自定义 header

            resp = &extProcPb.ProcessingResponse{

                Response: &extProcPb.ProcessingResponse_ResponseHeaders{

                    ResponseHeaders: &extProcPb.HeadersResponse{

                        Response: &extProcPb.CommonResponse{

                            HeaderMutation: &extProcPb.HeaderMutation{

                                SetHeaders: []*corePb.HeaderValueOption{

                                    {

                                        Header: &corePb.HeaderValue{

                                            Key:      "x-ext-proc-from",

                                            RawValue: []byte("ext-proc-service"),

                                        },

                                    },

                                },

                            },

                            Status: extProcPb.CommonResponse_CONTINUE,

                        },

                    },

                },

            }            

        default:

            // 其他阶段:不处理,直接继续

            continue

        }

        if err := srv.Send(resp); err != nil {

            return err

        }

    }

}

func main() {

    lis, err := net.Listen("tcp", ":9002")

    if err != nil {

        log.Fatalf("failed to listen: %v", err)

    }

    s := grpc.NewServer()

extProcPb.RegisterExternalProcessorServer(s, &extProcServer{})

    log.Println("ext_proc server listening on :9002")

    if err := s.Serve(lis); err != nil {

        log.Fatalf("failed to serve: %v", err)

    }

}

```

4.2 配置 Envoy Filter(以 Istio 为例)

在 Istio 服务网格中,通过 EnvoyFilter 资源将 ext_proc 过滤器插入 Sidecar 的 HTTP 过滤链:

```yaml

apiVersion: networking.istio.io/v1alpha3

kind: EnvoyFilter

metadata:

  name: httpbin-ext-proc

  namespace: your-namespace

spec:

  workloadSelector:

    labels:

      app: httpbin

  configPatches:

  - applyTo: HTTP_FILTER

    match:

      context: SIDECAR_INBOUND

      listener:

        portNumber: 80

        filterChain:

          filter:

            name: envoy.filters.network.http_connection_manager

    patch:

      operation: INSERT_BEFORE

      value:

        name: envoy.filters.http.ext_proc

        typed_config:

          "@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor

          grpc_service:

            envoy_grpc:

              cluster_name: outbound|9002||ext-proc.default.svc.cluster.local

          failure_mode_allow: true # 外部服务故障时是否允许请求继续

          processing_mode:

            request_header_mode: SEND      # 发送请求头

            response_header_mode: SEND      # 发送响应头

            request_body_mode: NONE         # 不发送请求体

            response_body_mode: NONE      # 不发送响应体

          message_timeout: 200ms       # 单条消息超时时间

```

4.3 部署外部处理服务

将 gRPC 服务打包为容器镜像,部署到 Kubernetes 集群中:

```yaml

apiVersion: v1

kind: Service

metadata:

  name: ext-proc

spec:

  ports:

  - name: grpc

    port: 9002

    targetPort: 9002

  selector:

    app: ext-proc

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: ext-proc

spec:

  replicas: 2

  selector:

    matchLabels:

      app: ext-proc

  template:

    metadata:

      labels:

        app: ext-proc

    spec:

      containers:

      - name: ext-proc

        image: your-registry/ext-proc:latest

        ports:

        - containerPort: 9002

        resources:

          requests:

            cpu: 100m

            memory: 128Mi

          limits:

            cpu: 500m

            memory: 512Mi

```

5. 优缺点分析

5.1 优点

1)语言无关:

任何支持 gRPC 的语言均可开发,技术选型灵活

2)强隔离性 

外部服务故障不影响 Envoy 主进程稳定性

3)功能全面 

可读写 Headers、Bodies、Trailers,甚至直接返回响应终止请求

4)独立部署升级

 逻辑更新无需重启或重建 Envoy,支持独立扩缩容

5)API 稳定 

gRPC 接口跨 Envoy 版本兼容性好,升级风险低

6)动态控制 

支持在处理过程中动态修改后续阶段的 processing_mode

5.2 缺点

1)额外网络延迟 

跨进程/跨网络调用引入延迟,长尾延迟增加 部署为 Sidecar 模式,使用本地通信;推荐策论:关键路径避免启用 Body 处理

2)资源开销 

外部服务消耗额外 CPU 和内存 合理设置副本数和资源配额;

推荐策略:按需启用处理阶段

3)序列化开销 

Protobuf 序列化/反序列化成本 使用流式模式(STREAMED)

推荐策略:避免大块数据缓存

4)运维复杂度 

需额外管理一个服务的生命周期 使用 Kubernetes 标准运维实践;

推荐策略:完善监控告警

5)故障处理复杂性 

需设计优雅降级和超时策略 

推荐策略:配置 failure_mode_allow: true,设置合理超时

6)不适合超低延迟场景 

相比进程内扩展延迟明显更高 

推荐策略:对延迟敏感的核心路径建议使用 C++ 扩展或 Dynamic Module

6. 最佳实践

6.1 架构设计

1. Sidecar 部署模式

   · 将外部处理服务作为 Sidecar 与 Envoy 同 Pod 部署,使用 localhost 通信,大幅降低网络延迟

   · 示例配置:grpc_service 地址设为 127.0.0.1:9002

2. 按需启用处理阶段

   · 默认情况下不发送任何数据,只显式启用需要的阶段

   · 若仅需修改 Headers,设置 request_body_mode: NONE 和 response_body_mode: NONE

3. 合理选择 Body 处理模式

   · 小 JSON/Protobuf 请求:使用 BUFFERED 模式,便于完整解析

 · 大文件上传/下载:使用 STREAMED 模式,避免内存溢出

 · 不确定大小:使用 BUFFERED_PARTIAL 并设置缓冲区上限

6.2 可靠性配置

1. 启用故障恢复

   ```

   failure_mode_allow: true   # 外部服务故障时继续转发请求,避免整体中断

   ```

2. 设置合理超时

   ```

   message_timeout: 200ms     # 根据服务响应时间调整,避免请求堆积

   ```

3. 实现优雅降级

   · 外部服务内部设置超时和熔断

   · 关键逻辑失败时返回 CommonResponse_CONTINUE 而非报错

6.3 性能优化

1. 连接复用
   · 确保 gRPC 客户端配置了连接池和 keepalive
   · Envoy 端使用 envoy_grpc 客户端类型,支持连接复用

2. 避免阻塞操作
   · 外部服务中避免同步调用慢速外部依赖
   · 使用异步非阻塞 I/O(如 Go goroutine、Java Netty)

3. 监控关键指标
   · 利用 Envoy 暴露的 ext_proc 统计信息:
     · streams_started:创建的 gRPC 流数量
     · message_timeouts:超时次数
     · streams_failed:流失败次数
   · 在 Access Log 中记录各阶段延迟:
     ```yaml
     log_format:
       json_format:
         ext_proc_header_latency: "%FILTER_STATE(envoy.filters.http.ext_proc:FIELD:request_header_latency_us)%"
         ext_proc_body_calls: "%FILTER_STATE(envoy.filters.http.ext_proc:FIELD:request_body_call_count)%"
     ```

参考资料:

https://www.envoyproxy.io/docs/envoy/v1.17.4/_sources/api-v3/extensions/filters/http/ext_proc/v3alpha/ext_proc.proto.rst.txt

https://envoy.k8s.ac.cn/docs/envoy/latest/api-v3/extensions/filters/http/ext_proc/v3/ext_proc.proto#envoy-v3-api-field-extensions-filters-http-ext-proc-v3-externalprocessor-allow-mode-override

https://tetrate.io/blog/envoy-extension-vs-integration

https://jimmysong.io/zh/book/envoy-handbook/extensibility/overview/

https://www.alibabacloud.com/help/en/asm/sidecar/use-envoy-external-processing-for-custom-processing-of-requests

内容概要:本文围绕含氢气氨气的综合能源系统优化调度展开研究,提出了一种基于Matlab的仿真建模与优化方法,旨在实现多能互补、高效利用与低碳运行。研究构建了包含风能、太阳能、电解水制氢、氢气储存、氢合成氨、氨储存及能源转换设备在内的综合能源系统架构,重点考虑了氢、氨作为二次能源载体在能量存储与转化中的关键作用。通过建立系统各组件的数学模型,如电解槽效率模型、合成氨反应动力学模型、储氢储氨容量模型等,并结合可再生能源出力不确定性、负荷需求波动等因素,构建了以系统运行成本最小化、碳排放最小化或多目标综合最优为目标的优化调度模型。采用智能优化算法(如改进粒子群算法、多目标优化算法等)对模型进行求解,实现了对系统中各类设备出力、储能充放电状态、能量交互功率等变量的精细化调度,有效提升了能源利用效率与系统经济性。; 适合人群:具备一定电力系统、能源工程或自动化专业背景,熟悉Matlab/Simulink仿真工具,从事新能源、综合能源系统、氢能等领域研究的研发人员、研究生及高年级本科生。; 使用场景及目标:① 为含氢、氨等新型能源载体的综合能源系统规划设计提供理论依据和技术支撑;② 实现对风光等波动性可再生能源的高效消纳,提高系统灵活性与可靠性;③ 通过优化调度降低系统运行成本与碳排放强度,服务于“双碳”战略目标。; 阅读建议:此资源以Matlab代码实现为核心,提供了完整的仿真模型与优化算法代码,学习者应结合相关专业知识,深入理解模型构建的物理意义与数学表达,调试并运行代码以掌握其工作流程,进而可根据实际需求对模型进行扩展与改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值