顺序写
每个 fd 都关联一个 当前的 offset,每次写入 offset 都会更新。
顺序写入就是所有的写都是写当前的 offset,
随机写就是 offset 会从[0~max]里随机取值写,这些随机的 offset 最后都可能会导致磁头的移动。
那么应用层面什么样的数据写入方式能保证磁盘层面是顺序写呢,简单来说就是,
- update-in-place 原地更新
- append-only btree/copy on write tree 顺序文件末尾追加
LSM - tree
关系数据库和键值数据库存储引擎对比
传统的关系数据库存储采用 B+ 树,数据被按照特定方式放置,能大幅度提升读性能,但写性能下降。
而 no-sql 一般 将整个磁盘就看做事一个日志,在日志中存放永久性数据及其索引,每次都添加到日志末尾。
将数据添加到文件,因为完全顺序,所以写操作性能优秀。但从日志文件读一些数据将比写操作消耗更多的时间,需要倒序扫描直到找到所需内容。相当于牺牲了部分读性能换来了写性能的提升。
深入理解 Log-Structured Merge-Tree(LSM-tree)
对比上面,其实就是 将一个大的查找结构(B+ tree),变换为 将写操作顺序地保存到一些相似的有序文件(sstable/HBASE) 中。每个文件包含了短时间段内的一些改动。因为文件有序,后续查找也会很快。所以这种方式 文件不可修改,永远不会更新,新操作只会写到新文件中,通过周期性的合并来减少文件的个数。
总结一下就是:1. 让操作顺序化,不断追加而不是修改(写性能高);延迟更新,批量写入硬盘。
简单对比读写:写操作被分批处理,只写到顺序块上;读操作有可能访问大量的文件(散乱的读)。
写操作步骤:
- 发出写操作
- 内存缓存(memtable)中使用树结构来保持key有序
- WAL写磁盘(防丢/恢复)
- 达到一定规模刷到磁盘上一个新文件里
- 越多的数据到存储系统中,就会有越多的不可修改的顺序sstable文件被创建(他们代表了小的、按时间顺序的修改)
- 系统周期性发起 compaction,合并文件并删除重复冗余,减少文件个数(因为sstable 是有序结构,可以才用归并排序的思想,所以合并非常高效)
读操作步骤:
- 发出读操作
- 先检查内存数据(memtable)
- 没有这个key
- 逆序一个个检查 sstable 直到找到
对比读写操作:
因为需要遍历所有sstable,当数量过多性能就会下降。一方面系统周期性合并sstable、用 cache 等技术;另一方面使用布隆过滤器来避免大量的读文件操作。
网友评论