数据存储与检索

219 阅读3分钟

本系列文章为阅读《数据密集型应用系统设计》时的总结

通过本文,你将了解到数据存储与检索的基本原理,对市面上主流的数据库产品有所熟悉,有助于你在工作中选择合适的数据库。当然,通过对这些原理的学习,有助于拓宽思路,解决工作中的问题。

数据结构

最简单的数据库

从一个最简单的数据库实现,我们开始进入数据库的世界

#!/bin/bash
db_set() {
    echo "$1,$2" >> database
}
db_get() {
    grep "^$1," database | sed -e "s/^$1,//" | tail -n 1
}

这是一种日志型的数据库,日志是一种仅支持追加更新的数据文件,db_set的性能很好,但是,随着条目的增加,db_get就捉襟见肘了,因为db_get需要遍历所有的数据。

索引

为了高效查找指定的key,需要引入索引,这些索引可以理解为路标,帮助定位所需要的数据。引入索引后,可以减低查找的开销,但是,每次写入时,都需要更新索引,任何索引的引入都会降低写的速度。

哈希索引

以key-value存储为例,哈希索引记录每个key的value在文件中的偏移量,这样可以快速定位到value的位置,并读取。

哈希索引提高查询速度
虽然听起来简单,但这便是Bitcak(Riak的默认存储引擎)的核心原理。

随着存储数据的增加,很快将会用完磁盘空间,为解决这个问题,当文件超过一定大小时,便打开新的文件写,同时,压缩老文件(相同的key可以合并)

在实际中,还有些问题需要解决

文件格式

采用二进制而不是csv

删除记录

如要删除一条记录,在数据文件中追加一条特殊的删除标记(墓碑),当文件合并时,遇到墓碑,则丢弃删除的key

崩溃恢复

hash map是存储在内存中的,如果系统奔溃重启,那么需要从历史文件中重建hash map,耗时较久,Bitcask采用的方案是,保存hash_map的快照到磁盘中,可以更快地恢复状态。

部分写入

写入中崩溃会导致脏数据,Bitcask通过校验值来保证记录的正确性。

并发控制

一个写线程,多个读线程。

** 追加写而不是覆盖写** 直观上看,覆盖写更加的合理,对于同一个key,只须有一条记录。追加写的优势在于:

  1. 追加和合并操作均为顺序写,比随机写要快的多。
  2. 并发和崩溃控制要简单的多,重写崩溃时,可能存在部分新值和旧值混杂的情况
  3. 合并可以避免文件碎片化的问题。

哈希表索引的局限性

  1. 哈希表需全部放入内存,如果有大量的键,将会比较麻烦
  2. 难以区间查询,只能逐个查询区间中的每个键

未完待续。。。