golang服务报错: write: broken pipe的解决方案
来源:脚本之家
时间:2022-12-27 11:13:10 500浏览 收藏
亲爱的编程学习爱好者,如果你点开了这篇文章,说明你对《golang服务报错: write: broken pipe的解决方案》很感兴趣。本篇文章就来给大家详细解析一下,主要介绍一下write:broken、pipe,希望所有认真读完的童鞋们,都有实质性的提高。
一、程序报错
发现BSC节点报错: write: broken pipe
2022/04/11 11:23:00 http: panic serving 172.31.34.109:32952: write tcp 172.31.6.64:9093->172.31.34.109:32952: write: broken pipe
goroutine 145578 [running]:
net/http.(*conn).serve.func1(0xc000399720)
/usr/local/go/src/net/http/server.go:1824 +0x153
panic(0xfbc720, 0xc008f36be0)
/usr/local/go/src/runtime/panic.go:971 +0x499
github.com/gin-gonic/gin/render.JSON.Render(...)
/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/render/json.go:56
github.com/gin-gonic/gin.(*Context).Render(0xc00621d600, 0xc8, 0x133ab98, 0xc00be29b10)
/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:927 +0x149
github.com/gin-gonic/gin.(*Context).JSON(...)
/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:970
bsc-wallet/router/apicommon.ReturnSuccessResponse(0xc00621d600, 0x0, 0x10c16c7, 0x7, 0xee3960, 0xc00ae84d20)
/go/src/bsc-wallet/router/apicommon/common.go:38 +0xc5
bsc-wallet/router/handler.BlockInfo(0xc00621d600)
/go/src/bsc-wallet/router/handler/wallethandler.go:395 +0x27e
github.com/gin-gonic/gin.(*Context).Next(...)
/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168
github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc000120340, 0xc00621d600)
/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:555 +0x2b0
github.com/gin-gonic/gin.(*Engine).ServeHTTP(0xc000120340, 0x133ec38, 0xc0067767e0, 0xc00621d500)
/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:511 +0x16b
net/http.serverHandler.ServeHTTP(0xc0001881c0, 0x133ec38, 0xc0067767e0, 0xc00621d500)
/usr/local/go/src/net/http/server.go:2887 +0xa3
net/http.(*conn).serve(0xc000399720, 0x13405b8, 0xc0059e4a40)
/usr/local/go/src/net/http/server.go:1952 +0x8cd
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3013 +0x39b
这个错误的字面意思为:客户端可能会在收到服务端响应之前断开连接
二、问题原因
想到的问题原因可能是以下两种原因:
- 服务端所在的服务器,超过了最大连接数
- 客户端在接收到服务端响应之前断开连接
2.1 连接数过大
当我们有一些高并发请求量环境时,会遇到来自于系统级别的连接数限制问题,这是因为CentOS根据系统硬件信息自己默认初始了一个限制连接数量,往往这个数量是我们遇到的问题,所以今天我们需要修改系统的默认值来达到我们需要的要求,解决一定的高并发产生的连接数问题。
使用以下命令查看当前最大连接数:
# ulimit -n 1024
临时修改: 该方法只在当前起作用
# ulimit -n 65535 # ulimit -n 65535
永久修改:修改以下配置文件
# vim /etc/security/limits.conf * soft nofile 65535 * hard nofile 65535 * soft nproc 65535 * hard nproc 65535
即便你使用limit -n 1024 等这样的修改是无法其效果的,
以及各种修改可能都不起作用:
经过我们的大量研究最终解决了该问题
2.2 调用者在接收到服务端响应之前断开连接
该问题可能是因为:client端获取响应数据,突然异常退出或直接close连接。
client退出后,server将会发送两次数据,server第一次发送给client,client返回给server RST。第二次在这个RST的连接上,server继续发送,出现broken pipe。即如下错误:
2022/04/11 12:27:53 http: panic serving 172.31.34.109:45842: write tcp 172.31.6.64:9093->172.31.34.109:45842: write: broken pipe
那么此时就会出现两个问题,server端迟迟没有响应数据给client端,那么也有可能是以下两个原因:
server端去节点请求数据的时候,节点一直没有返回连接数过高,请求需要排队处理,可能有的请求还没有处理完,就已经请求超时了
关于此问题已向client端进行求证,目前连接server端设置的超时时间是:连接超时:0.5秒,响应超时5秒
2.2.1 排查服务器上的连接数
查看系统连接数
# 获取当前socket连接状态统计信息 # cat /proc/net/sockstat sockets: used 1138 TCP: inuse 21 orphan 0 tw 0 alloc 786 mem 220 UDP: inuse 4 mem 2 UDPLITE: inuse 0 RAW: inuse 0 FRAG: inuse 0 memory 0 # 统计当前各种状态的连接的数量的命令 # netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' CLOSE_WAIT 1020 ESTABLISHED 59
查看端口范围
# 允许系统打开的端口范围,用于向外链接的端口范围 # cat /proc/sys/net/ipv4/ip_local_port_range 32768 60999
查看文件打开数
# 查看当前打开文件数 # 如果执行缓慢,那么执行结果显示系统当前打开文件数500w # lsof | wc -l 4792741 # 把当前打开文件列表保存 # lsof>>/tmp/lsof.log # 查看 5-6万 行之间的数据 sed -n '50000,60000p' /tmp/lsof.log
结果,bsc,且没有关闭:
COMMAND PID PPID USER PGID FD DEVICE SIZE NODE NAME
进程名称 进程标识符 父进程标识符 进程所有者 进程所属组 文件描述符 指定磁盘名称 文件大小 索引节点 打开文件的确切名称
bsc-wallet 2105 2125 root 1872u sock 0,7 0t0 2800355 protocol: TCPv6
bsc-wallet 2105 2125 root 1873u sock 0,7 0t0 2802021 protocol: TCPv6
bsc-wallet 2105 2125 root 1874u sock 0,7 0t0 2765499 protocol: TCPv6
bsc-wallet 2105 2125 root 1875u sock 0,7 0t0 2803112 protocol: TCPv6
bsc-wallet 2105 2125 root 1876u sock 0,7 0t0 2769274 protocol: TCPv6
bsc-wallet 2105 2125 root 1877u sock 0,7 0t0 2803114 protocol: TCPv6
bsc-wallet 2105 2125 root 1878u sock 0,7 0t0 2770305 protocol: TCPv
2.2.2 查看连接状态为CLOSE_WAIT的连接情况
统计当前各种状态的连接的数量的命令
# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' CLOSE_WAIT 1169 ESTABLISHED 84
查看CLOSE_WAIT是哪台服务器请求的,以及请求数
# netstat -a |grep "CLOSE_WAIT"|awk '{print $5}'|awk -F '.' '{print $1}' |sort | uniq -c | sort -nr 1382 ip-172-31-34-109
2.2.3 延时测试
可以看到情况为:另外一台服务器上面的服务(客户端)请求到bsc-clinet(服务端)时,由于在他设置的超时时间内未返回请求数据,客户端主动关闭了连接,导致服务端所在的服务器出现大量关于该服务端的CLOSE_WAIT的连接状态,最后服务端无法提供服务,报错: write: broken pipe
服务端未出现 CLOSE_WAIT 时的响应时间及延时
服务端目前没有CLOSE_WAIT连接状态
# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' ESTABLISHED 21
获取服务端请求响应时间
# curl -o /dev/null -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" -d "number=16619272&sign=b8aaab58e4d73753430c473ba29756d3" http://127.0.0.1:9093/api/block/blockInfo 0.000::0.000::0.088::0.088::1572245.000
-o:把curl 返回的html、js 写到垃圾回收站[ /dev/null]
-s:去掉所有状态
-w:按照后面的格式写出rt
time_namelookup:DNS 解析域名www.36nu.com的时间
time_commect:client和server端建立TCP 连接的时间
time_starttransfer:从client发出请求;到web的server 响应第一个字节的时间
time_total:client发出请求;到web的server发送会所有的相应数据的时间
speed_download:下周速度 单位 byte/s上面这条命令及返回结果可以这么理解:
0.000: DNS 服务器解析www.36nu.com 的时间单位是s
0.000: client发出请求,到c/s 建立TCP 的时间;里面包括DNS解析的时间
0.088: client发出请求;到s响应发出第一个字节开始的时间;包括前面的2个时间
0.088: client发出请求;到s把响应的数据全部发送给client;并关闭connect的时间
1572245.000 :下载数据的速度
建立TCP连接到server返回client第一个字节的时间:0.088s – 0.000s = 0.088s
server把响应数据发送给client的时间:0.088s – 0.088s = 0.000s
模拟客户端超时时间:连接超时:1秒,响应超时5秒
使用CURL时,有两个超时时间:一个是连接超时时间,另一个是数据传输的最大允许时间。
连接超时时间用–connect-timeout参数来指定,数据传输的最大允许时间用-m参数来指定。
# curl --connect-timeout 1 -m 5 -d "number=16619272&sign=b8aaab58e4d73753430c473ba29756d3" http://127.0.0.1:9093/api/block/blockInfo
超时时间没有问题,可以返回数据
服务端出现 CLOSE_WAIT 时的响应时间及延时
服务端目有大量有CLOSE_WAIT连接状态
# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' CLOSE_WAIT 1185 ESTABLISHED 31
获取服务端请求响应时间
# curl -o /dev/null -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" -d "number=16619272&sign=b8aaab58e4d73753430c473ba29756d3" http://127.0.0.1:9093/api/block/blockInfo 无法请求到服务端
模拟客户端超时
连接超时的话,出错提示形如:
curl: (7) Failed connect to 127.0.0.1:9093; Connection refused
数据传输的最大允许时间超时的话,出错提示形如:
curl: (28) Operation timed out after 30001 milliseconds with 0 out of -1 bytes received
三、解决方法
服务端出现大量的CLOSE_WAIT
连接状态,并且都是客户端请求过来的,说明是客户端主动关闭该连接,客户端需要修改以下两个问题:
- 客户端必须使用HTTP长连接池
- 客户端设置的响应超时时间5秒过于理想化,应修改该超时时间
当然,服务端此时需要请求其它服务获取数据返回给客户端,所以服务端请求时,也必须使用HTTP长连接池,延时可能也会影响该问题的出现,不过最主要的原因还是在客户端上,先修改以上两个问题即可。
希望大家通过以上方式可以解决自己的实际需求,解决自己目前所遇到的问题。
好了,本文到此结束,带大家了解了《golang服务报错: write: broken pipe的解决方案》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!
-
165 收藏
-
473 收藏
-
377 收藏
-
384 收藏
-
246 收藏
-
110 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 糟糕的服饰
- 好细啊,码起来,感谢楼主的这篇技术贴,我会继续支持!
- 2023-07-07 12:58:06
-
- 轻松的月饼
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢楼主分享技术贴!
- 2023-07-03 20:22:25
-
- 花痴的花瓣
- 这篇文章内容太及时了,师傅加油!
- 2023-06-26 00:50:47
-
- 顺心的裙子
- 赞 👍👍,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢师傅分享文章内容!
- 2023-02-05 12:09:28
-
- 受伤的冬瓜
- 太细致了,mark,感谢楼主的这篇技术贴,我会继续支持!
- 2023-01-30 18:52:07
-
- 发嗲的咖啡
- 这篇文章真及时,太详细了,很好,码起来,关注作者了!希望作者能多写Golang相关的文章。
- 2023-01-19 05:27:26
-
- 无限的咖啡豆
- 这篇技术文章真及时,很详细,写的不错,码住,关注博主了!希望博主能多写Golang相关的文章。
- 2023-01-01 07:08:12