我们正在考虑使用Akka进行客户端服务器通信,并尝试对数据传输进行基准测试。目前,我们正在尝试发送一百万条消息,其中每条消息是一个case类,具有8个字符串字段。
在这一点上,我们正在努力获得可接受的性能。我们在客户端和服务器上看到大约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"
}
}
}
更新:最后,尽管有关于序列化的讨论(见下文),我们只是将有效负载转换为使用字节数组,这样序列化不会影响测试。我们发现在拥有24gb内存的core i7上使用jeroMQ(即在java中重新实现的zeroMQ -所以仍然不是最快的),我们可以看到大约200k的消息/秒或大约20mb/秒,而在原始akka(即没有zeroMQ插件)上,我们可以看到大约10k的消息/秒或略低于1MB/秒。在akka + zeroMQ上尝试会使性能变差。
为了便于远程操作,akka使用Java序列化来进行消息序列化,这不是您在生产环境中通常使用的方法,因为它不是非常快,并且不能很好地处理消息版本控制。
你应该做的是使用kryo或protobuf进行序列化,你应该能够得到更好的数字。
您可以在这里阅读如何,在页面底部也有一些可用的序列化器的链接:http://doc.akka.io/docs/akka/current/scala/serialization.html
下面是我们的发现:
使用我们的客户端服务器模型,我们能够得到大约<3000条消息/秒而不做任何事情,这对我们来说是不可接受的,但我们真的很困惑发生了什么,因为我们无法最大限度地利用cpu。
因此,我们回到akka源代码并在那里找到了一个基准测试示例:
sample.remote.benchmark.Receiver
sample.remote.benchmark.Sender
这两个类使用akka remote将来自同一台机器上的两个jvm的一堆消息发送给它们自己。使用这个基准测试,我们能够在corei7上获得大约10~15k msg/秒,使用大约50%的cpu。我们发现调整分配给netty的分派器和线程会产生影响,但影响不大。用ask代替tell会让它慢一点,但慢不了多少。使用由许多参与者组成的平衡池来发送和接收会使其相当慢。
为了进行比较,我们使用jeromq进行了类似的测试,我们设法在使用100% CPU(相同负载,相同机器)的情况下获得大约100k msg/sec。
我们还攻击了Sender和receiver,使用Akka zeromq扩展将消息直接从一个jvm传输到另一个jvm,而绕过Akka remote。在这个测试中,我们发现我们可以快速发送和接收,大约100k msg/秒,但性能很快就下降了。在进一步的检查中,zeromq线程和akka actor切换不能很好地一起发挥作用。我们也许可以通过更聪明地处理zeromq和akka之间的交互来调整性能,但那时我们决定使用原始zeromq会更好。
结论:如果你关心在线上大量数据的快速序列化,不要使用akka。