gRPC双向流无消息传输1分钟后自动断开问题排查求助
问题根因
你遇到的Received RST_STREAM with error code 1报错本质是HTTP/2流被对端主动重置,你只修改客户端超时参数没用,因为断连触发方是服务端/中间代理,或者你代码的异步逻辑有问题阻塞了事件循环导致客户端无法维持连接,具体原因和对应解决方案如下:
解决方案
1. 排查服务端及中间代理的超时配置
1分钟断连是很多组件的默认空闲超时阈值:
- 服务端gRPC配置:检查是否开启了流空闲超时、RPC最大存活时间,默认值很多是60秒,需要调整到至少5分钟,同时开启保活许可:
服务端侧需要新增配置:grpc.keepalive_permit_without_calls=1 grpc.http2.idle_timeout_ms=300000 grpc.http2.max_pings_without_data=0 - 中间组件配置:如果请求路径上有反向代理、负载均衡(比如Nginx、云厂商LB),将其TCP空闲超时、HTTP/2空闲超时调整到大于3分钟,这类组件的默认空闲超时普遍为60秒,无流量时会主动切断连接。
2. 修正异步代码的阻塞问题
你当前代码直接在协程中执行同步耗时函数do_task(),会完全阻塞异步事件循环,导致gRPC异步客户端的底层保活、心跳逻辑无法正常调度,服务端会判定客户端无响应主动断连,修改方案如下:
import asyncio async def task_handler(): if task_available: # 将同步耗时任务放到线程池执行,不阻塞事件循环 loop = asyncio.get_running_loop() await loop.run_in_executor(None, do_task) # 任务完成后将结果写入请求队列,发送给服务端
3. 补全客户端gRPC保活配置
你之前调整的超时参数没有覆盖保活相关配置,通道初始化的options需要新增以下参数:
options = [ # 允许无RPC调用时发送保活ping ("grpc.keepalive_permit_without_calls", 1), # 空闲30秒后开始发送保活ping,小于1分钟的断连阈值 ("grpc.keepalive_time_ms", 30000), # 保活ping超时时间设为5秒 ("grpc.keepalive_timeout_ms", 5000), # 取消无数据时的ping次数限制,避免被服务端主动断开 ("grpc.http2.max_pings_without_data", 0), # 客户端侧最大连接存活时间设为5分钟 ("grpc.http2.max_connection_age_ms", 300000), ] channel=grpc.aio.secure_channel(address, credentials=creds, options=options)
4. 维持请求生成器存活
双向流的请求生成器get_requests()不能在发送完初始请求后就退出,否则流会提前关闭,建议改成队列驱动实现:请求生成器持续从队列取消息发送,任务完成后将结果写入队列,全部流程结束后再终止生成器,保持流的活性。
内容的提问来源于stack exchange,提问作者doca
相关产品推荐
相关产品推荐

