数据密集型系统设计(3)

数据密集型系统设计

  • 第三章--数据存储与检索

    • 概览

      • 存储引擎
        • 数据库
          • 关系型数据库
          • NoSQL数据库
        • 存储引擎家族
          • 日志结构的存储引擎
          • 面向页的存储引擎(比如B-tree)
    • 数据库核心:数据结构

      • 概览
        • 索引:基于原始数据派生而来的额外数据结构
        • 适当的索引可以加速读取 查询,但每个索引都会减慢写速度
      • 哈希索引
        • 保存内存中的hash map,把每个键一一映射到数据文件中特定的字节偏移量,采用追加的方式。将日志分解成一定大小的段,当文件达到一定大小时就合并并删除旧的段
          • 追加和分段合并主要是顺序写,它通常比随机写入快得多
          • 段文件是追加的或不可改变的,则并发和崩溃恢复要简单得多
          • 合并旧段可以避免随着时间的推移数据文件出现碎片化的问题
          • 哈希表必须全部放入内存,如果有大量的键,就没那么幸运了
          • 区间查询效率不高
      • SSTables和LSM-Tree
        • 概览
          • 排序字符串表,简称为SSTable:要求key-value对的顺序按键排序,每个键在每个合并的段文件中只能出现一次
            • 优点(相比于哈希索引的日志段)
              • 合并段更加简单高效,即使文件大于可用内存
              • 在文件中查找特定的键时,不再需要在内存中保存所有键的索引
              • 由于读请求往往需要扫描请求范围内的多个key-value对,可以考虑将这些记录保存到一个块中并在写磁盘之前将其压缩。然后稀疏内存索引中的每个条目指向压缩块的开头。除了节省磁盘空间,压缩还减少了I/O带宽的占用
        • 构建和维护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)
              • 追加一些行标识符来使每个键变得唯一
        • 在索引中存储值
          • 键:查询搜索的对象
            • 实际行(文档、顶点)
            • 对其他地方存储的行的引用
              • 存储行的具体位置被称为堆文件,不以特定的顺序存储数据
          • 聚集索引:索引行直接存储在索引中
          • 非聚集索引:仅存储索引中的数据的引用
          • 覆盖索引(包含列的索引):索引中保存一些表的列值。它可以支持只通过索引即可回答某些简单查询(在这种情况下,称索引覆盖了查询)
        • 多列索引
          • 级联索引:将一列追加到另一列,将几个字段简单的组合成一个键(索引的定义指定字段连接的顺序)
        • 全文搜索和模糊索引
          • 全文搜索引擎通常支持对一个单词的所有同义词进行查询
          • 在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立方体)
            • 不同维度分组的聚合网格
posted @ 2022-04-18 10:18  orangeScc  阅读(44)  评论(0编辑  收藏  举报