高分好书
什么是「数据密集型应用系统」?
当数据(数据量、数据复杂度、数据变化速度)是一个应用的主要挑战,那么可以把这个应用称为数据密集型的。与之相对的是计算密集型——处理器速度是主要瓶颈。
其实我们平时遇到的大部分系统都是数据密集型的——应用代码访问内存、硬盘、数据库、消息队列中的数据,经过业务逻辑处理,再返回给用户。
查询类型
Online analytical processing和Online analytical processing。
查询类型主要分为两大类:
引擎类型 |
请求数量 |
数据量 |
瓶颈 |
存储格式 |
用户 |
场景举例 |
产品举例 |
OLTP |
相对频繁,侧重在线交易 |
总体和单次查询都相对较小 |
Disk Seek |
多用行存 |
比较普遍,一般应用用的比较多 |
银行交易 |
MySQL |
OLAP |
相对较少,侧重离线分析 |
总体和单次查询都相对巨大 |
Disk Bandwidth |
列存逐渐流行 |
多为商业用户 |
商业分析 |
ClickHouse |
其中,OLTP 侧,常用的存储引擎又有两种流派:
流派 |
主要特点 |
基本思想 |
代表 |
log-structured 流 |
只允许追加,所有修改都表现为文件的追加和文件整体增删 |
变随机写为顺序写 |
Bitcask、LevelDB、RocksDB、Cassandra、Lucene |
update-in-place 流 |
以页(page)为粒度对磁盘数据进行修改 |
面向页、查找树 |
B 族树,所有主流关系型数据库和一些非关系型数据库 |
此外,针对 OLTP,还探索了常见的建索引的方法,以及一种特殊的数据库 —— 全内存数据库。
对于数据仓库,本章分析了它与 OLTP 的主要不同之处。数据仓库主要侧重于聚合查询,需要扫描很大量的数据,此时,索引就相对不太有用。需要考虑的是存储成本、带宽优化等,由此引出列式存储。
驱动数据库的底层数据结构
本节由一个 shell 脚本出发,到一个相当简单但可用的存储引擎 Bitcask,然后引出 LSM-tree,他们都属于日志流范畴。之后转向存储引擎另一流派 ——B 族树,之后对其做了简单对比。最后探讨了存储中离不开的结构 —— 索引。
首先来看,世界上 “最简单” 的数据库,由两个 Bash 函数构成:
1 2 3 4 5 6 7 8 |
#!/bin/bash db_set ( { } db_get ( { grep "^$1," database | sed -e "s/^$1,//" | tail -n 1 } |
这两个函数实现了一个基于字符串的 KV 存储(只支持 get/set,不支持 delete):
1 2 3 4 |
$ db_set 123456 '{"name":"London","attractions":["Big Ben","London Eye"]}' $ db_set 42 '{"name":"San Francisco","attractions":["Golden Gate Bridge" |