数据密集型系统设计(3)
数据密集型系统设计
-
第三章--数据存储与检索
-
概览
- 存储引擎
- 数据库
- 关系型数据库
- NoSQL数据库
- 存储引擎家族
- 日志结构的存储引擎
- 面向页的存储引擎(比如B-tree)
- 数据库
- 存储引擎
-
数据库核心:数据结构
- 概览
- 索引:基于原始数据派生而来的额外数据结构
- 适当的索引可以加速读取 查询,但每个索引都会减慢写速度
- 哈希索引
- 保存内存中的hash map,把每个键一一映射到数据文件中特定的字节偏移量,采用追加的方式。将日志分解成一定大小的段,当文件达到一定大小时就合并并删除旧的段
- 优
- 追加和分段合并主要是顺序写,它通常比随机写入快得多
- 段文件是追加的或不可改变的,则并发和崩溃恢复要简单得多
- 合并旧段可以避免随着时间的推移数据文件出现碎片化的问题
- 缺
- 哈希表必须全部放入内存,如果有大量的键,就没那么幸运了
- 区间查询效率不高
- SSTables和LSM-Tree
- 概览
- 排序字符串表,简称为SSTable:要求key-value对的顺序按键排序,每个键在每个合并的段文件中只能出现一次
- 优点(相比于哈希索引的日志段)
- 合并段更加简单高效,即使文件大于可用内存
- 在文件中查找特定的键时,不再需要在内存中保存所有键的索引
- 由于读请求往往需要扫描请求范围内的多个key-value对,可以考虑将这些记录保存到一个块中并在写磁盘之前将其压缩。然后稀疏内存索引中的每个条目指向压缩块的开头。除了节省磁盘空间,压缩还减少了I/O带宽的占用
- 优点(相比于哈希索引的日志段)
- 排序字符串表,简称为SSTable:要求key-value对的顺序按键排序,每个键在每个合并的段文件中只能出现一次
- 构建和维护SSTables
- 内存排序(红黑树和AVL树等)
- 存储引擎的基本工作流程如下
- 当写入时,将其添加到内存中的平衡树数据结构中(如红黑树)。这个内存中的树有时被称为内存表
- 当内存表大于某个阈值时,将其作为SSTable文件写入磁盘
- 为了处理读请求,首先尝试在内存表中查找键,然后是最新的磁盘段文件,接下来是次新的磁盘段文件,以此类推,直到找到目标(或为空)
- 后台进程周期性地执行段合并与压缩过程,以合并多个段文件,并丢弃那些已被覆盖或删除的值
- 上述方案有一个问题,数据库奔溃,最近的写入将会丢失。可以在磁盘上保留单独的追加日志,每当将内存表写入SSTable时,对应的日志可以被丢弃
- 从SSTable到LSM-Tree(Log-Structured Merge Tree,或LSM-Tree)
- 基于合并和压缩排序文件原理的存储引擎通常都被称为LSM存储引擎
- 性能优化
- 布隆过滤器
- 大小分级
- 较新的和较小的SSTable被连续合并到较旧和较大的SSTables
- 分层压缩
- 键的范围分裂成多个更小的SSTables,旧数据被移动到单独的“层级”,这样压缩可以逐步进行并节省磁盘空间
- 概览
- B-trees
- 概览
- 保留按键排序键值对,将数据库分解成固定大小的块或页,一般为4KB(有时更大),页是内部读/写的最小单元。这种设计更接近底层硬件,因为磁盘也是以固定大小的块排列
- 使B-tree可靠
- B-tree底层的基本写操作是使用新数据覆盖磁盘上的旧页。它假设覆盖不会改变页的磁盘存储位置,也就是说,当页被覆盖时,对该页的所有引用保持不变。这与日志结构索引(如LSM-tree)形成鲜明对比,LSM-tree仅追加更新文件(并最终删除过时的文件),但不会修改文件
- 预写日志(write-ahead log,WAL),也称作重做日志:仅支持追加修改的文件,每个B-tree的修改都必须先更新WAL然后再修改树本身的夜。当数据库在崩溃后需要恢复时,该日志用于将B-tree恢复到最近一致的状态
- 锁存器(轻量级的锁):并发控制时保护树的数据结构
- 优化B-tree
- 崩溃恢复不使用WAL而是使用写时复制方案
- 保存键的缩略信息,节省页空间
- 一般来说,页可以放在磁盘上的任何位置;没有要求相邻的页需要放在磁盘的相邻位置
- 添加额外的指针到树中
- B-tree的变体如分形树,借鉴了一些日志结构的想法来减少磁盘寻道
- 概览
- 对比B-tree和LSM-tree
- 概览
- 根据经验,LSM-tree通常对于写入更快,而B-tree被认为对于读取更快
- LSM-tree的优点
- 写放大:在数据库内,由于一次数据库写入请求导致的多次磁盘写
- LSM-tree通常能够承受比B-tree更高的写入吞吐量,部分是因为它们有时具有降低的写放大,部分原因是它们以顺序方式写入紧凑的SSTable文件
- LSM-tree可以支持更好的压缩,因此通常磁盘上的文件比B-tree小很多
- 更低的写放大和碎片减少对于SSD上有益,在可用的I/O带宽中支持更多的读写请求
- LSM-tree的缺点
- 压缩过程有时会干扰正在进行的读写操作。磁盘的并发资源有限,当磁盘执行昂贵的压缩操作时,很容易发生读写请求等待的情况
- 概览
- 其他索引结构
- 概览
- 二级索引:可以容易地机遇ket-value索引来构建。
- 键不唯一
- 使索引中的每个值成为匹配行标识符的列表(像全文索引中的posting list)
- 追加一些行标识符来使每个键变得唯一
- 键不唯一
- 二级索引:可以容易地机遇ket-value索引来构建。
- 在索引中存储值
- 键:查询搜索的对象
- 值
- 实际行(文档、顶点)
- 对其他地方存储的行的引用
- 存储行的具体位置被称为堆文件,不以特定的顺序存储数据
- 聚集索引:索引行直接存储在索引中
- 非聚集索引:仅存储索引中的数据的引用
- 覆盖索引(包含列的索引):索引中保存一些表的列值。它可以支持只通过索引即可回答某些简单查询(在这种情况下,称索引覆盖了查询)
- 多列索引
- 级联索引:将一列追加到另一列,将几个字段简单的组合成一个键(索引的定义指定字段连接的顺序)
- 全文搜索和模糊索引
- 全文搜索引擎通常支持对一个单词的所有同义词进行查询
- 在Lucene中,内存中的索引是键中的字符序列的有限状态自动机,类似字典树。这个自动机可以转换成Levenshtein自动机,它支持在给定编辑距离内高效地搜索单词
- 在内存中保存所有内容
- 如果将来非易失性存储(non-volatile memory,NVM)技术得到更广泛普及
- 概览
- 概览
-
事务处理与分析处理
-
概览
属性 事务处理系统(OLTP) 分析系统(OLAP) 主要读特征 基于键,每次查询返回少量的记录 对大量记录进行汇总 主要写特征 随机访问,低延迟写入用户的输入 批量导入(ETL)或事件流 典型使用场景 终端用户,通过网络应用程序 内部分析师,为决策提供支持 数据表征 最新的数据状态(当前时间点) 随着时间而变化的所有事件历史 数据规模 GB到TB TB到PB -
数据仓库
- 概览
- 数据仓库是单独的数据库,包含公司所有各种OLTP系统的只读副本。从OLTP数据库(使用周期性数据转储或连续更新流)中提取数据,转换为分析友好的模式,执行必要的清理,然后加载到数据仓库中。将数据导入数据仓库的过程称为提取-转换-加载(Extract-Transform-Load,ETL)
- OLTP数据库和数据仓库之间的差异
- 数据仓库的数据模型最常见的是关系型,因为SQL通常适合分析查询。有许多图形化数据分析工具,它们可以生成SQL查询、可视化结果并支持分析师探索数据(钻取、切片、切丁)
- 一个专注于支持事务处理、一个专注于分析工作负载
- 概览
-
星型与雪花分析模式
- 星型模式(维度建模):当表关系可视化时,事实表位于中间,被一系列维度表包围;这些表的连接就像星星的光芒
- 雪花模式:基于星型模式,其中维度表进一步细分为子空间。雪花模式比星型模式更规范化,但是星型模式通常是首选,主要是因为对于分析人员,星型模式使用起来更简单
-
列式存储
- 概览
- 解决事实表超过100列,但是用到的时候只需要其中的几列,防止将所有列从磁盘加载到内存,而只将需要的列加载到内存
- 不将一行中的所有值存储在一起,而是将每列中的所有值存储在一起
- 列压缩
- 概览
- 除了仅从磁盘中加载查询所需的列之外,还可以通过压缩数据来进一步降低对磁盘吞吐量的要求
- 游程编码
- 列族:在每个列中,将一行中的所有列与行主键一起保存,并且不使用列压缩。面向行的做法
- 内存带宽和矢量化处理
- 将数据从磁盘加载到内存的宽带是一大瓶颈
- 高效的将内存的带宽用于CPU,避免分支错误预测和CPU指令处理流水线中的气泡,并利用现代CPU中的单指令多数据(SIMD)指令
- 除了减少需要从磁盘加载的数据量之外,面向列的存储布局也有利于高效利用CPU周期
- 矢量化处理:查询引擎可以将一大块压缩列数据放入CPU的L1缓存中,并以紧凑循环(即没有函数调用)进行迭代。对于每个被处理的记录,CPU能够比基于很多函数调用和条件判断的代码更快地执行这种循环。列压缩使得列中更多的行可以加载到L1缓存。诸如先前描述的按位AND和OR的运算符,可被设计成直接对这样的列压缩数据块操作
- 概览
- 列存储中的排序
- 概览
- 在列存储中,行的存储顺序并不太重要。最简单的是按插入顺序保存,这样插入一个新行只是追加到每个列文件
- 即使数据是按列存储的,也需要一次排序整行。数据库管理员可以基于常见查询的知识来选择要排序表的列。当第一列排序出现相同值时,可以指定第二列继续进行排序。排序可以帮助进一步压缩列
- 几种不同的排序
- 数据需要复制到多台机器,这样在一台机器发生故障时,不会丢失数据。不妨存储不同方式排序的冗余数据,以便在处理查询时,可以选择最适合特定查询模式的排序版本
- 概览
- 列存储的写操作
- 面向列的存储、压缩和排序都非常有助于加速读取查询。但是,它们的缺点是让写入更加困难
- B-tree使用原地更新方式,对于压缩列不可能。LSM-tree是一个很好的解决方案
- 聚合:数据立方体与物化视图
- 物化聚合:
- 物化视图:在关系数据模型中,它通常被定义为标准(虚拟)视图:一个类似表的对象,其内容是一些查询的结果。不同的是,物化视图式查询结果的实际副本,并被写到磁盘,而虚拟视图只是用于编写查询的快捷方式
- 数据立方体(OLAP立方体)
- 不同维度分组的聚合网格
- 物化聚合:
- 概览
-
-
本文来自博客园,作者:orangeScc,转载请注明原文链接:https://www.cnblogs.com/ashScc/p/16158461.html