【发布时间】:2020-10-30 15:25:04
【问题描述】:
我正在编写一个通过 GRPC 发送和接收消息的 Spigot 插件。 我的问题是,在查看时间后服务器崩溃,因为该进程无法为新线程打开更多文件句柄。 从查看一些线程转储来看,GRPC 似乎每秒产生多个线程而从未关闭它们。 我用来接收消息流的代码如下所示:
public class GRPCMessageReceiver extends BukkitRunnable {
ChatSyncGrpc.ChatSyncBlockingStub chatSync;
LockedQueue lockedQueue = new LockedQueue();
Iterator<ChatMessage> receivingIterator;
public GRPCMessageReceiver(ChatSyncGrpc.ChatSyncBlockingStub chatSync, LockedQueue queue){
lockedQueue = queue;
this.chatSync = chatSync;
}
@Override
public void run() {
if (receivingIterator == null) receivingIterator = chatSync.beginReceive(Empty.newBuilder().build());
try {
if (receivingIterator.hasNext()) {
ChatMessage message = receivingIterator.next();
lockedQueue.Put(message);
message.
}
} catch (io.grpc.StatusRuntimeException e) {
receivingIterator = chatSync.beginReceive(Empty.newBuilder().build());
Bukkit.getLogger().info("Chat Sync Connection Failed created new one!");
}
}
} 所有线程都有相同的堆栈跟踪:
java.lang.Thread.State: WAITING
at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at io.grpc.stub.ClientCalls$ThreadlessExecutor.waitAndDrain(ClientCalls.java:731)
at io.grpc.stub.ClientCalls$BlockingResponseStream.waitForNext(ClientCalls.java:622)
at io.grpc.stub.ClientCalls$BlockingResponseStream.hasNext(ClientCalls.java:643)
at HausSheepPlugin.GRPCMessageReceiver.run(GRPCMessageReceiver.java:26)
at org.bukkit.craftbukkit.v1_16_R2.scheduler.CraftTask.run(CraftTask.java:81)
at org.bukkit.craftbukkit.v1_16_R2.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:54)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.lang.Thread.run(Thread.java:832)
这是我的问题还是 GRPC 的问题?
【问题讨论】:
-
看起来这是一个流式 RPC。流是否从服务器正确关闭?如果没有,您将有无数个线程都在等待它们的流结束。
-
系统设置为Server可以向Client推送消息,而不是Client不断拉取消息。因此,只有在连接中断/服务器或客户端关闭时,服务器才会关闭流。
-
那么您运行了多少个 RPC?
run()预计只会发生一次还是多次? -
运行每秒执行两次。第一次调用
run()时调用beginReceive方法,当hasNext()函数抛出io.grpc.StatusRuntimeException时,这意味着连接出现故障。我已经检查过连接不会在每次Run()执行时重新建立。 -
你能说明
run()是如何被执行的吗?receivingIterator存储在哪里?