3

我们有一个用 Java 编写的 RMI 客户端应用程序,它需要定期向服务器应用程序发送“保持活动”消息。我们将其实现为一个单独的心跳线程,它将保持活动状态消息发送到服务器,然后使用 Thread.sleep() 休眠 15 秒。

线程设置为高优先级:

Thread heartbeatThread = new Thread(new HeartbeatRunnable(server));
heartbeatThread.setPriority(Thread.MAX_PRIORITY);
heartbeatThread.start();

但是,当客户端运行的机器占用大量 CPU 时,我们会发现心跳丢失,这导致服务器认为我们的客户端应用程序已经死亡。

我们在我的主线程中添加了 Thread.yield() 调用,尽管这并没有解决问题。

有什么方法可以保证在我的应用程序仍在运行时按时发送心跳?

4

6 回答 6

3

你不能真正保证它。您可以在不同的线程中发送心跳,以防止发送心跳所花费的时间被添加到您的延迟中。还建议将两次心跳之间的延迟设置为服务器用来确定客户端死亡的时间的一半,即如果您的服务器在 15 秒后超时您的客户端,(尝试)每 7.5 秒发送一次心跳。

于 2009-03-24T10:38:17.883 回答
2

这取决于哪个进程正在使用 CPU。

如果这不是您的进程,并且客户端进程确实没有响应,那么它对于所有意图和目的都没有生命,因此不发送心跳是合适的。当盒子加载过多而无法执行此操作时,有一条心跳消息显示“我已起床并且可以处理消息”会产生误导。

如果心跳消息的意图是说“此进程正在运行,但可能需要半小时才能回复您”,那么让正在处理的任何事情将该消息发送到服务器。或者将超时设置为适合客户端响应能力的超时。

于 2009-03-24T10:48:11.837 回答
1

您应该配置服务器在确定客户端不可用之前等待的“丢失的心跳”数量。

因此,例如,如果您的心跳间隔为 15 秒并且错过的心跳数为 4,那么服务器将最多等待 60 秒(1 分钟),然后再确定客户端无法访问。

于 2009-03-24T13:49:38.967 回答
1

您可以通过在代码中自由地散布一个自写的“yield”函数来在非线程环境中实现用户模式线程。

同样,您可以在代码中自由地分散心跳检查函数调用。放弃线程,只需定期调用一个心跳函数来检查是否需要发送心跳。

这是一个粗略的解决方案,但鉴于您已经尝试了正确的解决方案并且它不起作用,也许这是您必须回退的东西。

事实上,你可以做的是在每个函数调用的开头放置一个宏,它可以快速检查时间并在必要时调用心跳函数。

(啊,你有 Java 中的宏吗?我认为没有 - 但你明白了)。

于 2009-03-28T14:20:50.560 回答
0

也许最好的解决方案是使用 Timer 的scheduleAtFixedRate。这样,如果一个执行延迟(这在 Java 中无法避免),后续调用将不会受到影响。

于 2009-03-24T10:49:36.997 回答
0

如果您希望服务器宣布它是活动的,您最好提供一个打开的套接字。在您的客户端上,只需从该套接字读取。它会阻塞(因为您的服务器没有写入任何内容),如果服务器消失/关闭,您的客户端将收到一个 IOException 指示服务器套接字/端口已消失。

这将不依赖于提供及时心跳的服务器。它使用很少的资源(服务器端的 TCP 端口,几乎没有带宽),并且在服务器(或服务器机器)变得不可用时及时显示。

于 2009-03-24T11:39:51.213 回答