本系列文章为阅读《数据密集型应用系统设计》时的总结
通过本文,你将了解到数据存储与检索的基本原理,对市面上主流的数据库产品有所熟悉,有助于你在工作中选择合适的数据库。当然,通过对这些原理的学习,有助于拓宽思路,解决工作中的问题。
数据结构
最简单的数据库
从一个最简单的数据库实现,我们开始进入数据库的世界
#!/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的位置,并读取。
随着存储数据的增加,很快将会用完磁盘空间,为解决这个问题,当文件超过一定大小时,便打开新的文件写,同时,压缩老文件(相同的key可以合并)
在实际中,还有些问题需要解决
文件格式
采用二进制而不是csv
删除记录
如要删除一条记录,在数据文件中追加一条特殊的删除标记(墓碑),当文件合并时,遇到墓碑,则丢弃删除的key
崩溃恢复
hash map是存储在内存中的,如果系统奔溃重启,那么需要从历史文件中重建hash map,耗时较久,Bitcask采用的方案是,保存hash_map的快照到磁盘中,可以更快地恢复状态。
部分写入
写入中崩溃会导致脏数据,Bitcask通过校验值来保证记录的正确性。
并发控制
一个写线程,多个读线程。
** 追加写而不是覆盖写** 直观上看,覆盖写更加的合理,对于同一个key,只须有一条记录。追加写的优势在于:
- 追加和合并操作均为顺序写,比随机写要快的多。
- 并发和崩溃控制要简单的多,重写崩溃时,可能存在部分新值和旧值混杂的情况
- 合并可以避免文件碎片化的问题。
哈希表索引的局限性
- 哈希表需全部放入内存,如果有大量的键,将会比较麻烦
- 难以区间查询,只能逐个查询区间中的每个键
未完待续。。。