BTree,Masstree也是论文中的开源实现,ART是我们根据论文实现的。
我们分别使用db_bench的fillrandom,readrandom,seekrandom来评估内存索引的性能,通过系统参数控
制不发生SwitchMemTable和Flush,使用32线程压测一个ColumnFamily。db_bench原有的索引键生成方式
是在64位整型后补ASCII字符0,我们修改了索引键的生成方式,使较长的索引键和数据库中复合索引的键模式
接近,而较短的索引键和数据库中整型索引键一致。
实验结果
点查询
改变数据量
我们使用长度为64Bytes的字符串类型的key和128Bytes的value,测试了五种内存索引在不同数据量大小的场
景下的点查询吞吐(200M-10G,对应1million-50million的键值对)。实验结果显示,五种内存索引中In-
memory BTree,Masstree和ART都能达到千万级别的吞吐,其中ART在不同数据量的场景下性能表现都是最
佳的。
从结果中我们观察到,在我们的测试场景下,ART的点查询性能显著地高于其他的树形索引,我们为此深入研究
了ART的实现,并结合测试负载的特点,认为ART性能突出的原因主要有两点:
数据结构自身查找性能的差距。字典树的查找开销是常量级O(k),而搜索树的查找开销是对数级O(LlogN)。
在较为理想的情况下,一个朴素的字典树,每一层对应key中一个位置的字节,考虑每个节点的扇出最高是
256,最少只需要搜索4层即可覆盖超过40亿个key的索引空间,无论是计算开销还是访存开销都很低。
使用自适应的节点格式,并在不同的节点格式中使用不同的查找方式。字典树中不同的节点可能有不同的扇
出,ART共有四种不同的节点格式:Node4、Node16、Node48和Node256,分别存储不同扇出的节点。
采用这样的设计有两个好处:
提高缓存效率。针对扇出较小的节点,如果统一使用包含256个指针的节点,可能会有较多的空闲空间,
如果使用变长的节点形式,内存分配过程中可能会产生大量的内存碎片。采用不同格式的节点,并预分配
固定的空间,可以在节省内存的同时降低写入时内存分配的开销、减少内存碎片。
可以根据不同格式的节点选择最优的查询方式。除了Node256可以直接通过下标找到子节点的指针外,
其他节点的查询都需要额外开销,这里针对不同格式的节点,选择了合适的查询方式。对于Node4,节点
中最多存储4个字符和4个指针,因为数据量小,只需要顺序遍历即可。对于Node16,节点中最多存储16
个字符和16个指针,可以使用SIMD指令集,在几个CPU cycle内并行比较节点包含的所有字符,找出子
节点的指针。对于Node48,节点中使用一个长度256的uint8数组和最多存储48个指针,uint8数组作为
一个hashmap,将字符映射到指针数组中的对应位置。
评论