跑一段管道命令,屏幕上蹦出 Broken pipe;写后端接口,日志里也时不时冒出 java.io.IOException: Broken pipe。很多人第一反应是程序有 bug,其实大多数时候是「对方先走了」。

管道里发生了什么

Linux 里管道连接一个进程的输出和一个进程的输入。读的那一头关闭了,写的那一头再往里写,内核就会回 SIGPIPE 信号,默认行为是终止进程,于是就出现了 Broken pipe。

最典型的例子:

cat bigfile.log | head -5

head 读够 5 行就退出,管道读端关闭,cat 还在拼命写,写不进就报错。这不是 cat 有问题,是正常现象,把 stderr 丢掉就清净了:

cat bigfile.log 2>/dev/null | head -5

Web 服务里的 Broken pipe

后端接口报这个错,多半是客户端提前断开了:用户关掉了页面、手机切换了网络、接口太慢触发了浏览器或者网关的超时。服务器还在往这个已经关闭的连接里写响应,于是抛异常。

所以看到 Broken pipe 首先要问的是:这个接口是不是太慢。慢查询、大文件导出、同步调用第三方,都是高危场景。

该不该处理

它不是致命错误,不需要让整个线程池报错或者疯狂重试。合理的做法是:

  • 降低日志级别:客户端断开是常态,打成 ERROR 会淹没真正的问题,改成 WARN 或者单独统计。
  • 缩短后端耗时:把大任务改成异步,接口快速返回任务 ID,前端轮询结果。
  • 设置合理的超时:网关、Nginx、应用三层超时要小于上层、大于下层,避免一层还在等另一层已经放弃。
  • 加断点续传:大文件下载用 Range 请求,断了能接着来。

SSH 和 Git 场景

通过 SSH 执行长命令,网络一抖就容易断,报写管道失败。这种情况用 tmux 或者 screen 把会话挂在服务器上,比调客户端参数更靠谱。Git push 报 Broken pipe 通常是包太大或者网络不稳,先缩小单次推送体积,再检查 MTU 和代理。

记住一句:Broken pipe 是「对面走了」,先想对面为什么走,再想自己能不能更快。