最近添哥一直反映,他手下的设备以grpc stream的方式向我服务端发送数据。偶然会收到错误。现象如下:

  1. 连接已经建立了一段时间,正常使用。
  2. 突然client.Send 返回 eof。
  3. 客户端有报错:connection reset by peer
  4. 在服务端找到错误:context canceled

这里不得不提一下,客户端上报到服务的网络环境并不是很好,而且服务端每个进程有数十万个协程在运行,处理上十万条grpc stream。

选取了几个设备在服务端与客户端tcpdump,通过七七四十九天,终于捕获到了异常时的抓包。

现象:

  1. 正常情况下,服务端客户端定期互Ping。
  2. 当异常时,在服务端/客户端的抓包会发现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

发包之后逻辑

  1. 检测是否在kpTimeoutLeft为0前收到了任何数据(不仅是ping的回包)。
  2. 此时outstandingPing为true,所以不会再有新的ping被发出。这是最坑的一点设计。合理的设计应该允许重试几次,以重试后能收到包为准。
  3. 不停的去sleep,并去减小kpTimeoutLeft。
  4. 当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 的一种解决方案的更多相关文章

  1. connection reset by peer问题总结及解决方案

    找遍了 中英文网站,翻遍了能找的角落,发现了出现故障的原因和原理,及改如何处理,这里记录下,希望能帮助到有需要的小伙伴,少走点弯路, 以上就整理内容: connection reset by peer ...

  2. Doker GRPC "Connection reset by peer"

    https://success.docker.com/article/ipvs-connection-timeout-issue https://forums.docker.com/t/setting ...

  3. ”Connection reset by peer“引发的思考

    闲来无事,把之前写的一个游戏服务器框架(<一个java页游服务器框架>),部署到阿里云服务器上,测试运行了下,结果看到后台log中打印出了“Connection reset by peer ...

  4. 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)"将会导致如下错误:

  5. ab测试出现error: connection reset by peer的解决方案

    我们在使用一些开源程序之前,可能会使用ab工具在服务器或者本地进行一次性能评估,但是很多时候却总是会以失败告终,因为,服务器会拒绝你的ab工具发出的http请求, 出现 error: connecti ...

  6. gem install 出现Errno::ECONNRESET: Connection reset by peer - SSL_connect (https://api.rubygems.org

    在安装了rvm来管理多版本的ruby之后,想在不同环境下安装一些gems,结果gem install puma 之后,发现一次又一次失败. gem install 出现Errno::ECONNRESE ...

  7. 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) ...

  8. apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104))

    apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104))   今天用apache 自带的ab工具测试,当并发量达到1000多的时 ...

  9. java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)

    java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)

随机推荐

  1. python学习-Day7

    目录 作业讲解 数据类型内置方法2 字符串(str) 列表(list) 类型转换 内置方法 索引取值 切片操作 步长 统计列表中元素的个数 成员运算 (in和not in) 列表添加元素的方式* 删除 ...

  2. 单列集合(Collection-List)

    与数组的区别 ArrayList while循环快捷键itit 遍历方法2:增强for循环 快捷键大写的I List接口(少部分常用的) List三种遍历方式 注意事项 ArrrayList底层结构和 ...

  3. k8s入门之PV和PVC(八)

    某些应用是要持久化数据的,如果直接持久化在pod所在节点,当pod因为某种原因重建或被调度另外一台节点,是无法访问到之前持久化的数据,所以需要一个公共存储数据的地方,无论pod删除重建或重新调度到其他 ...

  4. SpringBoot项目刚刚创建就报异常,Failed to configure a DataSource: 'url' attribute is not specified and no embedded 的解决办法

    错误信息: Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedde ...

  5. [题解] [AGC024F] Simple Subsequence Problem

    题目大意 有一个 01 串集合 \(S\),其中每个串的长度都不超过 \(N\),你要求出 \(S\) 中至少是 \(K\) 个串的子序列的最长串,如果有多解,输出字典序最小的那组解. 由于 \(S\ ...

  6. Python技法:用argparse模块解析命令行选项

    1. 用argparse模块解析命令行选项 我们在上一篇博客<Linux:可执行程序的Shell传参格式规范>中介绍了Linux系统Shell命令行下可执行程序应该遵守的传参规范(包括了各 ...

  7. 520,用Python定制你的《本草纲目女孩》

    摘要:让我们来用Python定制出心仪的"本草纲目女孩",敲出魔性的代码舞蹈,520,准备好心仪女孩的舞蹈视频,把这份别出心裁的礼物给TA 本文分享自华为云社区<[云驻共创] ...

  8. 好客租房49-组件的props(特点)

    特点 1可以给组件传递任意类型的数据 2props是只读的对象 只能读取属性的值 无法修改对象 3注意:使用类组件时 如果写了构造函数 应该将props传递给super() 否则 无法在构造函数 中获 ...

  9. [算法学习] 换根dp

    换根dp 一般来说,我们做题的树都是默认 \(1\) 为根的.但是有些题目需要计算以每个节点为根时的内容. 朴素的暴力:以每个点 \(u\) 作为 \(root\) 暴力dfs下去,复杂度\(O(n^ ...

  10. TornadoFx实现侧边栏菜单效果

    原文地址:TornadoFx实现侧边栏菜单效果 - Stars-One的杂货小窝 之前年前研究的东西,给蓝奏批量下载器重构了页面,实现了侧边栏菜单的效果,稍微总结下把 效果 实现 首先,要说明的是,总 ...