【问题标题】:How can I guarantee a "stay alive" heartbeat is sent?如何保证发送“活着”的心跳?
【发布时间】:2009-03-24 10:29:10
【问题描述】:

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

线程设置为高优先级:

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

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

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

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

【问题讨论】:

    标签: java concurrency rmi heartbeat


    【解决方案1】:

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

    【讨论】:

    • 感谢您的回复。我们已经在一个单独的线程中发送心跳,并且服务器在 90 秒内没有心跳后将我们切断,因此每 15 秒发送一次似乎是保守的。
    • 确实非常保守。但是,如果您在尝试每 15 秒发送一次心跳时未能在 90 秒内发送一次心跳,那么您的盒子就会严重超载,您的客户可能真的应该被认为已经死了。请参阅皮特的回答。
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      您可以在非线程环境中实现用户模式线程,方法是在代码中随意散布一个自写的“yield”函数。

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

            • 那不就是跟踪服务器本身是否还活着吗?目标进程可能已经崩溃(或至少变成了僵尸),而 TCP/IP 堆栈没有更明智的选择。
            • 没有。操作系统会照看这些。它会跟踪套接字/端口组合的父进程是否已启动
            猜你喜欢
            • 2014-08-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-18
            • 1970-01-01
            • 2010-09-19
            • 1970-01-01
            相关资源
            最近更新 更多