go grpc: connection reset by peer 的一种解决方案
最近添哥一直反映,他手下的设备以grpc stream的方式向我服务端发送数据。偶然会收到错误。现象如下:
- 连接已经建立了一段时间,正常使用。
- 突然client.Send 返回 eof。
- 客户端有报错:connection reset by peer
- 在服务端找到错误:context canceled
这里不得不提一下,客户端上报到服务的网络环境并不是很好,而且服务端每个进程有数十万个协程在运行,处理上十万条grpc stream。
选取了几个设备在服务端与客户端tcpdump,通过七七四十九天,终于捕获到了异常时的抓包。

现象:
- 正常情况下,服务端客户端定期互Ping。
- 当异常时,在服务端/客户端的抓包会发现Ping包未回。很快连接断开。
猜测和grpc keepalive功能有关。
grpc server keepalive配置
原始配置
var keepAliveArgs = keepalive.ServerParameters{
Time: 60 * time.Second,
Timeout: 5 * time.Second,
}
s := grpc.NewServer(
grpc.KeepaliveParams(keepAliveArgs).....)
为了防止客户端断连后资源泄漏,grpc的服务端一般会配置keepalive,每隔一段时间就向空闲的client发送ping包,并计算回包的时间。当ping没有回应。则认为连接已失败(比如被墙),此时在服务端会关闭这个连接并配置svr.Context()为done。
上面的配置代表,每60S向客户端检测一次,如果ping的包没有在5秒内回,则断开连接。此时就会出现上述的异常事件。
原因分析
为了弄清keepalive的逻辑,查看源码grpc/internal/transport/http2_server.go
grpc ping发包逻辑

每隔预设的时间,就会发一个包。并将kpTimeoutLeft置为keepalive.Timeout。
发包之后逻辑
- 检测是否在kpTimeoutLeft为0前收到了任何数据(不仅是ping的回包)。
- 此时outstandingPing为true,所以不会再有新的ping被发出。这是最坑的一点设计。合理的设计应该允许重试几次,以重试后能收到包为准。
- 不停的去sleep,并去减小kpTimeoutLeft。
- 当kpTimeoutLeft<0,连接关闭。

预期外断联原因
可能是因为网络抖动或者grpc server忙不过来,使得某次的ping包被丢弃或未及时处理。造成了连接被错误的切断。
解决
一开始,想要找一找有没有retry之类的配置。不要仅丢弃一次就把连接切断,但没找到。这时,添哥突发奇想,将Timeout的时间延长。于是,keepalive的配置变成了这样:
var keepAliveArgs = keepalive.ServerParameters{
Time: 30 * time.Second,
Timeout: 90 * time.Second,
}
在这个配置下,为ping之后给了更长的反应时间,根据grpc的源码,90秒内如果有任意的数据被接收(包含收到客户端发来的消息)。连接都不会被切断。但假如客户端一直没有数据回发,猜想应该还是会把连接切断。因为ping在没有收到回消息的时候不会再进行下一次ping。
通过查看注释也能应证代码的实现:
// After having pinged for keepalive check, the server waits for a duration
// of Timeout and if no activity is seen even after that the connection is
// closed.
Timeout time.Duration // The current default value is 20 seconds.
只要在ping后timeout内有activity,连接就不会中断。还好这个业务client和server交互很频繁,在90秒内一般会有数据的交互。
立马变更,困扰我们很久的问题,用一种不是很优雅的方式解决了。
go grpc: connection reset by peer 的一种解决方案的更多相关文章
- connection reset by peer问题总结及解决方案
找遍了 中英文网站,翻遍了能找的角落,发现了出现故障的原因和原理,及改如何处理,这里记录下,希望能帮助到有需要的小伙伴,少走点弯路, 以上就整理内容: connection reset by peer ...
- Doker GRPC "Connection reset by peer"
https://success.docker.com/article/ipvs-connection-timeout-issue https://forums.docker.com/t/setting ...
- ”Connection reset by peer“引发的思考
闲来无事,把之前写的一个游戏服务器框架(<一个java页游服务器框架>),部署到阿里云服务器上,测试运行了下,结果看到后台log中打印出了“Connection reset by peer ...
- Error -27780: [GENERAL_MSG_CAT_SSL_ERROR]connect to host "124.202.213.70" failed: [10054] Connection reset by peer [MsgId: MERR-27780]
解决方案一: 备注: 此方案如果请求响应时间太长,勾选"WinInet replay instead of Sockets(Windows only)"将会导致如下错误:
- ab测试出现error: connection reset by peer的解决方案
我们在使用一些开源程序之前,可能会使用ab工具在服务器或者本地进行一次性能评估,但是很多时候却总是会以失败告终,因为,服务器会拒绝你的ab工具发出的http请求, 出现 error: connecti ...
- gem install 出现Errno::ECONNRESET: Connection reset by peer - SSL_connect (https://api.rubygems.org
在安装了rvm来管理多版本的ruby之后,想在不同环境下安装一些gems,结果gem install puma 之后,发现一次又一次失败. gem install 出现Errno::ECONNRESE ...
- OGG-01232 Receive TCP params error: TCP/IP error 104 (Connection reset by peer), endpoint:
源端: 2015-02-05 17:45:49 INFO OGG-01815 Virtual Memory Facilities for: COM anon alloc: mmap(MAP_ANON) ...
- apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104))
apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104)) 今天用apache 自带的ab工具测试,当并发量达到1000多的时 ...
- java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
随机推荐
- python学习-Day5
目录 今日学习内容详解 流程控制理论 程序执行流程分类: 重点小知识* 分支结构(if 语法) 单 if 分支 if 与 else 分支 if 与 elif 与 else 分支 if嵌套 练习 循环结 ...
- Unity实现A*寻路算法学习2.0
二叉树存储路径节点 1.0中虽然实现了寻路的算法,但是使用List<>来保存节点性能并不够强 寻路算法学习1.0在这里:https://www.cnblogs.com/AlphaIcaru ...
- NS2中couldn‘t read file “../tcl/mobility/scene/cbr-3-test“: no such file or directory解决方法
运行wireless.tcl 文件时报错:couldn't read file "../../uAMPS/ns-leach.tcl": no such file or direct ...
- Golang 实现 Redis(11): RDB 文件解析
RDB 文件使用二进制方式存储 Redis 内存中的数据,具有体积小.加载快的优点.本文主要介绍 RDB 文件的结构和编码方式,并借此探讨二进制编解码和文件处理方式,希望对您有所帮助. 本文基于 RD ...
- django-rest-framework 基础三 认证、权限和频率
django-rest-framework 基础三 认证.权限和频率 目录 django-rest-framework 基础三 认证.权限和频率 1. 认证 1.1 登录接口 1.2 认证 2. 权限 ...
- mybatis plus 使用 SQL 保留字(关键字)
MybatisPlus:使用SQL保留字(关键字)的操作 必须要手动在 entity 的字段上加注解,否则最终会报错,因为 mybatis 或者 mybatis plus 不会自动处理
- Spring Security之短信登录
实现短信验证码登录 前面实现了 用户名+密码 的登录方式,现在实现一下短信验证码登录. 开发短信验证码接口 短信验证码和图形验证码类似,用户从手机短信得到验证码和从图片得到验证码类似. 校验短信验证码 ...
- 75. Sort Colors - LeetCode
Question 75. Sort Colors Solution 题目大意: 给一个数组排序,这个数组只有0,1,2三个元素,要求只遍历一遍 思路: 记两个索引,lowIdx初始值为0,highId ...
- 485. Max Consecutive Ones - LeetCode
Question 485. Max Consecutive Ones Solution 题目大意:给一个数组,取连续1的最大长度 思路:遍历数组,连续1就加1,取最大 Java实现: public i ...
- vue ui 创建vue项目 没反应的解决办法 2021
1.升级vue 脚手架 即可 2.再 vue ui 创建项目 cnpm i -g @vue/cli