LearningCache: 面向分离式内存的学习型索引写扩展机制

项目简介

本项目基于RDMA高性能网络构建的分离式内存架构,为学习型索引构建高效的写扩展方式。

传统的学习型索引写扩展方式主要分为:

  • Delta-Tree机制:以额外的增量树作为写扩展数据结构
  • Sparse-Node机制:以更大的数据节点产生额外数据间隙来吸收插入

我们认为Delta-Tree机制适合并发,但是性能受到Tree结构O(logk)搜索复杂度限制,而Sparse-Node则由于粗粒度的并发域而难以做多线程写扩展,但是由于模型预测而具备高性能。

为此我们提出了一种新的写扩展数据结构,我们观察到Delta-Tree的方式忽视了先前训练得到的数据分布情况。我们复用先前模型学到的数据分布,提出了Model-Based Delta-Buffer,并且采用核函数映射的方式修正数据分布误差,从而使得无论是静态索引结构还是吸收插入的写扩展数据结构的读写复杂度都为O(1)

其他项目优化

  • 异步重训练解耦合机制:我们采用多版本机制,存储节点重训练后构建新数据节点并利用RPC通知各个计算节点;此后,发生重训练的区域,写操作将发生在新数据节点上,而读操作将通过RDMA Doorbell Baching批量读取新旧数据节点上的键值对;从而将模型重训练移出插入操作的关键路径,有效降低系统尾延迟

  • 本地锁表和远程锁表机制:采用先前RDMA的相关优化研究,设计分层锁表机制,在存储节点构建全局锁表,在计算节点缓存局部锁表,从而将对同一位置的锁的远端内存访问改为本地内存访问,减少无效的远端内存访问次数;写吞吐提高3.85倍

  • 本地锁移交机制:基于上述分层锁表,设计了移交机制,本地线程对同一锁的访问冲突将被加入与此锁关联的等待队列,并在加锁线程操作完成后移交锁,从而节约了重复的释放锁和加锁过程;写吞吐进一步提高2.94倍

  • 两级分配器:针对计算节点与存储节点算力不匹配的特点,在存储节点上申请并向RNIC注册大内存,并进行粗粒度切块划分;全局内存分配器主要进行粗粒度内存分配;计算节点的本地内存分配器拿到后进行细粒度内存分配与管理,类似Slab分配器。有效降低内存管理开销

项目运行

首先需要一台服务器运行memcached,作为系统内各个计算节点/存储节点进行带外RDMA建链的中间服务

每次运行都需要清空memcached服务器内的各个节点的RDMA交互所需的元数据

$ mkdir build && cd build 
$ cp ../script/restartMemc.sh .
$ bash ./restartMemc.sh

其后进行编译运行。其中,充当存储节点的服务器运行:

$ cmake ..
$ ./Memoryserver 1 1 100 12 0

五个参数依次为,本次运行集群内的计算节点/存储节点数量,读操作比例,运行的线程数,以及是否存在scan

计算节点服务器运行

$ cmake ..
$ ./benchmark 1 1 100 12 0

各个参数意义同上

其他细节

1.需要确认本机RNIC的端口,可以采用 ibstatus 查看 然后修改:

bool createContext(RdmaContext *context, uint8_t port = 1, int gidIndex = 0,
uint8_t devIndex = 0);

2.修改CMakeLists.txt里相关库路径 Boost相关库【因为实验室服务器共享所以设置了自己的库路径】

# 设置Boost的路径
set(BOOST_ROOT "/home/byli/boost_new")
set(Boost_INCLUDE_DIR "${BOOST_ROOT}/include")
set(Boost_LIBRARY_DIR "${BOOST_ROOT}/lib")
其他相关库路径【如果不在默认路径中的话】, 这里可以查看所需的动态库有哪些,对应配置
set(LINKS_FLAGS "-L${Boost_LIBRARY_DIR} -Wl,-rpath,${Boost_LIBRARY_DIR} -lboost_system -lboost_coroutine -lcityhash -lpthread -libverbs -lmemcached")