RACE: One-sided RDMA-conscious Extendible Hashing——论文泛读

TOS 2022 Paper 论文阅读笔记整理

问题

分离式内存是数据中心中一种很有前途的技术,有助于提高资源利用率、故障隔离和弹性。哈希索引已被广泛用于在分布式存储器系统中提供快速查找服务。然而,由于内存池中的计算能力太弱,无法执行复杂的索引请求,传统的哈希索引对于分离式内存来说效率低下。

现有方法局限性

现有的对RDMA搜索友好(RSF)哈希索引包括:FaRM hopscotch哈希[14]、Pilaf cuckoo哈希[33]、DrTM集群哈希[46]。

这些RSF索引通过使用单侧RDMA读从远程内存中获取数据来执行搜索请求,而不涉及远程CPU。但插入、删除和更新(IDU)请求被发送到远程CPU上执行。然而,由于存储器池中的计算能力太弱,因此该机制在新的分解存储器架构中无法工作。

在这些RSF哈希索引中,可以通过使用单侧RDMA写和原子动词对远程数据进行操作,在计算刀片中执行IDU请求。但由于大量的网络往返和并发访问冲突,现有RSF哈希索引中使用单侧RDMA动词执行IDU请求会导致性能显著下降。

挑战

通过单边RDMA执行哈希索引面临以下挑战:

  • 许多远程读取和写入用于处理哈希冲突。为了处理哈希冲突,现有的哈希方案会产生大量的数据移动开销,而每个远程读取或写入都会产生一个RDMA网络往返,显著降低了哈希索引的性能。

  • 远程访问的并发控制和锁争用。为了处理并发访问的冲突,基于锁的技术已广泛用于哈希索引[16,28]。锁对本地哈希索引的开销很低,只有纳秒级延迟。但在分离式的内存场景中使用锁时,必须使用具有微秒级延迟的RDMA原子动词实现,从而导致高开销,并在发生锁争用时增加等待延迟。特别是对于数据移动过多的哈希索引,在移动数据之前会获取多个锁,这加剧了锁争用。

  • 远程调整哈希表的大小。当哈希表已满时,调整大小是不可避免的。传统方法需要将所有键值项从旧的哈希表移动到新的哈希表。可扩展的调整大小[15,35]减少了调整大小过程中移动项目的数量,但需要首先访问哈希表的目录,需要额外进行一次RDMA读取。此外,在调整大小期间,同时访问哈希表是一项挑战。

本文方法

本文提出了RACE哈希,单边RDMA感知的可扩展哈希索引,具有无锁远程并发控制和高效的远程调整大小功能,在分离式内存场景中提供高效的索引服务。

  • 利用可扩展的调整大小方案,来减少由可扩展的调整大小引起的额外RDMA访问,因此RACE哈希表由多个子表和用于索引子表的目录组成。为了减少可扩展调整大小带来的性能损失,将目录缓存在客户端,从而消除了对目录的RDMA访问。同时提供了简单高效的过时读取方案,以保证访问数据的正确性,并允许在调整大小期间执行请求。

  • 子表结构被设计为具有单侧RDMA感知(RAC),实现了所有索引请求(包括搜索、插入、删除和更新)都可以仅使用单侧RDMA谓词来执行,同时在最坏的情况下具有恒定的时间复杂度,从而提供高性能。

  • 为了提高远程并发的性能,利用无锁远程并发控制方案,实现了除插入失败外的所有索引请求都以无锁的方式并发执行。

实验结果表明,在YCSB混合工作负载中,RACE哈希比最先进的分布式内存哈希索引高1.4–13.7倍。

总结

针对分离式内存下的哈希设计,现有方法受限于远程访问的并发控制和锁争用、额外RDMA访问等。本文提出单边RDMA感知的可扩展哈希索引RACE,包括3个关键技术:(1)利用可扩展的调整大小方案,RACE哈希表由多个子表和用于索引子表的目录组成。将目录缓存在客户端,从而消除了对目录的额外RDMA访问。提供了简单高效的过时读取方案,以保证访问数据的正确性,并允许在调整大小期间执行请求。(2)将子表设计为单侧RDMA感知(RAC),实现了所有索引请求(搜索、插入、删除、更新)都可以使用单侧RDMA动词执行,同时在最坏的情况下具有恒定的时间复杂度。(3)利用无锁远程并发控制方案,实现了除插入失败外的所有索引请求都以无锁的方式并发执行。

以下是使用One-Sided Selection算法进行欠抽样的示例代码: ```python from collections import Counter import numpy as np from sklearn.neighbors import NearestNeighbors def one_sided_selection(X, y): """ 使用One-Sided Selection算法进行欠抽样 :param X: 特征矩阵 :param y: 标签数组 :return: 欠抽样后的特征矩阵和标签数组 """ # 查看原始类别分布 print('Original dataset shape %s' % Counter(y)) # 计算每个样本到其k个最近邻样本的平均距离 k = 5 neigh = NearestNeighbors(n_neighbors=k+1) neigh.fit(X) dist, _ = neigh.kneighbors(X) avg_dist = np.mean(dist[:, 1:], axis=1) # 将样本按照标签分成两类 X_pos, X_neg = X[y == 1], X[y == 0] avg_dist_pos, avg_dist_neg = avg_dist[y == 1], avg_dist[y == 0] # 选取与少数类样本距离最近的大多数类样本 idx = np.argsort(avg_dist_pos)[:len(X_pos)] X_resampled = np.concatenate((X_pos, X_neg[idx]), axis=0) y_resampled = np.concatenate((np.ones(len(X_pos)), np.zeros(len(X_pos))), axis=0) # 查看欠抽样后的类别分布 print('Resampled dataset shape %s' % Counter(y_resampled)) return X_resampled, y_resampled ``` 使用示例: ```python from sklearn.datasets import make_classification # 生成一个二分类的不平衡数据集 X, y = make_classification(n_samples=10000, n_features=20, n_informative=10, n_redundant=5, n_classes=2, weights=[0.9, 0.1], random_state=42) # 进行欠抽样 X_resampled, y_resampled = one_sided_selection(X, y) ``` 在上述示例中,我们使用了`sklearn`库中的`make_classification`函数生成一个二分类的不平衡数据集,然后使用`NearestNeighbors`类计算每个样本到其k个最近邻样本的平均距离。我们将样本按照标签分成两类,并选取与少数类样本距离最近的大多数类样本进行欠抽样。最后,我们使用`collections`库中的`Counter`函数来查看原始数据集和欠抽样后的数据集的类别分布。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妙BOOK言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值