第一部分:适用于所有数据系统的基本思想
第1章:术语与方法
- 数据库
- 高速缓存
- 索引:按关键字搜索数据并支持各种过滤
- 流式处理:持续发送消息至另一个进程,处理采用异步方式
- 批处理:定期处理大量的累积数据
设计数据系统时会遇到的问题
- 当系统内出现了局部失效时,如何确保数据的正确性与完整性?
- 当发生系统降级时,该如何为客户提供一致的良好表现?
- 负载增加时,系统如何扩展?
- 友好的服务API该如何设计?
目标
可靠性
硬件错误、软件错误、人为错误
可扩展性
本系统的负载是什么?(每秒请求处理次数?同时活动用户数量?平均值?峰值?)
负载增加但系统资源不变,系统性能会发生什么变化?
负载增加,如果要保持性能不变,需要增加多少资源?
本系统的性能指标如何衡量?(吞吐量?响应时间?)
负载增加时,如何保持良好的性能?(垂直拓展:升级到更强大的机器。水平拓展:将负载分布到多个更小的机器,无共享体系结构)
弹性拓展:自动检测负载增加,自动添加更多计算资源
手动拓展:人工分析性能表现,手动添加更多计算资源
无状态服务水平拓展比有状态服务更容易。
超大规模的系统要针对应用定制,没有一套通用的框架,所以说这种架构师的岗位是无法替代的,有出路,可以一直搞,从通用的组件定制出一个超大规模的系统。
可维护性
运维简单、项目复杂度低、易于改变
第2章:数据模型与查询语言
每层通过提供一个简洁的数据模型来隐藏下层的复杂性。
数据模型
层次模型:
不好用,基本用下面三种
关系模型:
写时模式(写时强制)
劣势:对象-关系不匹配(阻抗失谐,需要一个转换层也就是ORM)
文档模型:
读时模式(读时处理)
图模型
读时模式(读时处理)
所有数据都有可能相互关联
一个模型可以用另一个模型来模拟,但是在不同场景下,有的模型过于笨重,所以不同的系统用于不同的目的。
还有其他的模型(全文索引等)
查询语句
命令式
告诉计算机以特定的顺序执行某些操作,指定如何实现
声明式
只需指定所需的数据模式,不需要指定如何实现,系统自动选择
MapReduce
编程模型
查询的逻辑用代码片段来表示,这些代码片段可以被处理框架重复地调用。
基于函数语言中的map(也称collect)和reduce(也称fold或inject)函数
第3章:存储引擎
日志:表示一个仅能追加的记录序列集合。
墓碑:表示这个记录被删除的标记
索引结构
哈希索引:
必须全放进内存(放到磁盘基本没用)
不能简单支持区间查找
存储段key-value对不需要有序
值可以是实际行(文档,顶点),也可以是对其他地方存储的行的引用(这个用的多,因为存在多个二级索引的时候就可以避免复制数据),存储具体行的文件叫堆文件,
聚集索引:
在索引文件中保存行数据
非聚集索引:
索引文件中只存储数据的引用
覆盖索引:
多列索引:
全文索引和模糊索引:
日志结构
SSTable(排序字符串表)
key-value对有序
LSM存储引擎
Log-Structured Merge-Tree
性能优化
布隆过滤器
分层压缩(LevelDB,RocksDB)
大小分级(HBase)
B-trees
B-Tree的操作复杂,所以中途崩溃会导致操作无法完成,而且可能会破坏索引(比如分裂页中途崩溃)
使用日志做保障
内存数据库的性能优势不是因为它们不需要从磁盘读取,而是避免了写磁盘格式对内存数据结构编码的开销。
在线事务处理(online transaction processing)OLTP
在线分析处理(onlien analytic processing)OLAP
将数据库导入数据仓库的过程称为提取-转换-加载(Extract-Transform-Load,ETL)
数据仓库
星形表与雪花表
星形表:数据存储在一张巨大的事实表中,其他的表由它发散出去
雪花表:通过外键连接彼此
列式存储
可以使用位图进行列压缩