使用ZeroMQ进行进程间通信:传输大型阵列

时间:2016-03-29 04:04:06

标签: json scala zeromq jeromq

我需要在Scala进程(JeroMQ)和C进程(ZeroMQ)之间建立通信。 Scala进程需要发送大型数组(每个阵列1亿个浮点数)。这首先转换为JSON字符串,如下所示,我遇到了内存问题:

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
    at java.lang.StringCoding.encode(StringCoding.java:350)
    at java.lang.String.getBytes(String.java:939)
    at org.zeromq.ZMQ$Socket.send(ZMQ.java:1276)

1亿个浮点数对应762 MB。在我看来,序列化的JSON字符串变得越来越大。如果是,那么传输此大小数据的最佳方法是什么。

3 个答案:

答案 0 :(得分:1)

正如ZeroMQ's FAQ page所示,您可以使用Java(以及Scala)和C中支持的任何数据编组格式。其中有很多(对于某些C支持是第三方,尽管C ++通常不是):协议缓冲区,MsgPack,Avro,Thrift,BSON等。

答案 1 :(得分:1)

大小?不,与运输哲学相关的约束很重要。

ZeroMQ传输协调中存在一个比选择外部数据序列化SER / DES策略更重要的问题。

没有人可以禁止你尝试发送尽可能大的 BLOB ,而JSON装饰的字符串已经向你展示了这种方法的黑暗面,还有其他方法没有这样做的原因。

ZeroMQ是一个强大而强大的工具箱。仍然需要一段时间才能获得必要的洞察力,以实现智能且高性能的代码部署,从而最大限度地利用这个强大的工作马。

功能丰富的内部生态系统“引擎盖下”的副作用之一是隐藏在消息传递概念中的一个不太知名的策略。

可以发送任何合理大小的消息,但不保证交付。 要么完全交付,或者什么都没有,如上所述,没有任何保证。

<强>哎哟?!

,无法保证。

基于这种核心零保证理念,人们应该谨慎地决定步骤和措施,如果你打算尝试在那里移动“Gigabyte BEAST”,那就更多了。

从这个意义上说,它可能会受到真正的 SUT 测试的定量支持,小型消息可能会传输(如果你确实需要移动 {{1 }} -s(参考上面的评论,在OP下),没有其他选择)整个数据量被分割成更小的部分,容易出错的重新组装措施,导致比尝试使用dumb-force并指示代码将 GB 数据转储到实际存在的任何资源上更快,更安全端到端解决方案可用(ZeroMQ的零拷贝原则不能也不会在这些努力中为您节省费用)。

有关另一个隐藏陷阱的详细信息,与未完全零复制实现相关,read Martin SUSTRIK's, co-father of ZeroMQ, remarks on Zero-Copy "till-kernel-boundary-only" ( so, at least double the memory-space allocations to be expected... ).

最好的下一步?

虽然它没有解决你的问题,只有一些 GB -s,但如果你真的想把你的智力投入到分布式处理中,最好的事情就是阅读Pieter HINTJEN的可爱书“Code Connected,Vol.1”

是的,需要一些时间才能产生自己的洞察力,但这会在很多方面提升到另一层次的专业代码设计。 值得的时间。值得努力。

答案 2 :(得分:1)

First things first, there's nothing inherent to json or any other data serialization format that makes it non-viable for large data sets - you just have to make sure that your machine has the necessary resources to process it.

Certain formats might be more memory efficient than others, most likely a binary format is going to suit you better.

However, depending on your circumstances (e.g. if you constantly need updated access to the entire dataset) then user3666197's answer is probably more suited to your scenario.

Allow me to split the difference.

If your use case fits the following parameters:

  1. You need infrequent access to the entire data set
  2. You can deal with long latency times
  3. You cannot increase the resources available at the receiving host
  4. You cannot (or it is prohibitively difficult to) create a continuously updated local data store at the receiving host

... then your best bet is simple splitting of the data set. See how large of a message you can send and parse without running out of resources, give yourself anywhere between a 20-50% buffer (depending on your tolerance), split your data set up into chunks that size, send the chunks and reassemble them. This is working under the assumption that the memory problem is resulting from dealing with both the serialized and unserialized data in memory at the same time during the unserialization process. If that's not true and the unserialized data set is itself too large to fit in memory, then you'll just have to process the data in chunks without reassembling them. If that's the case, I would strongly recommend finding some way to increase your memory resources, because you're living on the edge.