LB+Tree

VLDB论文阅读笔记

可直接看LB+-Tree部分。

论文标题

《LB+-Trees Optimizing Persistent Index Performance on 3DXpoint memory》

http://www.vldb.org/pvldb/vol13/p1078-liu.pdf

Minimizes the number of NVM Line writes and performs Logless insertions.

简介

3DXpoint特性:

  • 使用 clwb,sfence等指令,将数据从cache拷到3DXpoint,会大大降低写性能。
  • 3DXPoint内存内部数据存取粒度是256B。等等

论文核心思想

在一个cache line中,修改的字数对3DXpoint的写性能没有影响。提出持久性索引LB+-tree来提高一次写入的字数,减少写NVM line的次数。提升LB+-tree 插入性能的方法:

  1. Entry moving。在叶子节点的第一行创建更多空槽。

    • 考虑插入新索引项,更新叶子节点的头。
    • best case:头部所在的行(即第一行)有空槽,则插入和更新需一次NVM行写入。
    • 另一情况:第一行已满,叶子节点的另一行找到空槽,更新头、写新项,需两次行写入。
    • 策略:将尽可能多的项从第一行移动到要写入的行,以产生更多空槽。
  2. Logless node split。使用原子写(NAW)来减少日志开销(先前的基于NVM优化的B+树使用日志来支持节点分割)。
  3. Distributed headers。使得(1)(2)对multi-256B节点非常有效。

    • 对于multi-256B节点,先前的做法是将元数据信息放在在节点的头部。(元数据信息包括:标记空/满项的bitmap、加速码搜索的指纹)。但是当节点大小增大时,第一行的槽项数会减少。该论文:在节点中,每256个block分配一个头。
  4. 后面证明
  • 在断电和进程崩溃的情况下,算法能保证数据一致性。
  • 微基准测试。插入操作,对比传统平衡树,NVM行写入次数的减少。
  • 系统实验:X-engine,Memcached。

背景

3DXpoint两种模式

  • 内存模式。DRAM作为3DXpoint的cache,主存容量和3DXPoint相同,对不写内存的应用友好。缺点:不支持持久性数据结构;更长的加载数据时间,需先访DRAM,缺失再访3DXpoint。
  • app-direct模式。DRAM、3DXPoint与CPU直连,使用PMDK(持久性内存开发工具)来安装文件系统。本文关注该模式。

论文三发现

  • 在一个cache行中,修改的字数对3DXpoint的写性能没有影响。先前数据比较写:读硬件原始数据,比较新的,仅写入修改的bit,则写延迟会比写整行要小。作者认为,目前的3DXPoint没有对数据比较写进行优化。如其中一款Intel的,数据有加密,修改一个bit会改变多个bit。
  • 3DXPoint内存内部数据存取粒度是256B。cache line是64个字节。读操作:3DXPoint读256个字节,给cache 64个字节;写操作:3DXpoint读256个字节,修改64个字节,再写256个字节。
  • 使用量低于1/8时,应用程序工作集变大,3DXPoint性能降低。应用程序访问的数据大于或等于3DXPoint容量的1/8,内存性能稳定。(因此实验需至少填满1/8)

数据一致性策略

一致性操作:缓存行flush指令(如clwb)和内存栅栏指令(如sfence),保证脏数据写回NVM。开销大。

NVM保证数据一致性的策略:logging , shadowing , PMwCAS , NVM atomic writes (NAW) 。

  • logging:write-ahead logging。故障恢复,根据日志。
  • shadowing:NVM中新分配空间,拷贝要修改的数据结构,修改拷贝,再使用NAW切换。注意点:须仅有一个指针指向要修改的数据(B+树满足)。故障恢复,指向新或旧的?
  • PMwCAS:兼顾数据一致性和无锁操作。

前三种方法,也许比直接修改持久性数据结构开销大得多。

NAW

8B写,后接clwb(persist),sfence。8B写是原子的。

LB+Tree_第1张图片

证明一致性。……

对于某些数据结构,如B+树叶子节点,可以采用多个中间可恢复状态、多个NAW来保证一致性。

LB+Tree_第2张图片

优化的NVM B+树

  • 基于缓存优化,缓存行对齐。
  • 尽可能减少NVM写次数。如使用bitmap,叶子节点不排序,可以减少移动的次数。
  • 使用NAW来保证数据一致性。如WB+树,叶子结点包含间接数组,以辅助在无序叶子结点的排序。 这和bitmap同,在插入时都需要NAW两次,是可恢复的。
  • 非叶结点放入DRAM中。如,Oukid 的选择一致性策略:将FP-tree的非叶结点放入DRAM,叶子结点放NVM(若出故障,可从叶子结点中恢复非叶部分);搜索码1字节指纹,SIMD加速叶子搜索。
  • 并发的B+树。
  • Bztree,使用PMwCAS,实现无锁数据一致性。

对3DXPoint设计原则

  • 减少NVM行写入的次数,而非字写入次数。
  • 叶子结点大小256B的倍数.
  • 完全不使用日志,用NAW实现结点分割。

LB+-Tree

结构

仿照FP-tree。

LB+Tree_第3张图片

  • 非叶结点放DRAM,叶子结点放3DXPoint。
  • lock位:并发控制。 alt:指明可选的兄弟结点。
  • 指纹:加速搜索。hash(key):计算出1字节的指纹,使用128bit的SIMD。
  • alt:选择当前正在使用的指针
  • sibling ptr, 各8B。有效的sibling ptr指向当前叶子结点的右兄弟指针。如果当前叶子结点为NULL,则为NULL。为什么要这样设计?

并发控制

仿照FP-tree,结合HTM(硬件事务存储)和lock 位来实现并发控制。本实验用原语实现HTM。

注意,缓存行flush指令不能兼容HTM,因为HTM在事务提交前,需要在cache中保持修改的cache line。然而,在3DXPoint中,缓存行flush指令是必须的。用lock bit 来解决。

index操作到达叶子,检查lock。若lock=1,说明已有index 写操作锁住结点了,废止事务。若lock=0,继续,读则读,写则先lock=1,提交事务,再真正写(事务外写,使用clwb)。

搜索

LB+Tree_第4张图片

  • 3,5,11并发控制
  • xbegin(), xabort(), and xend() 分别为开始、废止、提交事务。成功开始,返沪_XBEGIN_STARTED,若因xbort()或硬件冲突,则继续执行xbegin()
  • 搜非叶结点,查叶子结点
  • 使用SIMD 匹配指纹,得到候选集
  • 检查slot是否合法,key是否等

插入:减少line writes

LB+Tree_第5张图片

与header同line,需写一次line;否则,需写两次。

将数据从line0移到其他line时,修改header的bitmap和指纹:16B dword。

LB+Tree_第6张图片

证:256结点 LB+-tree,若叶子结点有空槽,插入操作能保证叶子结点的数据一致性。

(只在lineid行找空槽)。

结点分割

LB+Tree_第7张图片

  • 分配新结点,将14个索引项中最大的7个拷到新结点的最后两个line。
  • 交换兄弟结点,以在不改变当前有效 指针的情况下,插入新叶子结点? (新的兄弟1指向旧的有效的兄弟结点的指向,旧的alt改变,有效的指向新叶子结点)
  • 情况1:插入到新叶子结点 (17-18:leaf的bitmap变了)
  • 情况2:插入到旧叶子结点。20-23:先persist新叶和兄弟指针,插入项

(结点分割之后旧结点没有马上将line0的移动到line2, line3)

一致性证明。

删除

查找,用NAW置空bitmap对应位。

一致性证明。

故障恢复

一致性已证明。

出故障,扫描叶子,重建非叶。

multi-256B结点

原因分析

使用大结点的原因:非叶部分占更少DRAM;内存带宽、内存控制器队列大小可能大于256B。后面4.2部分,发现,512B的叶子结点性能更好。

使用分布式头部的原因:

若使用集中式(centralized)头,一个头(包含 ​-bit map, ​ x1B指纹, lock,alt位),两个兄弟节点,​ x 16 B的数据项。

则当结点大小为512B,768B,1024B时,头部大小分别为32B, 49B, 66B,则Line0 剩余的数据项数目分别为2,0,0。由于我们的目的是减少NVM写的次数,这种方法效率低。

使用分布式头部。

LB+Tree_第8张图片

使用H1的原因:若无,则结点分割时,需更新分布式头部,一个NAW无法处理多个头部写,且可能要求日志记录。

因此在2~m 块的末尾引入可选头部。复用alt,用来表示前后哪个头是有效的。??

写无效的头,再用一个NAW来修改第一个头部,切换兄弟结点和2~m 块的头。该过程不需写日志。?

操作

  • 搜索:指纹比较,bitmap检查,key比较。
  • 删除:直接更新第一个头部
  • 插入操作:寻找第一个非满block,进行插入。若所有block均满,进行节点分割。
  • 节点分割:分配新节点;把一半的项拷到新节点;修改替代兄弟节点和替代头部;使用一个NAW去更新第一个block的头部;切换alt

一致性证明。

代价分析

LB+Tree_第9张图片

实验

对比B+tree,WB+tree,FP-tree。LB+Tree基于后两者提出,但这两者没有entry moving,需要写日志,且采用集中式头部。LB+-Tree则通过使用替代兄弟指针和替代头部实现无日志写。FP-Tree和LB+Tree使用指纹数组支持SIMD查找,WB+tree 则使用间接数组来支持二分查找。

micro-benchmark

X-Engine和 Memcached

其他

可能可以进挖的点?

  • 根据3DXPoint的endurance ,进行wear-leveling。(本文2.2末尾)
  • 第三发现的原因。作者解释:可能为3DXPoint内存模块的缓存机制。

没看懂的:

  • 论文提到的PMwCAS。
  • 论文的并发控制?? 怪怪的。
  • 看看插入的代码吧
  • 为什么要设计两个兄弟指针? 怎么实现无日志写的?
  • 插入、分割的代码为什么要用dword
  • 插入的代码为什么不需要clwb leaf[to]所在的line
  • muti-256B,节点分割没看懂,具体的代码?(是将每个block的一半分给另一个节点吗?将整个block复制给新节点更高效吧?但是这好像和代价分析部分矛盾了?)
  • 代价分析。LB+ 的情况 leaf n 的计算, worst case,为什么有3个插入需要写2次,其他都是1 次?
  • 插入 worst case 不考虑数据迁移的开销吗---考虑的哦
  • 代价分析。传统的leafn 为什么要规定新的节点是填充在前面而不是后面的?
  • multi-256B的情况,代价分析? 对照的是集中式头部 迁移写 还是 分布式头部不迁移写?看说明,好像是前者?但是计算 又像是后者。
  • skip-list 跳表是什么?

LB+Tree_第10张图片

你可能感兴趣的:(数据库,内存数据库)