序列化可变状态并通过网络以近乎零拷贝的方式异步发送(Cap'n Proto + ZeroMQ)
Serializing mutable state and sending it asynchronously over the network with nearly-zero-copy (Cap'n Proto + ZeroMQ)
我有一个应用程序,我想通过网络将其可变状态的一部分发送到另一台机器(将有这些机器的集群)对其进行一些CPU密集型计算并返回结果。就像异步 RPC 一样。在程序执行期间,此类调用会发生多次,因此我想使开销尽可能小,例如尽量减少数据的冗余副本的数量。数据的大小从几十字节到几百KB不等,甚至可能只有几MB。它的结构相对复杂,它由一组对象树组成,但叶子只包含基元类型,内部节点包含最少的元数据。
我正在考虑使用 Cap'n Proto 进行序列化(不过,在这种情况下,我必须为我的数据创建一个冗余模型),以及用于传输的 ZeroMQ。在客户端/主应用程序端,我想使用 azmq,因为我需要 Boost:Asio 的功能(即协程/光纤支持)。语言是C++。
用一个非常粗略的草图总结:
RelativelyComplexState data;
CapnProtoRequest cp_req = buildRequest(data); // traverses my data, creates C'n P object
azmq_socket.async_send(boost::asio::buffer(cp_req, cp_req.size)); //azmq always copies the buffer? Not good.
// do other stuff while request is being processed remotely
// get notification from azmq/Boost:Asio when reply has arrived
azmq::message msg();
azmq_socket.async_receive(some_message_handler?); // get all the data into msg
CapnProtoResponse cp_resp = parseResponse(msg.cbuffer()); // interpret bytes as C'n P object, hopefully no copy
RelativelySimpleResult result = deserialize(cp_resp);
这是可行的,还是有更好的方法?在这种情况下,无架构序列化方法(即 Boost::Serialization)是否会使我的生活更轻松和/或应用程序更高效?
另外,使用 ZeroMQ/azmq 发送和接收 Cap'n Proto 对象的最佳方式是什么,避免不必要的副本?通过查看 azmq 的源代码,似乎对于发送,azmq 总是复制缓冲区内容。更微妙的问题是什么(细分/框架等)?我不熟悉这些库,也没有找到任何解释或好的例子。
谢谢!
我对 ZeroMQ 的接口了解不多,但我可以就如何最小化 Cap'n Proto 的副本提供建议。
在发送端,使用 capnp::MessageBuilder::getSegmentsForOutput()
( capnp/message.h
) 获取指向消息内容的直接指针,而无需复制。这为您提供了一个字节数组数组(实际上是单词,但您可以将它们转换为字节)。您需要以某种方式将这些提供给 ZeroMQ,而无需复制它们。您需要确保保留段之间的边界 - 目标是在接收端提出完全相同的数组数组。也许 ZeroMQ 明确支持多段消息,可以为您记住分段边界;如果没有,您需要在邮件前面加上细分大小表。
在接收端,一旦你重建了你的段数组,构造一个capnp::SegmentArrayMessageReader
(capnp/message.h
)并将数组传递给构造函数。这将使用基础数据而不复制。(请注意,您需要确保数据在 64 位边界上对齐。我不确定 ZeroMQ 是否保证这一点。
请注意,如果您的客户端和服务器都C++,您可能需要考虑使用 Cap'n Proto 自己的 RPC 协议,该协议更易于设置,并且已经避免了所有不必要的副本。但是,将 Cap'n Proto 的事件循环与 boost::asio
集成目前并非易事。这是可能的 - 例如,您可以查看将Cap'n Proto与libuv的事件循环集成的node-capnp - 但可能比您想要做的要多。
(披露:我是Cap'n Proto的作者。
- zeromq 在 I/O 线程中引发异常
- 如何在 Fedora 上为 C++ 包含 zeromq 标头?
- 如何使用ZeroMQ为协议缓冲区编写自己的RPC实现
- 如何在 MFC 应用程序中启动 ZeroMQ 线程?
- ZeroMQ:如何使用 C < C11 使用多个发布服务器和单个客户端
- ZeroMQ 发布-订阅通信:SUB 不接收任何内容
- ZeroMQ 在使用 std::thread 创建工作线程时崩溃
- 在 Cap'n Proto RPC 服务器中定期运行函数
- ZeroMQ:如何使用inproc减少多线程通信延迟
- ZeroMq:打开的文件太多.在同一对象上连续增长的fd使用数
- 将Socket_t指针传递给ZeroMQ发送函数
- ZeroMQ :如何将 Poller 中使用的pollitem_t项投射回 ZeroMQ 套接字?
- 如何监控ZeroMQ服务器是否存在
- 如何在C++中使用ZeroMQ通信多个映像
- ZeroMQ SUB 从不接收消息
- ZeroMQ (cppzmq) 订阅者,过滤器以相同的字符串开头
- ZeroMQ(cppzmq)订阅者跳过第一条消息
- 实时线程中的 ZeroMQ inproc PubSub send() 调用会导致严重的阻塞吗?
- 与处理 ZeroMQ 的永久线程与 Qt 通信
- 序列化可变状态并通过网络以近乎零拷贝的方式异步发送(Cap'n Proto + ZeroMQ)