关于Scala:Akka IO应用消耗100%的CPU

Akka IO app consumes 100% cpu

我正在尝试配置持续使用或接近100%CPU使用率的Akka应用程序。我使用visualvm提取了CPU示例。该示例表明有2个线程占CPU使用率的98.9%。 79%的cpu时间用于称为sun.misc.Unsafe的方法。关于SO的其他答案说,这仅意味着线程正在等待,但在本机实现层中(jvm之外)。

在与我的问题类似的情况下,人们被告知要寻找其他地方,但未提供具体细节。我在哪里应该找出导致CPU峰值的原因?

该应用程序是一台主要使用Akka IO来侦听TCP套接字连接的服务器。


在没有看到任何源代码的情况下,甚至在不知道您在说什么IO通道(套接字,文件等)的情况下,这里的任何人都可以给您很少的见识。

我确实有一些相当笼统的建议。

首先,您应该在应用程序中使用反应式技术和反应式IO。发生此问题的原因是,您正在紧密循环中轮询某些资源的状态,或者在应该使用响应式资源时使用阻塞调用。正是由于您可以花费CPU周期"主动等待"而没有做任何事情,所以这往往会成为反模式和性能下降。我建议仔细检查以下内容:

  • 资源轮询
  • 阻止通话

    • 系统调用
    • 磁盘刷新
    • map合适的时候等待Future

第二,您不应该在应用程序中使用Mutexes或其他线程同步。如果是这样,那么您可能正在遭受活锁的困扰。与死锁不同,活动锁表现为诸如100%CPU使用率之类的症状,因为线程不断锁定和解锁并发原语,以试图"全部捕获"它们。 Wikipedia很好地描述了活锁的外观。有了Akka,您就不需要使用Mutexes或任何线程同步原语。如果是,那么您可能需要重新设计应用程序。

第三,您应该限制IO(以及重新连接尝试之类的错误处理)。因为您的系统缺乏有效的限制,所以可能发生此问题。通常,对于数据通道,我们保持其带宽不受限制。但是,当该通道达到100%饱和并开始从系统的其他部分窃取资源时,这可能会成为问题。例如,如果您在没有合理限制的情况下移动大型文件,则会发生这种情况。

或者,您还需要在遇到任何错误时限制连接重试,而不是立即重试。如果许多系统失去连接,它们将尝试重新连接到服务器。虽然通常很理想,但是如果您使用幼稚的重新连接策略,这可能会导致问题行为。例如,假设以这种方式编写的网络客户端:

1
2
3
4
5
6
class MyClient extends Client {
... other code...
  def onDisconnect() = {
    reconnect()
  }
}

每次客户端出于任何原因断开连接时,它将尝试重新连接。您可以看到如果拔出Wifi保险开关或网络电缆,这将如何在错误处理代码和客户端之间造成紧密的循环。

第四,您的应用程序应具有定义明确的数据源和接收器。您的问题可能是由"数据循环"引起的,即一组Akka参与者只是将消息发送到链中的下一个参与者,而最后一个参与者将消息发送回链中的第一个参与者。确保您有明确明确的方式让消息进入和退出系统。

第五,为您的应用程序使用适当的配置文件和检测。使用Kamon或Coda Hale的Metrics库检测应用程序。

要找到合适的探查器将更加困难,因为作为一个社区,我们要为响应式应用程序开发成熟的工具还有很长的路要走。我个人发现visualvm有用,但对于检测受CPU约束的代码路径并不总是绝对有帮助。问题在于,采样分析器仅在JVM达到安全点时才能够收集数据。这可能会使某些代码路径产生偏差。解决方法是使用支持AsyncGetStackTrace

的探查器

祝你好运!如果可以的话,请添加更多上下文。