Bitcask

Bitcask是一个高性能的键值存储系统,设计之初的目的是提供高写入吞吐量和高效读取性能。采用了日志化结构哈希表(Log-Structured Hash Table),核心是写前日志(WAL)、内存哈希表和定期merge.

具体细节均在官方的设计论文 Bitcask Design Paper 中可以查看。

官方论文中提到的bitcask应该具备的特性

  • low latency per item read or written
  • high throughput, especially when writing an incoming stream of random items
  • ability to handle datasets much larger than RAM w/o degradation
  • crash friendliness, both in terms of fast recovery and not losing data
  • ease of backup and restore
  • a relatively simple, understandable (and thus supportable) code structure and data format
  • predictable behavior under heavy access load or large volume
  • a license that allowed for easy default use in Riak

目前已经有优秀的开源实现:

Bitcask 核心

  • 目录结构(bitcask):作为一个目录,存储数据文件,仅允许一个进程同时写入
  • 数据文件(datafile):
    • activefile: 当前用于写入的文件,达到阈值(1GB)时关闭,变成仅读文件
    • readonlyfile: 仅读文件,存储旧数据条目
    • dataentry: 写入数据文件的数据条目 => { crc | tstamp | key_sz | value_sz | key | value }
  • 内存结构(keydir): 映射键值到数据文件中的位置,每次写入时原子更新
    • index: [key] -> { file_id | value_sz | value_pos | tstamp }
  • 合并(merge): 定期或者主动触发合并操作,遍历不可变文件,创建新的包含最新现有键的数据文件,同时生成提示文件(hint)
  • 提示文件(hint): 包含数据文件中值的位置和大小信息,即保存keydir,加速启动流程
  • 恢复崩溃(recover): 由于数据文件的不可变且作为提交日志,恢复简单,扫描提示文件进行恢复

在bitcask论文中提到,允许处理比内存大得多的数据集,且不显著降低性能,是因为其采用了将键和元数据存储在内存中,而将数据值存储在磁盘上,通过键值分离的设计,使其能够处理比内存大得多的数据集。但是因此bitcask将所有的键存储在内存中,这可能在键数量极多的时候成为瓶颈。