提高 Akka 远程吞吐量
Improving Akka Remote Throughput
我们正在考虑使用 Akka 进行客户端服务器通信,并尝试对数据传输进行基准测试。目前我们正在尝试发送一百万条消息,其中每条消息都是一个带有 8 个字符串字段的案例 class。
此时我们正在努力获得可接受的性能。我们在客户端和服务器上看到大约 600KB/s 的传输速率和空闲 CPU,所以出现了问题。可能是我们的netty配置问题。
这是我们的 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 核心 i7 上(即在 java 中重新实现的 zeroMQ - 所以仍然不是最快的)我们始终看到大约 200k msgs/sec 或大约 20 MB/sec 而在原始 akka(即没有 zeroMQ 插件)我们看到了大约 10k msgs/sec 或略低于 1MB/sec。尝试使用 akka + zeroMQ 会使性能变差。
好的,这就是我们的发现:
使用我们的客户端服务器模型,我们能够在不做任何事情的情况下获得大约 < 3000 msg/sec,这对我们来说是不能接受的,但我们真的对发生的事情感到困惑,因为我们无法最大化 cpu。
因此我们回到 akka 源代码并在那里找到了一个基准测试示例:
sample.remote.benchmark.Receiver
sample.remote.benchmark.Sender
这是两个 类,它们使用 akka remote 从同一台机器上的两个 jvm 向自己发送一堆消息。使用这个基准,我们能够在 24g 的 corei7 上获得大约 10~15k msg/sec,使用大约 50% cpu。我们发现调整分配给 netty 的调度程序和线程会有所不同,但影响很小。使用 asks 而不是 tells 会使它慢一点,但不会慢很多。使用由许多参与者组成的平衡池来发送和接收会使它变得相当慢。
为了比较,我们使用 jeromq 进行了类似的测试,我们设法使用 100% CPU(相同的负载,相同的机器)获得了大约 100k msg/sec。
我们还破解了发送方和接收方,以使用 Akka zeromq 扩展将消息直接从一个 jvm 传输到另一个,同时绕过 akka 远程。在此测试中,我们发现我们可以快速发送和接收开始,大约 100k msg/sec,但性能很快下降。在进一步检查中,zeromq 线程和 akka actor 切换不能很好地协同工作。我们可能可以通过更智能地了解 zeromq 和 akka 之间的交互方式来稍微调整性能,但那时我们决定使用原始 zeromq 会更好。
结论:如果您关心通过线路快速序列化大量数据,请不要使用 akka。
为了更容易开始远程处理,akka 使用 Java 序列化来进行消息序列化,这不是您通常在生产中使用的方法,因为它不是很快并且不能很好地处理消息版本控制。
你应该做的是使用 kryo 或 protobuf 进行序列化,你应该能够得到更好的数字。
您可以在此处了解操作方法,页面底部还有一些指向可用序列化程序的链接:http://doc.akka.io/docs/akka/current/scala/serialization.html
我们正在考虑使用 Akka 进行客户端服务器通信,并尝试对数据传输进行基准测试。目前我们正在尝试发送一百万条消息,其中每条消息都是一个带有 8 个字符串字段的案例 class。
此时我们正在努力获得可接受的性能。我们在客户端和服务器上看到大约 600KB/s 的传输速率和空闲 CPU,所以出现了问题。可能是我们的netty配置问题。
这是我们的 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 核心 i7 上(即在 java 中重新实现的 zeroMQ - 所以仍然不是最快的)我们始终看到大约 200k msgs/sec 或大约 20 MB/sec 而在原始 akka(即没有 zeroMQ 插件)我们看到了大约 10k msgs/sec 或略低于 1MB/sec。尝试使用 akka + zeroMQ 会使性能变差。
好的,这就是我们的发现:
使用我们的客户端服务器模型,我们能够在不做任何事情的情况下获得大约 < 3000 msg/sec,这对我们来说是不能接受的,但我们真的对发生的事情感到困惑,因为我们无法最大化 cpu。
因此我们回到 akka 源代码并在那里找到了一个基准测试示例:
sample.remote.benchmark.Receiver
sample.remote.benchmark.Sender
这是两个 类,它们使用 akka remote 从同一台机器上的两个 jvm 向自己发送一堆消息。使用这个基准,我们能够在 24g 的 corei7 上获得大约 10~15k msg/sec,使用大约 50% cpu。我们发现调整分配给 netty 的调度程序和线程会有所不同,但影响很小。使用 asks 而不是 tells 会使它慢一点,但不会慢很多。使用由许多参与者组成的平衡池来发送和接收会使它变得相当慢。
为了比较,我们使用 jeromq 进行了类似的测试,我们设法使用 100% CPU(相同的负载,相同的机器)获得了大约 100k msg/sec。
我们还破解了发送方和接收方,以使用 Akka zeromq 扩展将消息直接从一个 jvm 传输到另一个,同时绕过 akka 远程。在此测试中,我们发现我们可以快速发送和接收开始,大约 100k msg/sec,但性能很快下降。在进一步检查中,zeromq 线程和 akka actor 切换不能很好地协同工作。我们可能可以通过更智能地了解 zeromq 和 akka 之间的交互方式来稍微调整性能,但那时我们决定使用原始 zeromq 会更好。
结论:如果您关心通过线路快速序列化大量数据,请不要使用 akka。
为了更容易开始远程处理,akka 使用 Java 序列化来进行消息序列化,这不是您通常在生产中使用的方法,因为它不是很快并且不能很好地处理消息版本控制。
你应该做的是使用 kryo 或 protobuf 进行序列化,你应该能够得到更好的数字。
您可以在此处了解操作方法,页面底部还有一些指向可用序列化程序的链接:http://doc.akka.io/docs/akka/current/scala/serialization.html