Plasma Prototype: Arch and API
Code analysis on the prototypical implementation of Plasma, a distributed in-memory object store.
Redis, Plasma and Lightening
Danyang Zhuo, Kaiyuan Zhang, Zhuohan Li, Siyuan Zhuang, Stephanie Wang, Ang Chen, and Ion Stoica. 2021. Rearchitecting in-memory object stores for low latency. Proc. VLDB Endow. 15, 3 (November 2021), 555–568. DOI:https://doi.org/10.14778/3494124.3494138
Plasma Arch and API
Redis 和 Plasma 架构相似,Server进程是其中的核心。Server接受(多个)Client进程的请求,在处理它们的过程中又向更底层的Store进程发送请求。这种架构实现简单,而且相比Lightening的共享内存方案是“直观”的。以plasma来说:
- Client定义上层应用可用的API:
- 连接/断开:plasma_connect/plasma_disconnect
- 查询本地对象:plasma_contains
- 写/读/删对象:plasma_create(plasma_seal)/plasma_get/plasma_delete
- 拉取远端对象:plasma_fetch(跨节点通信)
- Server是实现跨节点fetch的地方:
- process_fetch_requests(这里会发生一次redis,即GCS查询) -> process_fetch_request
- process_transfer_request
- process_data_request:这里接收方会调用plasma_create,然后从Socket中拷贝数据进去
- process_seal:封存对象,这里会发生一次redis更新
- Store是实现本地Create/get的地方:我关注进程如何共享内存实现Create和Get?
plasma_fetch的通信机制如图
这样Client API的操作流程就明确了:
- plasma_contains 查询本地对象,成功后可以plasma_get
- plasma_create 进行本地创建操作,填入数据后调用plasma_seal。seal会更新redis的元数据,使得其他Client可以看到对象,并且调用fetch
- plasma_fetch 获取一个远端的对象。
这里有一个问题,plasma似乎需要对象在集群中一定是存在的,因为fetch操作需要ID,fetch一个不存在的ID程序会崩溃。并且ID是用户程序(例如Ray)提供的,而不是Plasma生成的。 因此对象管理的逻辑并不实现在这一层。
共享内存?
简单了解了多进程如何实现共享内存。其实是基于mmap这一神器,围绕着一个file descriptor(再一次感慨一切皆文件:Socket, etc.)
- 首先要有一个(内存)文件,大小和内存buffer相同。描述符为fd,然后进程1调用mmap将一段虚拟内存空间和fd绑定,返回地址指针。
- 使用ipc(Unix Domain Socket)将这个fd交给另一个进程2
- 进程2再次以fd使用mmap,返回的地址指针。
代码中,由Store进程维护fd表。这样plasma_get实际上就是在一个Client进程中,用recv_fd调用从Store拿到fd,然后以该fd执行了步骤3,和Store共享了虚拟内存空间。
Leave a comment