数据密集型应用系统设计(3)
文章目录
- 数据存储与检索
- 数据库核心是数据结构
- 哈希索引
- SSTable和LSM-Tree
- B-trees
- B-tree和LSM-tree
- 其他索引结构(*)
- 事务处理和分析系统
- 小结
数据存储与检索
本章我们从数据库的角度来探讨探讨如何存储输入的数据,并且在收到查询时找到数据。
针对事务型负载和针对分析型负载的存储引擎优化存在很大的差异。
数据库核心是数据结构
日志通常指的是应用程序的运行输出日志,来记录发生了什么事情。当然日志还有一个更通用的含义,表示一个仅能追加的记录序列集合。它可能是人类不可读的,可能是二进制格式而只能被其他程序读取。
日志方式的查找开销是O(n)O(n)O(n)。
为了高效查找数据库中的特定键的值,需要新的数据结构:索引。索引的基本想法是保留一些额外的元数据,将这些元数据作为路标,帮助定位想要的数据。
索引是基于原始数据派生而来的额外数据结构。很多数据库允许单独添加和删除索引而不改变数据库的内容,以影响查询性能。对于写入,任何类型的索引都会降低写的速度(相比于日志的简单追加文件方式)。
所以适当的索引可以加速读取查询,但每个索引都会降低写速度:这是存储系统中重要的权衡设计。
哈希索引
假设数据存储全部采用追加式文件组成,最简单的索引策略是保存内存中的hash map,把每个键一一映射到数据文件中特定的字节偏移量,这样就可以找到每个值的位置。当查找某个值时,使用hash map来找到文件中的偏移量,即存储位置,然后读取内容。
如果key比较少,但每个key都有大量的写操作,将所有key保存在内存中是可取的。可以采用上述方式。
具体可见日志结构的存储引擎-bitcask。
哈希表索引的缺陷:
- 哈希表必须全部放入内存。因为磁盘上的hash map表现不好,需要大量的随机访问I/O,当哈希变满时,继续增长代价昂贵,并且哈希冲突时需要处理复杂的处理逻辑。
- 区间查询效率不高,只能采用逐个查找的方式查询每一个键。
SSTable和LSM-Tree
上述的日志结构的存储段中的键值对是按照写入顺序排列的。如果我们希望按照键对键值对排序,这种格式称为SSTable,它有以下优点:
- 合并段更加高效简单。
- 在文件中查找特定的键时,不需要在内存中保存所有键的索引。(通过稀疏索引减少索引的数量)
- 读请求需要扫描全球范围内的多个键值对,可以考虑将这些记录保存到一个块中并且在写磁盘之前将其压缩。
构建和维护SSTables
存储引擎的基本工作流程如下:
- 当写入时,将其添加到内存中的平衡树数据结构中(例如红黑树),有时被称作内存表
- 当内存表过大时,将其作为SSTable文件写入磁盘。由于树已经维护了按键排序的键值对,写磁盘可以比较高效。新的SSTable文件成为数据库的最新部分。当SSTable写磁盘的同时,写入可以继续添加到一个新的内存表实例
- 为了处理读请求,首先尝试在内存表中查找键,然后是最新的磁盘段文件,接下来是次新的磁盘段文件,以此类推,直到找到目标
- 后台进程周期性执行段合并和压缩过程,以合并多个段文件,并丢弃那些被覆盖或者删除的值
以上的算法本质在很多引擎使用,如LevelDB,RocksDB,类似的存储引擎还有Cassandra和HBase。
LSM-Tree的基本思想是保存在后台合并的一系列SSTable。基于合并和压缩排序文件原理的存储引擎通常都被称为LSM存储引擎。
B-trees
B-tree同样保留按键排序的键值对,以实现高效的键值查询和区间查询,但是它本质上具有非常不同的设计理念。
不同于之前看到的日志结构索引将数据库分解为可变大小的段,通常大小为几兆字节或者更大,并且始终按照顺序写入段。B-trees将数据库分解成固定大小的块或者页,传统上大小是4KB,页是内部读/写的最小单元。
由于每个页面都可以使用地址进行标识,就可以让一个页面引用另外一个页面。可以用这些页面引用构造一个树状页面,索引一个键时,从根页面开始逐渐向下寻找,直到到达一个包含单个键的叶子页,它包含每个内联键的值或包含可以找到值的页的引用。
分支因子是一个页中包含的子页的引用数量,实际中通常为几百个。
更新策略和崩溃恢复策略:
- 更新现有键的值即搜索包含该键的页子叶,更改该页的值
- 添加新键,需要找到范围包含该键的页,并且添加。如果此页无可用空间,则分裂成两个半满的页,且更新父页。
- 为了崩溃恢复,使用预写日志WAL,所有修改先更新WAL再修改树本身的页。WAL用于将树恢复到最近一致的状态。
B-tree和LSM-tree
根据经验,LSM-tree通常对于写入更快,B-tree读取更快。
LSM-tree的优点:
由于B-tree存储引擎按固定页写入,那么通常每一页都会有些空间无法使用。而LSM-tree不是面向页的,并且定期重写SSTable以消除碎片化,所以具有较低的碎片率。
LSM-tree通常能够承受比B-tree更高的写入吞吐量,部分原因是具有较低的写放大(一次数据写入导致多次磁盘写入称为写放大),部分原因因为它是以顺序方式写入紧凑的SSTable文件。
LSM-tree的缺点:
日志结构存储的缺点是有时候压缩过程会干扰正在进行的读写操作。另外写入吞吐量和压缩要共享磁盘的有限的写入带宽,也就是说数据库的数据量越大,压缩就需要越多的磁盘带宽。
B-tree的每个键恰好唯一对应于索引中的某个位置,而日志结构的存储引擎可能在不同的段中具有相同键的多个副本。如果在这种场景下需要提供强大的事务语义,无疑B-tree更具竞争力。
其他索引结构(*)
在索引中存储值
多列索引
全文搜索和模糊搜索
在内存中保存所有内容
事务处理和分析系统
待补
小结
本章的重点在于介绍数据库内部如何处理存储和检索,例如存储新数据和查询数据。
存储引擎大致分为两大类:针对事务处理(OLTP)优化的架构,以及针对分析型(OLAP)的优化架构。
- OLTP系统通常面向用户,这意味着它们可能收到大量的请求。为了处理负载,应用程序通常在每个查询中只涉及少量的记录。应用程序基于某种键来请求记录,而存储引擎使用索引来查找所请求键的数据。磁盘寻道时间通常是瓶颈。
- 由于不是直接面对最终用户,数据仓库和类似的分析型系统相对并不太广为人知,它们主要由业务分析师使用。处理的查询请求数目远低于OLTP,但每个查询通常要求很严苛,需要在短时间内扫描数百万条记录。磁盘带宽通常是瓶颈。
在OLTP中分为两个主要流派:
- 日志结构流派,只允许追加式更新文件和删除过时的文件,但不会修改已写入的文件。
- 原地更新流派,将磁盘视为可以覆盖的一组固定大小的页。B-tree是最典型代表,已用于所有主要的关系数据库和大量的非关系数据库。
数据密集型应用系统设计(3)相关推荐
- 数据密集型应用系统设计 [Designing Data-Intensive Applications]
作者:[美] Martin Kleppmann(马丁·科勒普曼) 著,赵军平 吕云松 耿煜 李三平 译 出版社: 中国电力出版社 出版时间:2018-09-01 数据密集型应用系统设计 [Design ...
- Designing Data-Intensive Application《数据密集型应用系统设计》笔记
Designing Data-Intensive Application 中译<设计数据密集型应用>又名<数据密集型应用系统设计>,我看的是冯若航在gitbook开源的翻译版本 ...
- 《数据密集型应用系统设计》读书笔记——第一部分 数据系统基础
第一部分 数据系统基础 第1章 可靠.可扩展与可维护的应用系统 当今许多新型应用都属于数据密集型,而不是计算密集型.对于这些类型应用,CPU的处理能力往往不是第一限制性因素,关键在于数据量.数据的复杂 ...
- 豆瓣评分 9.7 的神书:《数据密集型应用系统设计》
我最近在读一本好书<数据密集型应用系统设计>(也被叫做 DDIA).这真是本相见恨晚的神书. 这是怎样一本神书?豆瓣评分高达 9.7 分! 什么是「数据密集型应用系统」? 当数据(数据量. ...
- 《数据密集型应用系统设计》读书笔记——数据系统基础
因为个人兴趣,想学学分布式方面的知识,然后找到了这本<数据密集型应用系统设计>,确实非常的不错,无论对于以前的工程还是现在的科研都有启迪和感悟,所以就写份读书笔记记录一下,里面提到的知识非 ...
- 数据密集型应用系统设计——笔记
本篇章内容为阅读<数据密集型应用系统设计>一书的读书笔记. 作为个人成长学习使用,同时希望对刷到的朋友有所帮助,一起加油哦! 生命就像一朵花,要拼尽全力绽放,芳香四溢,在风中舞蹈! 写在前 ...
- 数据密集型应用系统设计-第七章分布式系统的麻烦-笔记
这阵子在看数据密集型应用系统设计书籍,自己把书籍比较重要的内容整理出来,基本一天一更,请感兴趣的朋友多多关注! 整个系列会在这几天都发布出来,可以关注一下 链接: 数据密集型应用系统设计-笔记. 文章 ...
- 数据密集型应用系统设计(读书笔记)第一天
第一章: 可靠.可扩展与可维护的应用系统 数据密集型应用通常也是基于标准模块构建而成,每个模块负责单一的常用功能.例如,许多应用系统都包含以下模块: 数据库:用以存储数据,这样之后应用可以再次面问. ...
- 《数据密集型应用系统设计》读书笔记——第二部分 分布式数据系统(二)
第8章 分布式系统的挑战 故障与部分失效 当你在⼀台计算机上编写一个程序时,它通常会以一种确定的方式运⾏:⽆论是⼯作还是不工作.充满错误的软件可能会让人觉得电脑有时候是"糟糕的一天" ...
- 数据密集型应用系统设计--数据分区
数据分区与数据复制 分区的目的一般是提高可扩展性.容错性和集群吞吐,同一个分区会在多个节点中都有副本. 容错性:一个节点挂掉,则这个节点上的分区,在其他节点上都有副本,可以查询其他的节点 可扩展性:新 ...
最新文章
- 在docker中搭建apache Tomcat+JDK环境
- 深度学习核心技术精讲100篇(三十二)-网易实时数仓实战应用
- C++链表linked list(附完整源码)
- android中判断sim卡状态和读取联系人资料的方法
- 你需要的git命令大全来了
- Struts1.x和Struts2.0的Action的区别
- matlab画二维颜色深浅,matlab中如何为二维图形填充渐进的颜色
- vagrant开启Xshell使用密码登录方式
- 用PHP做服务器接口客户端用http协议POST访问安全性一般怎么做
- 《21天学通Java(第7版)》——VC程序员的学习笔记1
- java实习鉴定书个人鉴定_大学生实习鉴定表自我鉴定范文
- 思科模拟器CIsco Packet Tracer路由器上配置 DHCP
- 图解 Cisco IOS 命名规范
- looking for domain authoritative name server and domain name location
- BBS中用SSH方式登录添加附件
- 记一次微信支付回调失败的修复
- 【生成对抗网络 论文泛读】……pix2pix pix2pixhd……
- 从校训、企业文化到团队文化
- C语言完成图书管理系统
- Android 耳机驱动知识
热门文章
- C++强制关闭进程的办法
- 查询至少生产两种不同的计算机(PC或便携式电脑)且机器速度至少为133的厂商
- 在linux中 系统默认,在Red Hat Linux 9中,系统默认的( )用户对整个系统拥有完全的控制权...
- conceptd什么时候上市_iPhone12 Pro Max什么时候上市售价
- 虹软android工程师,虹软人脸识别技术公开课开讲!AI工程师如何快速进阶
- html5 canvas 图片拼接,HTML5 canvas drawImage方法实现读取图片数据截图拼接图片。
- 数据库主键如何设计?
- 详解JavaScript创建对象——构造函数模式
- 128*64点阵图形液晶显示屏程序设计教程
- 国家电网计算机知识点归纳,国家电网考试知识点整理.doc