最理想的点到点通信库究竟是怎样的?
在本文中,我们讨论一下,一个最理想的点到点通信库应该是什么样?如果现在还没有这样的库,我们何不一起做一个这方面的开源项目?
编程简单,易于满足各种上层应用,包括封装成RPC使用,在OneFlow这样的深度学习框架中使用,甚至被用在HPC和深度学习中常见的集群通信原语中(all-reduce, broadcast等);
高性能:表现为零拷贝、低延时、高吞吐;
底层支持TCP/IP套接字和RDMA传输。
面向消息的编程模型;
非阻塞的接口;
零拷贝;
对小消息和大消息都友好。
int64_t send(void* in_buf, int64_t size);
int64_t recv(void* out_buf, int64_t size);
void send(void* in_buf, int64_t size, Callback done);
void recv(void* out_buf, int64_t size, Callback done);
void send(void* in_buf, int64_t size);
void read(void* out_buf, int64_t size, Callback done);
CommNet 满足 OneFlow 的功能需要两个最重要的抽象,Eager Message 和 RMA Read。目前的实现中,Massage用于传输ActorMsg,RMA Read用于传输regst的实际内容。
Eager Message的设定:
点对点,每个消息对应一个发送端、对应一个接收端
发送端发送一个消息,接收端在未来接收到对应消息
发送端直接向接收端发送消息,无需事先协商
接收端无条件接受消息
发送端可以假设发送一定会成功,接收端未来一定可以收到消息
接收端通过轮询或者注册回调的方式处理消息
有连接或者无连接抽象,无连接抽象中,发送端使用接收端标识作为发送参数,有连接抽象中,发送端需事先与接收端建立连接,并使用连接标识作为发送参数
同一个线程向同一个接收端或者同一个连接发送的不同消息,需保证接收端接收到的顺序与发送的顺序一致
消息本身为固定大小或者动态大小的数据块,无需关心上层协议
一般为处理小块数据而设计
关键指标一般是延迟与吞吐率
Remote Memory Access (RMA) Read的设定:
点对点,每次操作对应一个本地端与远端
本地端发起操作,操作的结果为将远端地址空间里面的一段数据读取掉本地内存空间
远端需要事先生成访问令牌(token),本地端必须通过令牌才能访问远端在生成令牌时注册的地址范围内的数据。操作发起前,本地端和远端需通过其他任何方式交换访问令牌
一次访问本地端可以读取访问令牌对应的范围内的任意范围数据,同一位置的数据可以被读取任意次数
读取过程中,远端不需要参与
本地端通过轮询或者注册回调的方式处理传输完成事件
本地端认为远端内存一直可用
一般为处理大块数据而设计
关键指标一般是带宽/吞吐率