提高Akka远程吞吐量

提高Akka远程吞吐量,akka,netty,throughput,akka-remote-actor,Akka,Netty,Throughput,Akka Remote Actor,我们正在考虑使用Akka进行客户机-服务器通信,并尝试对数据传输进行基准测试。目前,我们正在尝试发送一百万条消息,其中每条消息都是一个带有8个字符串字段的case类 在这一点上,我们正在努力获得可接受的性能。我们在客户端和服务器上看到大约600KB/s的传输速率和空闲CPU,所以出现了一些问题。也许是我们的网络配置 这是我们的akka配置 Server { akka { extensions = ["akka.contrib.pattern.ClusterReceptionistEx

我们正在考虑使用Akka进行客户机-服务器通信,并尝试对数据传输进行基准测试。目前,我们正在尝试发送一百万条消息,其中每条消息都是一个带有8个字符串字段的case类

在这一点上,我们正在努力获得可接受的性能。我们在客户端和服务器上看到大约600KB/s的传输速率和空闲CPU,所以出现了一些问题。也许是我们的网络配置

这是我们的akka配置

Server {
  akka {
    extensions = ["akka.contrib.pattern.ClusterReceptionistExtension"]
    loggers = ["akka.event.slf4j.Slf4jLogger"]
    loglevel = "DEBUG"
    logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
    log-dead-letters = 10
    log-dead-letters-during-shutdown = on
    actor {
      provider = "akka.cluster.ClusterActorRefProvider"
    }
    remote {
      enabled-transports = ["akka.remote.netty.tcp"]
      netty.tcp {
        hostname = "instance.myserver.com"
        port = 2553
        maximum-frame-size = 1000 MiB
        send-buffer-size = 2000 MiB
        receive-buffer-size = 2000 MiB
      }
    }
    cluster {
      seed-nodes = ["akka.tcp://server@instance.myserver.com:2553"]

      roles = [master]
    }
    contrib.cluster.receptionist {
      name = receptionist
      role = "master"
      number-of-contacts = 3
      response-tunnel-receive-timeout = 300s
    }
  }

}

Client {
  akka {
    loggers = ["akka.event.slf4j.Slf4jLogger"]
    loglevel = "DEBUG"
    logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
    actor {
      provider = "akka.remote.RemoteActorRefProvider"
    }
    remote {
      enabled-transports = ["akka.remote.netty.tcp"]
      netty.tcp {
        hostname = "127.0.0.1"
        port = 0
        maximum-frame-size = 1000 MiB
        send-buffer-size = 2000 MiB
        receive-buffer-size = 2000 MiB
      }
    }
    cluster-client {
      initial-contacts = ["akka.tcp://server@instance.myserver.com:2553/user/receptionist"]
      establishing-get-contacts-interval = "10s"
      refresh-contacts-interval = "10s"
    }
  }

}
更新:


最后,尽管讨论了序列化(见下文),但我们只是将有效负载转换为使用字节数组,这样序列化就不会影响测试。我们发现,在使用jeroMQ的24gb ram的core i7上(即zeroMQ在java中重新实现,所以仍然不是最快的),我们始终看到大约200k msgs/秒或大约20 MB/秒,而在原始akka上(即没有zeroMQ插件),我们看到大约10k msgs/秒或略低于1MB/秒。在akka+zeroMQ上尝试会使性能更差

好的,以下是我们的发现:

使用我们的客户机-服务器模型,我们能够在不做任何事情的情况下获得大约<3000 msg/秒,这对我们来说是不可接受的,但我们确实对正在发生的事情感到困惑,因为我们无法最大限度地利用cpu

因此,我们回到akka源代码,在那里找到了一个基准测试示例:

sample.remote.benchmark.Receiver

sample.remote.benchmark.Sender

这是两个类,它们使用akkaremote在同一台机器上的两个jvm之间传递一组消息。使用这个基准测试,我们能够在24g的corei7上获得大约10~15k msg/秒,使用大约50%的cpu。我们发现,调整分派给netty的分派器和线程会产生影响,但影响不大。使用“询问”而不是“告知”,会使速度稍慢,但不会太慢。使用一个由多个参与者组成的平衡池进行发送和接收,这使得发送和接收速度大大降低

为了进行比较,我们使用jeromq做了一个类似的测试,我们使用100%的CPU(相同的负载,相同的机器)获得了大约100k msg/秒

我们还通过黑客攻击发送方和接收方,使用Akka zeromq扩展将消息直接从一个jvm传递到另一个jvm,同时绕过Akka remote。在这个测试中,我们发现我们可以获得快速发送和接收,大约100k msg/秒,但性能很快就会下降。进一步检查后发现,zeromq线程和akka actor切换不能很好地结合在一起。我们本可以通过更智能地了解zeromq和akka之间的交互方式来调整性能,但在这一点上,我们决定使用原始zeromq更好


结论:如果您关心在线快速序列化大量数据,请不要使用akka。

为了便于开始远程处理,akka使用Java序列化进行消息序列化,这不是您通常在生产中使用的方法,因为它不是很快,也不能很好地处理消息版本控制

您应该做的是使用kryo或protobuf进行序列化,您应该能够获得更好的数字


你可以在这里阅读,在页面底部还有一些可用序列化程序的链接:

你能展示一些你用来发送消息的代码吗?@william rubens你能分享你测试的最终结果吗?@Tolsi,用我们的测试结果更新了问题william,Akka没有实现序列化程序——如果您没有配置正确的序列化程序(这是非常不鼓励的),那么最终将使用Java序列化,众所周知,Java序列化速度很慢。因此,您的基准测试是由Java序列化而不是Akka本身造成的。请参阅以了解如何配置序列化程序并选择一个快速的序列化程序,如Kryo或ProtoBuf或类似的东西。以下是如何使用Kryo谢谢!真的很有帮助,我会试试这个。你替换了序列化吗?这是结果吗?抱歉,有点混乱。原始问题中有一个更新,这些是我们刚刚通过网络发送字符串时的结果,因此序列化不再是一个问题。请澄清:)