gRPC-Java 怎么配置 Keepalive 以及时发现断开的连接【免费下载链接】grpc-javaThe Java gRPC implementation. HTTP/2 based RPC项目地址: https://gitcode.com/GitHub_Trending/gr/grpc-java长连接的 gRPC 通道有一个隐蔽的问题对端进程崩溃、机器宕机或网络中断后客户端可能毫无察觉下一次 RPC 才会带着失败暴露出来。gRPC-Java 提供基于 HTTP/2 PING 帧的 keepalive 机制来解决这个问题当连接上没有数据传输时一端按固定间隔向另一端发送 PING 帧如果 PING 在超时时间内没有被确认这条连接就会被判定为已断开并关闭从而把静默断连变成可感知的连接失效。下面基于仓库中的 keepalive 示例 KeepAliveClient 和 KeepAliveServer 说明如何在客户端和服务端两侧完成配置以及如何用日志验证 PING 帧确实在收发。示例的运行前提keepalive 示例位于 examples/src/main/java/io/grpc/examples/keepalive它复用了 helloworld 示例的Greeter服务服务端监听localhost:50051客户端发起一次sayHello调用然后Thread.sleep(30000)让连接空转 30 秒——这段时间内没有任何 RPC 活动正是 keepalive PING 生效的窗口。按照 examples/README.md 的说明示例要求 grpc-java 已经构建好如果是非发布的版本例如 master HEAD需要先按 COMPILING.md 把 grpc-java SNAPSHOT 和代码生成插件安装到本地。构建示例用 Gradlecd examples ./gradlew installDist完成后会在examples/build/install/examples/bin/下生成hello-world-server、hello-world-client等可执行脚本每个示例都要求先启动服务端再启动客户端。客户端用 ManagedChannelBuilder 配置 PING 节奏keepalive 的配置入口是 channel 构建器。示例使用的核心代码是ManagedChannel channel Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) .keepAliveTime(10, TimeUnit.SECONDS) // Change to a larger value, e.g. 5min. .keepAliveTimeout(1, TimeUnit.SECONDS) // Change to a larger value, e.g. 10s. .keepAliveWithoutCalls(true)// You should normally avoid enabling this. .build();三个参数的含义以 ManagedChannelBuilder 的 API 注释和示例内注释为准keepAliveTime(10, TimeUnit.SECONDS)连接上没有读活动时每隔多久发一个 keepalive PING。示例注释说明 10 秒只是演示值实际应按环境取更大的值例如keepAliveTime(5, TimeUnit.MINUTES)。过小的值可能被底层实现调大设为Long.MAX_VALUE纳秒或一个过大的值会直接禁用 keepalive默认就是无限即不启用。keepAliveTimeout(1, TimeUnit.SECONDS)发出 PING 后等待确认ack的时长超时且连接上没有任何读活动连接就被视为已死。默认是 20 秒。API 注释明确这个值应当至少是 RTT 的数倍以容忍丢包示例同样提醒 1 秒只适合某些低延迟环境实际取值例如keepAliveTimeout(10, TimeUnit.SECONDS)。keepAliveWithoutCalls(true)允许在没有未决 RPC 的连接上发 PING默认false。示例注释写明正常情况下应避免开启。API 注释给出的理由很直接空闲连接上的 keepalive 可能悄悄消耗可观的带宽和 CPU无调用场景一般应改用idleTimeout()。两点需要特别留意。其一API 注释要求客户端在启用 keepalive 前获得服务所有者的许可因为 keepalive 会增加服务端负载且通常不可见难以被发现是否造成了过量压力所以应只取必要的最小值。其二在支持 TCP_USER_TIMEOUT 的实现grpc-netty 在 netty-transport-native-epoll 支持的 Linux 平台中启用 keepalive 会连带启用 TCP_USER_TIMEOUT要求所有发出的包在 keepalive 超时前都收到 TCP 确认——这是文档声明的实现行为跨平台部署时值得关注。服务端容忍客户端 PING并管理连接生命周期服务端侧的配置在 ServerBuilder 上示例服务端的完整配置是int port 50051; server Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .keepAliveTime(5, TimeUnit.SECONDS) .keepAliveTimeout(1, TimeUnit.SECONDS) .permitKeepAliveTime(5, TimeUnit.SECONDS) .permitKeepAliveWithoutCalls(true) .maxConnectionIdle(15, TimeUnit.SECONDS) .maxConnectionAge(30, TimeUnit.SECONDS) .maxConnectionAgeGrace(5, TimeUnit.SECONDS) .build() .start();这些参数分两组。第一组控制服务端自己的探测节奏与客户端同名参数语义相同keepAliveTime(5, TimeUnit.SECONDS)服务端空闲 5 秒后就向客户端发 PING确认连接仍然存活。API 注释说受支持时典型默认值是两小时。keepAliveTimeout(1, TimeUnit.SECONDS)等待 PING ack 的时长超时则判定连接已死默认 20 秒同样应取 RTT 的数倍。第二组是服务端对客户端行为和资源的管理permitKeepAliveTime(5, TimeUnit.SECONDS)客户端允许的最激进 keepalive 间隔如果客户端 PING 得比这个频率更快服务端会强制关闭连接。受支持时典型默认值是 5 分钟。API 注释同样强调未经服务所有者许可不应使用 keepalive未加限制的 keepalive 可能带来大量流量和 CPU 开销。permitKeepAliveWithoutCalls(true)允许客户端在没有未决 RPC 时也发 keepalive PING受支持时默认false。maxConnectionIdle(15, TimeUnit.SECONDS)连接空闲超过该时长从最近一次未决 RPC 清零或连接建立时算起会被优雅终止。maxConnectionAge(30, TimeUnit.SECONDS)连接存活超过该时长会被优雅终止实现上会附加 ±10% 的随机抖动。maxConnectionAgeGrace(5, TimeUnit.SECONDS)达到 maxConnectionAge 后给未决 RPC 的宽限时间宽限内没完成的 RPC 会被取消连接随之关闭。需要说明ServerBuilder 中这组 keepalive/连接管理方法均标注为ExperimentalApi自 1.47.0 引入升级版本时留意其稳定性承诺。这些示例值5 秒、1 秒、15 秒、30 秒同样是加速演示用注释里明确写着demo only, you should set more appropriate values based on your real environment。用日志验证 PING 帧确实在收发两个示例的注释都给出同一套验证手段通过 Java logging 配置把 gRPC 内部日志开到 FINE 级别就能看到 keepalive PING 帧。examples/logging.properties 的内容如下handlersjava.util.logging.ConsoleHandler io.grpc.levelFINE java.util.logging.ConsoleHandler.levelALL java.util.logging.ConsoleHandler.formatterjava.util.logging.SimpleFormatter启动时通过 JVM 参数指向该文件文件自身也注明了这一用法JAVA_OPTS-Djava.util.logging.config.filelogging.properties 你的启动命令验证流程先启动配置好的服务端再在另一个终端启动客户端。客户端成功会先打印一次问候 RPC 的结果然后进入 30 秒空转由于连接上没有活动客户端按keepAliveTime示例中 10 秒发出 PING服务端按自己的keepAliveTime示例中 5 秒反向发 PING。此时观察 FINE 级别日志中出现的 keepalive PING 帧记录即可确认两侧的 keepalive 配置都实际生效。如果怀疑连接已断开判定逻辑就是文档描述的机制本身某个方向的 PING 在keepAliveTimeout内没有收到 ack该侧就会关闭连接。取值与适用边界把文档中明确的约束汇总一下配置时逐条对照keepalive 只在连接上没有活动no activity时才需要示例注释和 API 注释都以空闲时发 PING为前提有持续 RPC 流量的连接本身就有读写活动。keepAliveTime过小的值可能被实现调大取Long.MAX_VALUE纳秒或过大的值等价于禁用 keepalive。keepAliveTimeout默认 20 秒应取至少数倍于 RTT 的值示例里的 1 秒属于演示用的激进值。keepAliveWithoutCalls和permitKeepAliveWithoutCalls默认都是关闭的开启前者需要服务所有者许可无调用场景优先考虑idleTimeout()。服务端超过permitKeepAliveTime频率的客户端 PING 会被强制断连如果你的客户端 keepalive 比服务端的容忍间隔更激进连接会被服务端关掉两侧参数需要配合。示例中的具体数值10 秒/5 秒的 PING 间隔、1 秒超时、15/30/5 秒的连接生命周期都是加速演示的取值生产取值必须按你的环境设定不要照抄演示值。仓库的 keepalive 示例 README 还指向了 gRPC 官方的 gRFC A8客户端侧 keepalive与 gRFC A9服务端侧连接管理提案文档ManagedChannelBuilder和ServerBuilder的 API 注释同样引用了这两份提案需要深入协议层面的细节时可以从这两个提案和 api/src/main/java/io/grpc/ManagedChannelBuilder.java、api/src/main/java/io/grpc/ServerBuilder.java 的注释继续读起。配置完成后回到 FINE 日志确认 PING 帧按预期间隔出现、断连场景下连接在keepAliveTimeout后被关闭这次 keepalive 配置就可以算落地了。【免费下载链接】grpc-javaThe Java gRPC implementation. HTTP/2 based RPC项目地址: https://gitcode.com/GitHub_Trending/gr/grpc-java创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
