Envoy Mobile Python 库实战:用 asyncio 与 httpx 集成 Envoy 高性能网络引擎
2026/9/15 14:33:14 网站建设 项目流程

Envoy Mobile Python 库实战:用 asyncio 与 httpx 集成 Envoy 高性能网络引擎

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

导读

Envoy Mobile Python 库 为 Python 应用提供了 Envoy 的原生绑定(bindings),让你不必亲自启动一个独立的 Envoy 进程,就能在进程内复用 Envoy 的高性能网络能力——包括 HTTP/2、HTTP/3(QUIC)、连接池、DNS 缓存与丰富的指标。本文围绕该库的官方 README 展开,完整讲解AsyncClient高层异步 API 与直接操作Engine/Stream的底层用法,并深入其源码(mobile/library/python/envoy_mobile)与集成测试(mobile/test/python),说明请求头规范化、显式流控、httpx transport 适配等实现细节,帮助你快速在自己的 Python 项目中落地 Envoy Mobile。

功能特性总览

按照 README 的描述,该库提供四大核心能力:

  • 高层异步 API(High-level Async API):基于 Python 标准库asyncio实现,AsyncClient提供熟悉的非阻塞 HTTP 请求接口,与httpx的调用风格接近;
  • Envoy 引擎集成(Envoy Engine Integration):可直接访问 Envoy 引擎进行高级配置与性能调优(连接超时、DNS 刷新、QUIC 提示、gzip/brotli 解压、socket tagging 等);
  • 现代协议支持(Modern Protocols):原生支持 HTTP/2 与 HTTP/3(QUIC);
  • 可观测性(Observable):集成 Envoy 丰富的指标(stats)与日志(logging)。

从包结构上看,envoy_mobile/init.py 对外导出AsyncClientEngineEngineBuilderLogLevelStreamStreamPrototypeEnvoyErrorErrorCodeStreamIntelFinalStreamIntel以及三组 httpx transport(AsyncEnvoyClientTransportEnvoyClientTransportEnvoyTransportFactory),分层清晰:

  • envoy_engine:pybind11 生成的 C++ 绑定模块(.so);
  • async_client/:纯 Python 的高层AsyncClient及其ResponseExecutor、请求规范化工具;
  • *_client_transport.pytransport_factory.py:面向 httpx 生态的 transport 适配层。

使用 AsyncClient 发起异步请求

AsyncClient是官方推荐的入口。它“每个客户端实例独占一个 Envoy 引擎和 executor”,request()在流完成后返回Response对象,整个操作借助底层asyncio事件循环与AsyncioExecutor完全非阻塞(见 client.py 的类文档)。

最小可用示例

README 中的示例完整可运行,其核心流程是:构造EngineBuilder→ 配置日志级别 → 将 builder 交给AsyncClient作为上下文管理器 → 发起请求 → 读取响应:

import asyncio from envoy_mobile import AsyncClient, EngineBuilder, LogLevel async def main(): # Configure the engine builder = EngineBuilder().set_log_level(LogLevel.info) # Use AsyncClient as a context manager async with AsyncClient(builder) as client: # Make a request response = await client.request( method="GET", url="https://api.github.com/repos/envoyproxy/envoy-mobile" ) print(f"Status: {response.status_code}") body = await response.body() print(f"Body length: {len(body)}") if __name__ == "__main__": asyncio.run(main())

生命周期与引擎就绪等待

AsyncClient作为异步上下文管理器使用时,__aenter__内部做了三件事(见 client.py):

  1. 创建一个asyncio.Event作为引擎就绪信号,并用AsyncioExecutor(loop=asyncio.get_running_loop())绑定当前事件循环;
  2. 调用builder.set_on_engine_running(...)注册回调后build()引擎——这是为了让回调能安全地跨线程调度回 asyncio 循环(AsyncioExecutor.wrap内部使用loop.call_soon_threadsafe,见 executor.py);
  3. await self._engine_running.wait()阻塞直到引擎真正跑起来(DNS 等子系统就绪)。

退出时__aexit__调用engine.terminate()释放资源,__del__也做了兜底清理,避免引擎泄漏。

请求参数与响应读取

request(method, url, **kwargs)是全部 HTTP 动词方法(get/post/put/delete/head/options/patch/trace)的统一实现,支持jsondataheaderstimeout四个扩展参数(client.py):

  • json:序列化为 JSON 字节并自动设置content-type: application/json;与data同时传入会抛出ValueError
  • data:字符串按 UTF-8 编码;dict/list 会被urlencode为表单并设置application/x-www-form-urlencoded;同时自动计算content-length
  • headers:dict 形式,值为字符串或字符串列表;
  • timeout:int/float/timedelta 均可,最终换算为毫秒并写入x-envoy-upstream-rq-timeout-ms头(见 utils.py)。

Response对象(response.py)暴露了丰富的读取能力:

  • response.status_code/response.headers/response.trailers:从:status伪头解析状态码,头信息由回调逐条填充;
  • await response.body:读取完整响应体并缓存,重复调用直接返回缓存;
  • await response.text:以 UTF-8 解码响应体(当前未根据 charset 头动态解码,属 TODO 项);
  • await response.json():将响应体解析为 JSON;
  • response.content.read(n)StreamReader流式读取接口,可每次读取 n 字节,避免大响应整体缓冲(默认_READ_SIZE = 1024,见 response.py);
  • response.ok:状态码小于 400 即为真;raise_for_status()在非 2xx/3xx 时抛ClientResponseError
  • async with responseresponse.close()可取消未完成的底层流。

Response内部通过attach()注册on_headers/on_data/on_trailers/on_complete/on_error/on_cancel六个回调,且开启explicit_flow_control=True(显式流控),即每次通过stream.read_data(n)主动向 Envoy 请求数据块(response.py)。

并发请求

同一个AsyncClient可并发发起多个请求。集成测试 async_client_fetch_test.py 展示了用asyncio.gather同时发送 GET/POST 并统一等待响应的写法,测试还覆盖了自定义请求头、流式逐字节读取、JSON 请求、json/data冲突报错、404 时raise_for_status等场景,可作为最佳实践参考。

直接使用 Engine 与 Stream 底层 API

对于需要精细控制的高级场景,README 提供了绕过AsyncClient、直接与EngineStream交互的方式。该方式不依赖 asyncio,适合在纯回调/线程模型中使用:

from envoy_mobile import EngineBuilder, LogLevel def on_data(data, end_stream): print(f"Received data: {data}") builder = EngineBuilder().set_log_level(LogLevel.debug) engine = builder.build() # Create a stream and send a request stream = engine.get_stream_client().new_stream_prototype() \ .on_data(on_data) \ .start() stream.send_headers({"method": "GET", "scheme": "https", "authority": "google.com", "path": "/"}, True)

注意:当前仓库 API 与 README 示例的差异

需要指出的是,当前仓库版本的绑定 API 与 README 示例存在细微差异:在 module_definition.cc 中,StreamClient通过engine.stream_client(listener_name)获取(listener_name默认为空字符串),流回调通过StreamPrototype.start(on_headers=..., on_data=..., on_complete=..., ...)关键字参数一次性注册,Stream提供send_headers(headers, end_stream, idempotent=False)send_data(bytes)close(bytes|dict)cancel()read_data(n)方法。集成测试 fetch_test.py 展示了当前仓库中直接流式编程的标准写法:

stream = ( engine.stream_client() .new_stream_prototype() .start( on_headers=on_headers, on_data=on_data, on_complete=on_complete, on_error=on_error, on_cancel=on_cancel, ) ) headers = { ":method": "GET", ":scheme": "http", ":authority": self._echo_server_url, ":path": "/", } stream.send_headers(headers, end_stream=True)

因此在实际编码时,应以本仓库 module_definition.cc 中 pybind11 暴露的签名为准。请求头必须使用 HTTP/2 伪头形式(:method:scheme:authority:path),end_stream=True表示请求侧立即结束。

回调与流内省数据

流回调携带两类内省对象(module_definition.cc):

  • StreamIntel:流级信息,含stream_idconnection_idattempt_count(重试次数)、consumed_bytes_from_response(已消费的响应字节数);
  • FinalStreamIntel:流结束时的最终统计,含 DNS 解析、TCP 连接、TLS 握手、发送/接收各阶段的毫秒时间戳(未发生阶段为 -1)、socket_reusedsent_byte_countreceived_byte_countupstream_protocol等。

on_error收到的EnvoyError带有error_codemessage,错误码枚举ErrorCode包括UndefinedErrorStreamResetConnectionFailureBufferLimitExceededRequestTimeout(module_definition.cc)。测试 fetch_test.py 验证了取消流的语义:取消后stream_start_ms/stream_end_ms有值,而sending_end_msresponse_start_msupstream_protocol为 -1。

EngineBuilder 高级配置

EngineBuilder是引擎配置的入口,链式调用、逐项返回自身。pybind11 绑定(module_definition.cc)暴露了完整的配置面,核心项分类如下:

类别方法说明
日志set_log_level(level)enable_logger(bool)日志级别枚举LogLevel:trace/debug/info/warn/error/critical/off
生命周期set_on_engine_running(closure)set_on_engine_exit(closure)引擎就绪/退出回调
网络超时add_connect_timeout_seconds(n)set_stream_idle_timeout_seconds(n)set_per_try_idle_timeout_seconds(n)连接超时、流空闲超时、单次尝试空闲超时
DNSadd_dns_refresh_seconds(n)add_dns_failure_refresh_seconds(base, max)add_dns_query_timeout_seconds(n)add_dns_min_refresh_seconds(n)enable_dns_cache(on, save_interval_seconds=1)DNS 刷新/失败回退/查询超时/最小刷新间隔/持久缓存
协议enable_http3(bool)add_quic_hint(host, port)add_quic_canonical_suffix(suffix)add_h2_connection_keepalive_idle_interval_milliseconds(ms)add_h2_connection_keepalive_timeout_seconds(n)HTTP/3 开关、QUIC 预连接提示、H2 keepalive
连接池add_max_connections_per_host(n)单主机最大连接数
传输优化enable_gzip_decompression(bool)enable_brotli_decompression(bool)enable_interface_binding(bool)enable_socket_tagging(bool)enable_worker_thread(bool)解压、网卡绑定、socket tag、worker 线程
安全enforce_trust_chain_verification(bool)enable_platform_certificates_validation(bool)set_upstream_tls_sni(sni)信任链校验、平台证书校验、上游 SNI
标识set_app_version(v)set_app_id(id)set_device_os(os)set_node_id(id)应用/设备/节点标识,用于统计上报
运行时add_runtime_guard(guard, value)enable_stats_collection(bool)set_network_thread_priority(n)运行时开关、统计采集、线程优先级
收尾build()构建并启动引擎(GIL 释放)

集成测试中常见的组合是开启 worker 线程、统计与 socket tagging,并通过set_on_engine_running+threading.Event等待引擎就绪(见 httpx_transport_fetch_test.py):

engine_running = threading.Event() engine = ( EngineBuilder() .set_log_level(LogLevel.info) .enable_stats_collection(True) .enable_socket_tagging(True) .set_on_engine_running(lambda: engine_running.set()) .enable_worker_thread(True) .build() ) engine_running.wait(timeout=30)

与 httpx 生态集成:Transport 与共享引擎

除自带的AsyncClient外,该库还提供一套完整的 httpx transport 适配,让httpx.Client/httpx.AsyncClient直接跑在 Envoy 引擎之上:

  • EnvoyClientTransport:同步 transport,用threading.Eventqueue.Queue桥接 Envoy 回调与 httpx 同步迭代;
  • AsyncEnvoyClientTransport:异步 transport,用asyncio.Futureasyncio.Queue桥接回调;
  • EnvoyTransportFactory:单例工厂,保证进程内只创建一个 Envoy 引擎(引擎初始化代价高,应存活于整个进程生命周期),通过get_shared_engine()get_async_transport()get_sync_transport()对外提供。
from envoy_mobile import EnvoyTransportFactory import httpx transport = EnvoyTransportFactory.get_async_transport() async with httpx.AsyncClient(transport=transport) as client: response = await client.get("https://example.com")

请求头映射与限制

transport 层通过 get_envoy_headers 将httpx.Request映射为 Envoy 伪头格式,并有几点工程化处理:

  • 跳过连接相关头connectionkeep-aliveproxy-connectiontransfer-encodingupgrade这些 HTTP/1.1 专有头在 HTTP/2 中是被禁止的,直接丢弃,交由 Envoy 自己设置正确的上游连接头;
  • 避免覆盖伪头与 host:开头的头和host头会被跳过,由 Envoy Mobile 自动设置权威主机;
  • socket tag:每个 transport 实例通过itertools.count生成唯一的 32 位 tag,并写入x-envoy-mobile-socket-tag头,用于连接池隔离;transport 关闭时调用engine.drain_connections_by_socket_tag(tag)精准排空该 transport 的连接而不影响其他 transport(测试见 httpx_transport_fetch_test.py)。

错误映射

Envoy 错误码会被映射为 httpx 异常(httpx_utils.py):ConnectionFailure(2)httpx.ConnectErrorRequestTimeout(4)httpx.ReadTimeoutStreamReset(1)httpx.RemoteProtocolError,其余归入httpx.RequestError

请求体流式发送

同步/异步 transport 都采用“先发头(end_stream=False)→ 逐块send_datastream.close(b"")标记结束”的三段式发送(async_client_transport.py),支持生成器作为请求体逐块发送、大文件上传不整体驻留内存;响应侧则以 64KB 为单位read_data(65536)拉取数据(async_client_transport.py)。

构建与打包(Bazel)

该库使用 Bazel 构建,mobile/library/python/BUILD 给出了完整定义:

  • envoy_engine:pybind11 扩展(pybind_extension),入口 module_definition.cc,依赖 C++ 层的//library/cc:engine_builder_lib//library/cc:envoy_engine_cc_lib_no_stamp等;产物为envoy_engine.so(Windows 为 .pyd),并通过 genrule 拷贝到envoy_mobile/包目录内以便随 wheel 分发;
  • envoy_mobile_lib:纯 Python 包(glob全部envoy_mobile/**/*.py),依赖httpx(来自@mobile_pip3的 pip 依赖),并打包py.typed标记(提供类型提示);
  • envoy_mobile_wheelpy_wheel目标,发行名为envoy-mobile-client,版本 0.5.0,可通过--//library/python:python_platform--//library/python:python_version两个 flag 选择平台(manylinux2014_x86_64macosx_10_15_x86_64macosx_11_0_arm64)与 Python 版本(3.12/3.13/3.14)。

README 注释中的示例构建命令为:

bazel build -c opt --strip=always \ //library/python:envoy_mobile_wheel \ --//library/python:python_platform="manylinux2014_x86_64"

小结

Envoy Mobile Python 库把 Envoy 的进程内网络引擎能力带给了 Python:日常开发优先使用基于 asyncio 的AsyncClient及其便捷的Response读取接口;需要精细化控制时直接操作Engine/Stream底层 API,借助StreamIntel/FinalStreamIntel获取完整的连接与传输时序;若已在 httpx 生态中,可选用同步/异步 transport 或共享引擎工厂,获得请求体流式发送、连接池隔离与精准排空等高级能力。实践时请注意以本仓库 module_definition.cc 中 pybind11 暴露的实际签名为准,并参考 mobile/test/python 下的集成测试验证各 API 的真实行为。

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询