十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Envoy io_uring:启用与调优基于 io_uring 的异步套接字 I/O

Envoy io_uring:启用与调优基于 io_uring 的异步套接字 I/O Envoy io_uring启用与调优基于 io_uring 的异步套接字 I/O【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本篇技术指南聚焦 Envoy 的 io_uring 支持通过 bootstrap 扩展envoy.extensions.network.socket_interface.default_socket_interface启用基于 io_uring 的套接字 I/O覆盖完整的示例配置、IoUringOptions全部可调参数含默认值与取值约束、内核版本要求与回退机制并结合 Envoy 仓库源码解析每个 worker 线程独立 ring、eventfd 事件集成以及读写水位反压的底层实现。io_uring 是什么以及它在 Envoy 中的工作方式io_uring 是较新 Linux 内核提供的异步 I/O 接口旨在减少网络 I/O 中的系统调用次数以提升性能。Envoy 可以配置为让所有 TCP listener 和上游连接走 io_uring 路径UDP/Datagram 套接字除外。从 线程模型文档 可以看到 Envoy 与 io_uring 的集成方式每线程独立 ring每个 worker 线程在初始化时创建自己独立的 io_uring 实例互不共享事件集成I/O 操作提交到提交队列SQ完成事件从完成队列CQ收割CQ 通过一个eventfd 与 worker 的事件循环集成因此 io_uring 能与其他事件驱动机制定时器、epoll 上的其他 fd 等透明共存。API 层面每个 worker 线程初始化时创建 ring操作提交到 SQ完成事件经 eventfd 被 worker 事件循环唤醒后收割这一点在 API proto 注释 中有明确说明。需要注意两个重要前提见 io_uring 配置文档io_uring 目前是实验性特性仍在积极开发中性能表现与内核版本强相关该特性不支持 Windows启用后要求Linux 内核至少为 5.11若内核不支持 io_uringEnvoy 会静默回退到传统 socket API不会导致启动失败。启用 io_uringBootstrap 扩展 默认套接字接口启用方式分为两部分在bootstrap_extensions中注册默认套接字接口扩展并配置io_uring_options同时在 bootstrap 顶层用default_socket_interface字段显式指向该扩展。这样 Envoy 初始化套接字接口时就会使用带 io_uring 支持的实现替换掉默认的、基于传统 socket API 的套接字接口。完整可运行的示例配置来自 io_uring.yamlstatic_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 80 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 codec_type: AUTO stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: app domains: - * routes: - match: prefix: / route: cluster: local_service http_filters: - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: local_service type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: local_service endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 8080 bootstrap_extensions: - name: envoy.extensions.network.socket_interface.default_socket_interface typed_config: type: type.googleapis.com/envoy.extensions.network.socket_interface.v3.DefaultSocketInterface io_uring_options: {} default_socket_interface: envoy.extensions.network.socket_interface.default_socket_interface配置要点io_uring_options: {}表示启用 io_uring 并全部使用默认值。该字段是google.protobuf.UInt32Value/bool包装类型不设置即走默认值字段完全不设置连io_uring_options都不写则不启用 io_uring继续使用标准 epoll I/O 路径见 proto 注释。顶层default_socket_interface字段用于显式选定套接字接口不显式声明时扩展仍会被注册但不会替换默认实现。IoUringOptions 参数详解IoUringOptions的完整定义位于 default_socket_interface.proto七个字段的含义、默认值与约束如下默认值同时可从 socket_interface_impl.cc 的解析代码 得到印证字段类型 / 默认值说明io_uring_size默认 1000SQ 队列的条目数每个在途 I/O 操作占用一个 SQECQ 按2 × io_uring_size提供溢出余量。enable_submission_queue_polling默认 false启用 SQPOLL 模式由专用内核线程轮询 SQ消除提交时的io_uring_enter()系统调用以降低延迟为代价换取更高 CPU 占用。read_buffer_size默认 8192基于readv的每次 io_uring 读起始缓冲字节数。只要连续读持续填满缓冲下一次读缓冲最多按 16 倍递增大传输因此可以用更少的读完成若启用enable_multishot_receive该值同时也是每个内核提供缓冲的大小。write_timeout_ms默认 1000关闭套接字时等待在途写操作完成的超时毫秒。io_uring 写是异步的若对端停止读取写可能永远无法完成超时后待完成写被取消并关闭套接字。write_high_watermark_bytes默认 131072128 KiB最小 4096写缓冲高水位。待写数据超过该阈值时套接字停止接受来自上层连接的新写返回 EAGAIN让反压向上传播。write_low_watermark_bytes默认 1638416 KiB最小 1024写缓冲低水位。写曾因高水位暂停后待写数据回落到该值及以下时恢复接受写。必须小于高水位否则会被钳制为write_high_watermark_bytes / 2。enable_multishot_receive默认 false启用内核 buffer ring 支撑的 multishot 读每个套接字只武装一次recv数据到达时由内核持续投递无需每次读都重新提交减少事件循环唤醒与读提交次数。buffer ring 容纳io_uring_size向上取整到 2 的幂上限 4096个缓冲、每个read_buffer_size字节因此每个 worker 线程最多占用 buffer 数 × read_buffer_size 的内存。要求内核 6.0旧内核自动回退到readv读。其中低水位钳制逻辑在源码中可以逐行验证socket_interface_impl.ccuint32_t write_low_watermark PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, write_low_watermark_bytes, 16384); if (write_low_watermark write_high_watermark) { write_low_watermark write_high_watermark / 2; }即配置错误不会导致启动失败而是被静默修正排障时需注意实际生效值可能与配置值不同。源码走读从 Bootstrap 到套接字创建io_uring 的完整链路在源码中分为三层以下逐层说明其职责均为实现事实可对照源码阅读1. Bootstrap 扩展解析SocketInterfaceImpl::createBootstrapExtensionsocket_interface_impl.cc把配置反序列化为DefaultSocketInterface消息先检查has_io_uring_options()与运行时内核探测Io::isIoUringSupported()二者都通过才创建IoUringWorkerFactoryImpl传入上述全部解析后的参数与threadLocal()并返回DefaultSocketInterfaceExtension否则返回一个持有空 factory 的扩展等价于未启用。该整段逻辑被#if defined(__linux__) !defined(__ANDROID_API__) defined(ENVOY_ENABLE_IO_URING)包围——从源码结构看io_uring 路径仅在 Linux 非 Android 且编译时启用ENVOY_ENABLE_IO_URING宏的构建中存在这解释了为何文档强调平台限制。2. 套接字创建分发SocketInterfaceImpl::makePlatformSpecificSocketsocket_interface_impl.cc在检测到线程已注册且 io_uring worker 可用时为流式套接字创建IoUringSocketHandleImpl替代默认的IoSocketHandleImplDatagram 套接字始终传入空 factory因此永远走传统路径。一个值得注意的细节在socket()函数socket_interface_impl.cc// When io_uring is enabled, SOCK_NONBLOCK becomes redundant. io_uring can multiplex sockets on // its own, and the EAGAIN caused by SOCK_NONBLOCK can lead to unnecessary event triggers. if (hasIoUringWorkerFactory(...) socket_type Socket::Type::Stream) { flags 0; }启用 io_uring 后流式套接字不再以SOCK_NONBLOCK创建——io_uring 自己负责多路复用SOCK_NONBLOCK引发的 EAGAIN 只会带来多余的事件触发。3. 每线程 ring 实现io_uring_impl.h 中的IoUringImpl实现了prepareAccept/prepareConnect/prepareReadv/prepareWritev/prepareClose/prepareCancel/prepareShutdown等提交接口以及registerEventfd/forEveryCompletion等事件集成接口CQ 溢出时内核将多余完成项暂存在 backlog 中下一次提交时冲刷代码中用checkCqOverflow()记录并告警io_uring_impl.h。配套组件包括io_uring_worker_impl.cc、io_uring_worker_factory_impl.cc均在 source/common/io以及套接字句柄封装 io_uring_socket_handle_impl.h、io_uring_socket_handle_impl.cc。底层依赖 liburing 库见 bazel/deps.yaml 中 C helpers to set up and tear down io_uring instances 的依赖声明。版本演进与行为变化结合 changelog 可以还原该特性的演进脉络便于判断所用 Envoy 版本支持哪些调优能力1.34.0changelogs/1.34.0.yaml在默认套接字接口中首次新增io_uring选项这是该特性的起点。1.39.0changelogs/1.39.0.yaml新增 multishot 读支持enable_multishot_receive内核 6.0 的 buffer ring与写反压write_high_watermark_bytes/write_low_watermark_bytesreadv读路径开始对大传输自适应增长缓冲最多 16 倍read_buffer_size作为 minor behavior change已启用 io_uring 的存量部署默认开启写反压——写缓冲超过 128 KiB 后写会返回EAGAIN回落到 16 KiB 以下恢复升级后行为会变化需要关注上层如缓冲较大的 filter 链对 EAGAIN 的容忍情况。适用前提与调优建议总结该特性的启用边界与调优要点平台仅 Linux非 Android 构建、内核 ≥ 5.11multishot 读需内核 ≥ 6.0Windows 不支持。内核不满足时自动回退传统 socket API功能不受影响但也不会报错——验证是否真正启用建议观察启动日志或对比 I/O 行为。内存预算io_uring_size决定 SQ 大小CQ 为 2 倍启用 multishot 后每个 worker 线程额外占用约min(next_pow2(io_uring_size), 4096) × read_buffer_size的缓冲池调大这两个参数前先按 worker 线程数估算总量。反压参数write_high_watermark_bytes/write_low_watermark_bytes控制写缓冲对上层反压的敏感度二者存在约束关系低水位 ≥ 高水位时自动钳制为高水位一半且要求高水位 ≥ 4096、低水位 ≥ 1024配置应满足低水位 高水位。延迟敏感场景enable_submission_queue_polling通过内核线程轮询 SQ 消除提交侧系统调用代价是持续 CPU 占用适合低延迟且 CPU 富余的部署。状态该特性在文档中被明确标注为实验性experimental升级 Envoy 版本时应留意 changelog 中 io_uring 相关行为变化。相关入口文件速查配置文档 docs/root/configuration/other_features/io_uring.rst、示例配置 docs/root/configuration/other_features/_include/io_uring.yaml、API 定义 api/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto、核心实现 source/common/network/socket_interface_impl.cc 与 source/common/io。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表