-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Open
Description
您好,请问是否有sendfile实现零拷贝的计划呢?
HttpHandler::sendFile(使用的是read->WriteBody) 走的还是用户态的文件全量读取,内存消耗会比较大。
当前我使用的是分块流式传输来实现的大文件传输,不过分块传输走的也是用户态拷贝,但是可以解决内存消耗问题。
下面是AI生成的内容,仅供参考:
1、期望行为:
使用 sendfile(2)(Linux)/ TransmitFile(Windows)让数据直接在内核态从文件页缓存传到 socket 缓冲区:
2、实现建议:
针对 defaultLargeFileHandler 场景:
- HTTP 响应头通过 hio_write() 正常发送(headers 很小,用户态拷贝没影响)
- Headers 刷新完成后,通过 sendfile(fd_socket, fd_file, &offset, count) 传输 body
- sendfile 可能不会一次发完,需要注册 EPOLLOUT 事件在 socket 可写时继续
- 传输完成后调用 writer->End() 清理
3、需要考虑的问题:
- 需要 socket fd:sendfile(2) 需要 socket 文件描述符。hio_fd() 可以提供,但需要绕过事件循环的写缓冲区管理
- 写缓冲区冲突:hio_write() 使用内部写队列,sendfile 需要在 headers 完全刷新后才能开始,避免数据混乱
- SSL/TLS 不兼容:sendfile(2) 无法与 SSL 连接配合(数据必须经过 SSL 加密层),此优化仅适用于明文 HTTP
- 限速功能:当前 limit_rate 功能基于 timer 分块读取,sendfile 需要用 TCP_CORK / TCP_NODELAY 或 OS 级流控代替
- 跨平台:Linux sendfile(2)、macOS sendfile(2)(参数不同)、Windows TransmitFile 需要平台抽象层
4、最小可行方案:
- 如果完整实现较复杂,也可以考虑暴露一个 hook,让用户在 headers 发送后接管 body 传输
// 在 headers 发送后,允许用户直接操作 socket fd 传输文件
writer->SendFileBody(filepath, offset, length);
-或者提供获取底层 socket fd 的方法,让用户自行实现 sendfile。
5、参考:
- nginx 默认启用 sendfile,静态文件吞吐量提升 30-50%
- Go net/http 通过 io.Copy + *os.File 自动使用 sendfile
- 此外 Linux 5.6+ 的 io_uring IORING_OP_SPLICE / IORING_OP_SEND_ZC 也是潜在的零拷贝方案
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels