技术主题
mysql的底层是b+树,hbase的底层数据结构是LSM树
一B树
1、B的英文全为Balance(平衡)的缩写,一种多路的平衡搜索树
2、和普通的平衡二叉树不同的是,B树的每个节点可以存储多个数据,而且每个节点不止有两个子节点,最多可以有上千个子节点
3、B树中的每个节点都存放着索引和数据,数据遍布整个树结构,搜索可能在非叶子节点结束,最好的情况是0(1)
4、一般一颗B树的高度在3层左右,3层就可满足百万级别的数据量
二B+树
与B树的区别是
1、叶子节点保存了完整的索引和数据,而非叶子节点只保存索引值,查询的时间固定为log(n)
2、叶子节点中有指向下一个节点的指针,叶子节点类似一个单链表
3、因为叶子节点保存了完整的数据以及指针作为连接,B+树可以增加了区间的访问性,提高了范围查询
4、B+树更适合外部存储,非叶子节点不存储数据,只保存索引
三红黑树
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red节点和黑节点,通过任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,接近平衡
红黑树的性质:
1、每个结点不是红色就是黑色
2、根结点是黑色的
3、如果一个节点是红色的,则它的两个孩子结点是黑色的
4、对于每个结点,从该节点到所有后代结点的简单路径上,均包含相同数目的黑色结点
5、每个叶子结点都是黑色的
四LSM树
LSM树本质是一种存储结构,目前Hbase,LevelDB采用的是LSM树
LSM树的核心特点是利用顺序写来提高写性能,但因为分层(分层指的是分为内存和文件两部分)的设计会稍微降低读性能,但是通过牺牲小部分的读性能换来高性能的写。
1、LSM树的核心思想
LSM树有以下三个重要的组成部分
1)MemTable
MemTable是在内存中的数据结构,用于保存最近更新的数据,会按照key有序地组织这些数据,LSM树对于具体如何组织有序有序地组织数据并没有明确的数据结构定义,例如Hbase使用跳跃表保证内存中key的有序。
数据保存在内存中,断电丢数据,通过WAL(Write-ahead logging预写式日志)保证数据的可靠性。
2)Immutable MemTable
当MemTable达到一定大小后,会转化成Immutable MemTable,是一种中间状态,写操作由新的MemTable处理,在转存过程不阻塞数据的更新操作
3)SSTable(Sorted string table)
有序键值对集合,是LSM树在磁盘中的数据结构,为了加快SSTable的读取,可以通过建立key的索引以及布隆过滤器以及布隆过滤器来加快key的查找
LSM树(Log-Structured-Merge-Tree),将所有的数据插入,修改,删除等操作记录保存在内存中,当此类操作达到一定的数据量后,再批量顺序写入磁盘当中,这与B+树不同,B+树数据的更新会直接在原数据所在处修改对应的值,但是LSM数的数据更新是日志式的,当一条数据更新是直接append一条更新记录完成的。这样设计的目的就是为了顺序写,不断地将Immutable MemTable flush到持久化存储即可。而不用去修改之前的SSTable中的key,保证了顺序写。
因此当MemTable达到一定大小flush到持久化存储变成SSTable后,在不同的SSTable中,可能存在相同key的记录,当然最新的那条记录才是最准确的
带来一些问题:
1)冗余存储,对于某个key,实际上除了最新的那条记录外,其他的记录都是冗余无用的,但是仍然占用了存储空间,因此需要进行Compact操作(合并多个SSTable)来清除冗余的记录
2)读取时需要从最新的倒着查询,直到找到某个key的记录。最坏的情况需要查询完所有的SSTable,这里可以通过前面提到的索引/布隆过滤器来优化查找速度
2、LSM树的核心思想
Compact操作十分关键,否则SSTable数量会不断膨胀,在Compact策略上,两种基本策略:size-tiered和leveled。
三个概念
1)读放大:读取数据时实际读取的数据量大于真正的数据量。例如在LSM树中需要先在MemTable查看当前的key是否存在,不存在继续从SSTable中寻找。
2)写放大:写入数据时实际写入的数据量大于真正的数据量,在LSM树中写入时可能触发Compact操作,导致实际写入的数据量远大于该key的数据量
3)空间放大:数据实际占用的磁盘空间比数据的真正大小更多。上面提到的冗余存储,对于一个key来说,只有最新的那条记录是有效的,而之前的记录都是可以被回收的
1)size-tiered策略
size-tiered策略保证每层SSTable的大小相近,同时限制每一层SSTable为N,当每层的SSTable达到N后,则触发Compact操作合并这些SSTable,将合并后的结果写入到下一层成为一个更大的sstable
2)leveled策略
leveled策略也是采用分层的思想,每一层限制总文件的大小
但是跟size-tiered策略不同的是,leveled会将每一层切分成多个相近的SSTable。这些SSTable是这一层是全局有序的,意味着一个key在每一层至多只有1条记录,不存在冗余记录。之所以可以保证全局有序,是因为合并策略和size-tiered不同
leveled策略相较于size-tiered策略来说,每层内key是不会重复的,即使是最坏的情况,除开最底层外,其余层都是重复key,按照相邻层大小比例为10来算,冗余占比也很小。因此空间放大问题得到缓解。但是写放大问题会更加突出。举一个最坏场景,如果LevelN层某个SSTable的key的范围跨度非常大,覆盖了LevelN+1层所有key的范围,那么进行Compact时将涉及LevelN+1层的全部数据。