Swoole HTTP Server 响应延迟高的本质是默认启用输出缓冲且 buffer_output_size=2MB,小响应不自动 flush;必须用 $response->end() 发送,流式场景才需 $response->flush()。

为什么 swoole_http_server 响应延迟高,但 curl 直连却很快?
本质是 Swoole 默认启用了输出缓冲(output buffer),且缓冲区大小、刷新策略和 PHP 的 ob_*() 函数存在隐式耦合。HTTP Server 在未显式 echo 或未满足缓冲触发条件时,不会立即发包,导致肉眼可见的“卡顿”。
- 默认
buffer_output_size是 2MB,小响应几乎从不自动 flush - PHP 的
ob_flush()+flush()在协程环境下无效,甚至会报Warning: flush(): failed to flush buffer -
swoole_http_response->end()才是真正终结并发送响应的唯一可靠方式;中间任何echo/print都只是写入 Swoole 自己的缓冲区 - 若用
swoole_http_response->write()分多次推送,必须手动调用$response->flush()(注意:不是 PHP 的flush())
swoole_http_response->flush() 什么时候必须调用?
仅在流式响应(streaming response)、SSE(Server-Sent Events)、或长轮询中需要分块返回内容时才需主动 flush()。它把当前缓冲区内容推送到 TCP 层,但不关闭连接 —— 这和 end() 有本质区别。
- 调用前确保已调用过
$response->header()(如Content-Type: text/event-stream),否则某些浏览器会等满缓冲才解析 -
flush()不保证数据立刻抵达客户端,受 TCP_NODELAY、Nagle 算法及网络栈影响;如需更低延迟,建议同时设置$server->set(['tcp_nodelay' => true]) - 频繁
flush()(比如每字节都调)会显著增加系统调用开销,实测 QPS 可降 30%+;建议单次write()至少 1KB 再flush()
buffer_output_size 设太小会出什么问题?
这个配置控制每个请求响应的最大缓冲容量,设得过小会导致 ERR_EMPTY_RESPONSE 或直接截断响应体,尤其在模板渲染、JSON 大对象或文件下载场景下极易触发。
- 默认值
2097152(2MB)对多数接口足够;若你返回的是10MB PDF,需设为12582912或更高 - 不能设为 0 或负数,Swoole 启动会报错:
Fatal error: Uncaught Swoole\Exception: invalid buffer_output_size - 该值是 per-request 的,不是全局共享缓冲池,增大不会明显增加内存压力,但极端并发下仍需按峰值响应体积 × 并发数预估内存
- 配合
sendfile(如用$response->sendfile())时,buffer_output_size不生效 —— 此时走内核零拷贝,绕过用户态缓冲
协程 HTTP 客户端收不到响应头?检查 http_compression 和缓冲链路
当你用 Swoole\Coroutine\Http\Client 调用另一个 Swoole 服务,发现 $client->headers 为空或状态码异常,大概率是服务端开启了压缩但没正确处理缓冲边界。
- 开启
http_compression => true时,Swoole 会在响应末尾追加压缩校验(如 gzip 的 CRC32),若服务端提前end()或缓冲未刷完,客户端收到的就是不完整压缩流,直接丢弃整个响应 - 务必确认服务端在
end()前已完成所有write()+ 必要的flush(),且未混用ob_start()类函数 - 调试时可用
tcpdump -i lo port 9501 -w swoole.pcap抓包验证实际发出的 HTTP 包结构,比日志更可靠










