数据库系统设计概述(下篇)

大家好我是佩奇
发布于 2022-8-4 15:21
浏览
1收藏

数据库系统设计概述(上篇)

 

四、知行合一

知是行的主意,行是知的工夫;知是行之始,行是知之成。—— 王阳明

这一章节将简单讲解一些数据库系统的常见技术点。

 

系统架构
Master-Slave
Master-slave 架构可以说是最常用的数据存储架构,关系型数据库如:mysql,postgreSql,oracle,Nosql 诸如:MongoDb,消息队列如:Kafka,RabbitMQ 等都使用了这种架构。

数据库系统设计概述(下篇)-鸿蒙开发者社区

master_slave

在整个系统中,Master 承担写任务,Slave 通过复制 Master 的数据保证与 Master 数据的一致性。Master 和 Slave 都可以承担读任务。Master 架构解决了数据的高可用问题(Slave 存储了数据副本),也扩展了数据读并发能力(多 Slave 同时通过读请求)。

在 Master-Slave 架构中,单 Master 如果出现故障,就会导致这个数据库系统不可用,这时就可以采用 Master-Master 架构,系统中同时存在多个 Master 节点,但是,多个 Mater 节点并不同时提供写服务,同时只会存在一个可写的 Master,另一个 Master 作为备机存在,只有当其他 Master 不可用时才会被选举称为 Master 节点提供写服务,作为备机的 Master 是可以提供读服务的。这种架构的只解决了单 Master 节点的高可用问题,并没有解决单 Master 负载过大的问题,这里之所以只有一个 Master 提供写服务,是为了保证写数据的一致性问题。

 

数据一致性
我们将同一份数据在不同数据节点上的存储称之为副本。只要系统中数据存在多个副本,就会有数据一致性问题。如何保证数据多副本的一致性,一直以来都是分布式系统的最大挑战。多节点数据同步,一般采用复制方式,从节点复制主节点的数据,多节点之间相互复制等等,但无论采用哪种方式,都无法避免不一致的情况。

数据一致性可以分为最终一致性和强一致性。强一致性模型能够允许你的单服务程序移植到分布式节点集群上并且不会发生任何错误。强一致性往往通过牺牲系统可用性来达到,在写入数据时,如无法保证多副本一致,则失败。最终一致性模型中,当停止改变数值的一段不确定的时间后,所有的复制集将会最终保持一致。这表明,在这段时间之前,数据副本在某种情形下是不一致的,但数据最终会达到一致,最终一致性意味着“收敛”,即预期所有的副本最终会收敛到相同的值。

在数据收敛过程中,为保证最终数据的一致性性,还有许多问题需要解决。如系统间的时序问题,原子提交问题,共识问题。

 

CAP 理论
**定理:**一个分布式系统不可能同时满足 consistency、availability、partition tolerance 这三个基本需求,最多同时满足两个。

 ● consistency 一致性:所有节点同一时刻看到相同数据
 ● availability 可用性:节点失败不阻止影响正在运行的节点的工作
 ● partition tolerance 分区容错:即使出现信息丢失或网络、节点失败,系统也能继续运行(通过复制)

数据库系统设计概述(下篇)-鸿蒙开发者社区

cap

这三种性质进行俩俩组合,可以得到下面三种情况:

 ● CA:完全严格的仲裁协议,例如 2PC(两阶段提交协议,第一阶段投票,第二阶段事物提交)
 ● CP:不完全(多数)仲裁协议,例如 Paxos、Raft
 ● AP:使用冲突解决的协议,例如 Dynamo、Gossip
CA 和 CP 系统设计遵循的都是强一致性理论。不同的是 CA 系统不能容忍节点发生故障。CP 系统能够容忍 2f+1 个节点中有 f 个节点发生失败。

 

分区

数据库系统设计概述(下篇)-鸿蒙开发者社区

p_r_mini

上面说副本只能保证数据的可用性。为提高大量数据集的读写能力,我们可以将数据拆分成不同的分区分开处理,这种技术称之为分片。

分片,即将数据集分割成相互独立的小数据集,减少因数据集增长而带来对单个节点的压力。数据分片有以下好处:

 ● 提高性能:限制分区中数据量的大小,降低数据压力
 ● 提高可用性:数据之间相互独立,不同分区之间失败互不影响,允许失败节点的存在
分区自然也会带来一些问题,首先需要考虑的就是如何分区的问题。

 ● 基于关键字区间:将数据按关键字划分为不同区间,将相同区间的数据写入同一个节点。比如用户数据 id 分布在[1-1000000]之间,需将数据分布到 10 个节点上,可以将数据划分成十个区间:
 ● **关键字哈希分区:**通过 Hash 算法计算分区号,将数据写入相应分区号的分区中。
数据分区带来的负载倾斜和热点问题:由于数据的不确定性,数据关键字计算出来的分区存储可能集中在某几个区间内,这样就可能导致某些节点数据明显多余其他节点,这种数据集中于某个节点的情况就是数据热点。由于数据热点的出现,整个系统的负载将倾斜到这些节点上,造成分区间的负载不均衡,这就是负载倾斜问题。

 

去中心化:Dynamo
Dynamo 是 Amazon 的一个分布式存储。Amazon 发表了一篇论文 👉Dynamo: Amazon’s Highly Available Key-value Store 讲解 Dynamo 架构,使得 Dynamo 称为许多数据存储系统借鉴的架构。

Dynamo 基于一些众所周知的技术实现了可扩展性和高可用性:

 ● 数据通过一致性哈希算法进行分区和复制(partitioned and replicated)
 ● 通过对象版本化(object versioning)实现一致性
 ● 副本之间的一致性由一种仲裁的技术(quorum-like technique)和一个去中心化的副本同步协议(replica synchroni protocol)来保证
 ● 基于 gossip 协议进行分布式故障检测和成员检测(membership)协议管理节点
Dynamo 是一个完全去中心化的系统。

数据库系统设计概述(下篇)-鸿蒙开发者社区

no_master

向 Dynamo 添加或移除存储节点不需要人工 partition(调整哈希节点)或 redistribution(在节点之间重新平衡数据分布)

Dynamo 采用最终一致性方案。

生产级别的存储系统的架构是很复杂的。除了最终存储数据的组件之外,系统还要针对以下方面制定可扩展和健壮的解决方案:负载均衡、成员管理(membership)、故障检测、故障恢复、副本同步、过载处理(overload handling)、状态转移、并发和任务调度、请求 marshalling、请求路由(routing)、系统监控和告警,以及配置管理。

下表总结了 Dynamo 使用的这些技术及每项技术的好处。

数据库系统设计概述(下篇)-鸿蒙开发者社区

Partition
 ● 技术:一致性哈希
 ● 好处:增量可扩展性


写高可用
 ● 技术:读时协调(解决冲突)的向量时钟(vector clocks with reconciliation during reads)
 ● 好处:version size 和更新频率(update rates)解耦


短时故障处理
 ● 技术:宽松的选举和 hinted handoff(移交给其他节点处理,附带提示信息)
 ● 好处:部分副本不可用时,仍然可以提供高可用性和持久性


持久(permanent)故障恢复
 ● 技术:基于 Merkle tree 的逆熵(anti-entropy)
 ● 好处:后台同步版本不一致的副本


成员管理和故障检测
 ● 技术:基于 Gossip 的成员管理协议和故障检测
 ● 好处:保持了架构的对称性,无需一个中心组件(centralized registry)来存储成员和节点状态等信息

分布式数据库 Cassandra 就是 Dynamo 的典型实现。

 

有主架构:Bigtable
Bigtable 是 google 开源的数据库系统。Bigtable 是典型的有主架构。

Bigtable 主要由三个组件构成:

  1. 一个客户端库,会链接到每个客户端
  2. 一个 master server
  3. 多个 tablet server


master 负责:

  1. 将 tablet 分配给 tablet server
  2. 检测 tablet server 的过期(expiration)及新加(addition)事件
  3. 平衡 tablet server 负载
  4. 垃圾回收(GC)
  5. 处理 schema 变动,例如 table 和 column family 的创建
    BigTable 的 Master 只负责元数据的管理,Table Server 负载自身管理的 Table 的读写功能,客户端只想 Master 同步元数据,数据不经过 Master 节点,直接和 Table Server 通信。因此,BigTable 中 Master 节点的负载很低。

有主架构中,Master 承担的能力也会不一致,比如在下图架构中,Master 只承担 Coordinate 功能,管理元数据和 Node 节点,Client 获取 Mata Data,直接和相应的数据节点通信。

数据库系统设计概述(下篇)-鸿蒙开发者社区master_worker1

在下面架构中,Client 不直接和 Data Node 节点通信,而是和 Master 通信,Master 更加相关元数据将请求转发给对应的 Data Node:

数据库系统设计概述(下篇)-鸿蒙开发者社区

master_work2

Coordinate-Worker 架构是很多分布式数据库采用的架构,有兴趣的同学可以看看笔者之前讲解的 👉《Druid 的架构设计》

 

索引
数据库系统的索引,就是用来提高数据检索效率的。数据库系统的数据记录存储在磁盘中,如果没有索引,要从磁盘中检索相应的记录,就需要扫描所有的数据段,这种 O(N) 的访问效率和全磁盘的扫描自然不可能在真正的数据库系统中使用。为提高数据检索能力,数据库系统引入索引技术,为磁盘上的数据记录做一个索引结构,这些索引放在内存中,或按块存储在磁盘上(但只需要少数几次磁盘读取就可以读入内存中),这样检索一个数据先从内存索引中查找到对应的 Key 或磁盘位置,然后从磁盘中读取记录。

这里索引做了两个事情:

 ● 将大量磁盘检索变成内存检索
 ● 通过特定的数据结构可以提高内存检索的效率,改变 O(N) 这种低效率的检索


HASH 索引

数据库系统设计概述(下篇)-鸿蒙开发者社区

hash_index

HASH 即哈希表,类似 Java 的 HashMap 数据结构,Key-Value 格式。假设我们在内存内维护一个 HashMap Index,key 为数据的键,Value 是数据在磁盘的存储偏移量。

 ● 获取数据时,先从内存 Map 获取对应数据的磁盘 offset,然后读取磁盘的数据。
 ● 写数据时,先将数据追加写入磁盘,然后更新内存 HashMap Index。
Hash 索引听起来过于简单,但确实是一种可行的索引方法。Hash 索引简单高效,查询性能 O(1),更新也高效,当时也有明显的缺点,比如:

 ● 需要将整个哈希表放入内存,这对于大数据量来说内存耗费将不可承受的。
 ● 只能进行精确查询。
 ● 不能实现范围查询。


B-Tree 索引
B-trees 索引始见于 1970 年,经受了长久的时间考验,时至今日,它仍然时几乎所有关系数据库中的标准索引实现,许多非关系型数据库也经常使用。

了解B-trees索引先从二叉搜索树开始。二叉搜索树是一种特殊的二叉树,它满足以下条件:

 ● 左子树小于父节点
 ● 右子树大于父节点

数据库系统设计概述(下篇)-鸿蒙开发者社区

BST

上图是一个搜索二叉树,如果我要查找 208 这个 key:

 ● 先从根节点开始,即 136。比较 208 > 136,下一步应该从根节点的右子树查找
 ● 398 > 208,继续搜索 398 的左子树
 ● 250 > 208,继续搜索 250 的左子树
 ● 200 < 208,继续搜索 200 的右子树。
 ● 200 的右子树并不存在,因此数据中没有 208,查找结束
让我们再查找 40:

 ● 从根节点 136 开始,136 > 40,继续搜索左子树
 ● 80 > 40,继续搜索左子树
 ● 40 = 40,节点存在,从节点中获取数据 id,然后可以更加数据 id 查找对应的数据
在索引结构中,树的每个Node包含一个 key 值,一个数据指针(或数据 id、磁盘 offset 等)

 

二叉搜索树的时间复杂度是 log(N),这是一个不错的结果。

二叉搜索树依旧只能获取特定的值,如果我需要进行范围查找,即查找两个数之间的所有数据,就需要去遍历树中的每一个节点,去判断节点是否在此范围内,这种情况下,时间复杂度又下降到了 O(N)。因此我们需要改进上面的数据结构,现代大多数数据库都才有一种改进的二叉搜索树—— B+Tree。

数据库系统设计概述(下篇)-鸿蒙开发者社区

B+tree

B+Tree 在二叉搜索树的基础上添加如下特征:

 ● 仅仅在叶子节点存储索引信息(关联表数据的信息)
 ● 其余节点仅仅用于查找到最终的叶子节点(叶子节点包含了所有的 key)
在 B+Tree 中,每个 Key 会存在两个 Node,所有中间节点只用于辅助检索最终正确的叶子节点(叶子节点才包含关联数据的信息)。

让我们尝试从上面的 B+Tree 中搜索出[40, 100]之间的节点:

 ● 采用和二叉搜索树一样的方式,我们只需要搜索 40 这个节点(或搜索出最接近 40 的节点,当 40 的节点不存在时)
 ● 然后在叶子节点链表中往下追溯,知道超过 100
假设树中共有 N 个节点,追溯了 M 个叶子节点,那么可以得出,此次搜索的时间复杂度是:log(N) + M。相对于之前的 O(N) 的二叉搜索树有以下好处:

 ● 不需要读取整棵树,这样可以减少读取磁盘的次数(索引数据一般按页存储在磁盘上)
 ● 大多数情况下 M (约等于检索范围)会远小于整个数据量 N,因此这里的 O(M) 时间复杂度大多数情况下远小于 O(N)。
*任何事情都是双面的。*B+Tree 索引带来的检索优势,必然会有其他方面的损失。这主要体现在删除数据时。因为叶子节点类似于链表结构,删除一个节点需要从 header 开始遍历,时间复杂度是 O(N)。

B+Tree 索引具有比较好的检索性能,为了减少磁盘访问次数,大多数索引系统的 B+tree 都只有 3- 4 层,因此 B+Tree 索引能够承载的节点数是有限的。B+Tree 在更新节点是需要自排序和自平衡,这需要额外的性能消耗,B+Tree 的插入和删除时间复杂度是 O(log(N))。这就是为什么在使用数据库时不建议索引字段都添加索引,而是充分考虑具体情况,在需要的字段上添加索引,否则索引太多会影响表的insert\update\delete操作性能。

 

LSM
B+Tree 是基于页的索引引擎,B+Tree 的数据存储本身是无序的,其建立索引的思想是在内存中维护一个 key 与数据磁盘位置的对应关系,并保证这个内存数据结构有序。有一种基于文件的存储引擎,它将数据划分成文件段,并保证数据在磁盘文件段中有序,因此,这种存储引擎并不需要在内存中维护所有数据的顺序表,只需要在内存中维护一个稀疏的索引结构,每次从内存索引中搜索到的数据并不是具体到每条数据,而是一个文件段(或文件块),然后将这些有序的数据读入内存,再按序获取具体的数据。(如何保证写入数据有序?)

LSM(Log-Structured Merge-Tree),就是这样一种索引结构。LSM 的架构如所示:

数据库系统设计概述(下篇)-鸿蒙开发者社区

lsm

SSTable: LSM 的磁盘文件,称作SSTable(Sorted String Table)。望文得意,LSM 存储在磁盘中的文件,数据也是按 Key 排序存储的,这样就可以解决上面讲到的数据量大了之后无法将数据全部索引到内存中的问题。如果磁盘文件也是有序的,那么内存索引可以采取”稀疏索引“(Sparse Index),可以每一段记录一个索引,将数据逻辑上分成多个block,稀疏索引只需要记录每个block的偏移量,每条数据通过遍历block实现。这样索引量将大大减小。

Memtable: LSM 的内存结构叫做Memtable。Memtable是一个有序结构,同样可以采用树结构,可以用跳表。LSM 写数据时,只需要写入内存中的Memtable,当Memtable到达一定量之后,会异步刷入磁盘,就是上面的SSTable。

Immutable Memtable: 在数据从内存Memtable刷入SSTable时,为避免读写锁导致的性能问题,LSM 会在内存中 copy 一份immutable Memtable表,顾名思义,这个数据结构不可改变,新写入的数据只会写入新的Memtable,immutable Memtable供刷盘线程读取,查询数据的请求也可以访问这个数据结构,这样如果数据在内存中,就不需要访问磁盘,可以提供数据查询的效率。

WAL: write ahead log,预写日志,关于 WAL,可以参考我之前的文章👉《你常听说的 WAL 到底是什么》。在 LSM 中,在数据刷入磁盘前,为防止异常导致数据丢失,LSM 会先将数据写入 WAL,然后写入 SSTable,系统重启时,LSM 会从 WAL 中回溯 SSTable,当写完一个 SSTable 时,LSM 会清理掉过期的 WAL 日志,防止 WAL 过量。

LSM 如何写入数据:

  1. 写入 WAL
  2. 写入 Memtable
  3. Memtable 达到阈值时,复制 Imutable Memtable
  4. 异步刷入磁盘
    LSM 如何删除数据: 为保证顺序写磁盘,LSM 不会去直接删除数据,而是通过写一条 delete 标识来表示数据被删除,数据只有在被 Compact 时才会被真正删除。

LSM 如何读取数据: LSM 读取数据将从memtable、imutable、sstable依次读取,直到读取到数据或读完所有层次的数据结构返回无数据。所以当数据不存在时,需要依次读取各层文件。LSM 可以通过引入布隆过滤器来先判断一个数据是否存在,避免无效的扫文件。

密集索引(dense index) 和 稀疏索引(spare index):密集索引为每条数据对应一个索引记录,稀疏索引一般只索引数据块或文件,是跳跃式的。因此稀疏索引比密集索引更节省空间。

 

压缩
数据压缩对数据库系统中 I/O 性能的影响相当明显,它可以减少磁盘空间使用、降低带宽使用和提高吞吐量。数据库系统中的数据存储、索引存储、数据转换、数据备份和网络通信都会用到相应的压缩技术。当将数据库压缩引入实时数据库时。压缩算法必须提供高压缩比才能实现高数据存储,压缩算法必须足够快,才能在实时数据库中实现实时记录和查询功能。

压缩过程一般由两个独立的部分组成,建模和编码。建模定义输入流中不同符号的特征。模型存储有关符号在数据中出现的频率的信息,即符号概率。编码是压缩过程的第二部分,它根据模型提供的概率为不同符号创建一组代码,从而产生数据的压缩版本。将更频繁地出现的符号与较短的代码词和较长的稀有符号互换。数据的均匀性会影响大多数压缩算法的压缩比,但对压缩速度没有任何影响。因此,为了达到更好的压缩性能,压缩算法是专门为数据的每个部分设计的,因此不同的压缩算法对不同类型的,不同量级和不同组合的数据的压缩效果是不一致的。也因此大多数支持数据压缩的数据库系统都会提供多种不同的压缩算法让用户根据自身数据情况自由选择。

压缩算法可以分为以下两大类:

 ● 有损压缩:有损压缩会重构原始数据。所以读取的压缩后的数据是不完整的。这种压缩方式通常用在音频、视频等流文件的压缩中。
 ● 无损压缩:无损压缩不影响压缩数据的原始值。通常使用在文本,数字等数据的压缩中。
压缩应该考虑什么问题:

 ● 大小:压缩后的文件大小,即压缩比。当使用压缩时,本就是为了降低数据大小,所以压缩算法的压缩比是首要考虑的问题。
 ● 速度:压缩速度会影响数据的读写效率,这对实时系统来说尤为重要,速度和大小是 trade-off 的两面,必须充分考虑具体的使用场景。
 ● **资源:**压缩节省了磁盘和宽带,但是会增加 CPU 和压缩时的内存使用。所以压缩时的资源耗损情况也需要考虑。
下面列举一些常见的压缩算法或方法(Gzip、Bzip2、LZMA、XZ、LZ4、LZO),并做相应的对比:

测试条件:

 ● Intel Core i5 CPU 750 at 2.67GHz
 ● 8GB of DDR3 memory
 ● tmpfs as ram disk
 ● Linux kernel 3.3.2, gentoo amd64
 ● CFLAGS: -pipe -O2 -g -floop-block -floop-interchange -fgraphite
 ● bzip2-1.0.6-r3, xz-utils-5.0.3, gzip-1.4
文件压缩对比结果(原数据: 445M):

数据库系统设计概述(下篇)-鸿蒙开发者社区c-c

压缩比对比:

数据库系统设计概述(下篇)-鸿蒙开发者社区c-r

压缩耗时对比:

数据库系统设计概述(下篇)-鸿蒙开发者社区

各大数据库系统多多少少都会用到压缩技术来降低数据存储空间,来提高系统性能,以下列举一些数据库系统使用到的压缩技术:

 ● Google 在 BigTable 和 MapReduce 中使用 Snappy 压缩数据和网络传输。
 ● SQL Server 使用 XPRESS 算法压缩备份数据。
 ● Oracle 使用自实现的 Oracle Advanced Compression 算法压缩数据。
 ● MySQL 使用 LZ77 算法压缩 InnoDB 的表。
 ● Kafka 同时支持 gzip 和 snappy 和 lz4 算法,并对默认的 lz4 做了特定的优化。
 ● Druid 使用 lz4 压缩数据。


数值压缩:delta-of-delta
数值压缩经常用于压缩列式存储的数字列。前面我们讲到过,列式存储将每列的数据存储在相邻的位置。这样的存储结构利于压缩数据,下面我们讲一下在许多列式存储中使用的 Delta 数值压缩技术。

![delta of delta](https://magebyte.oss-cn-shenzhen.aliyuncs.com/databases/delta _of_delta.png)

如图所示,假设有 6 个原始数值(73、300、302、332、343、372)。在未压缩之前,每个数值占用 4 个字节,6 * 4 = 24 共占用 24 个字节。Delta 压缩算法不存储原始的数值,而是先确定一个数字(一般取第一个数值),后面的数值是相对于第一个数值的差值,如图第二行所示得到的数据集为(73、227、3、30、11、29)。因为最大的差值是 227,因此只需要一个 byte 就可以表示,因此之前需要使用 4 个字节存储的每个数值,现在只需要使用 1 个字节。为了保存对应的差值相关元描述信息,需要额外的 1 字节保存这些信息,上图还将数据分块存储,因此最终需要的字节数是 7 个。这样相对于原始的 24 字节节约了将近 3 倍的空间。

其实上图就是 Elasticsearch 底层使用 Lucence 的原理。

delta-of-delta 适用于数值类型数据的压缩,且对数据量大并且数据集中的数据压缩才有效果。如果数据集比较小,且比较稀疏,数据的最大差值已经和数据值可以表示的最大值相差不大,那么压缩的意思便存在。

 

读写
数据存储系统就是一个与磁盘和网络打交道的系统,所以数据存储系统在这方面的优化可谓精益求精,比如异步IO、缓冲批量读写、append写数据、按磁盘页读写数据,预读数据和磁盘内存映射技术等等。

 

异步
与异步 IO 对应的是同步 IO,即每进行一次 IO 操作,需要等待此次操作结束才能继续接下来的操作,这样在大量并发请求情况下,IO 的效率将会大大降低,磁盘 IO 和网络 IO 在并发量大的情况下采用异步 IO 可以明显提供效率。

Mysql 的 InnoDB 也采用 AIO 提高效率,InnoDB1.1.x 之前,AIO 的实现通过 InnoDB 存储引擎中的代码来模拟实现,从 InnoDB1.1.x 开始,提供了内核级别的 AIO 支持,称为 Native AIO。在 InnoDB 存储引擎中,read ahead 方式的读取都是通过 AIO 完成,脏页的刷新,即磁盘的写入操作则全部由 AIO 完成。

在 Kafka 中,Broker 的数据磁盘落地,都是采用的 Java NIO 的方式处理的,这是 Java 的异步 IO 的实现,Java NIO 可以提供数据写入的并发性能。

 

缓冲
缓冲技术是为了协调吞吐速度相差很大的设备之间数据传送而采用的技术。

数据库系统设计概述(下篇)-鸿蒙开发者社区

buffer

在数据到达与离去速度不匹配的地方,就应该使用缓冲技术。缓冲技术好比是一个水库,如果上游来的水太多,下游来不及排走,水库就起到“缓冲”作用,先让水在水库中停一些时候,等下游能继续排水,再把水送往下游。

将缓冲和批量发送结合,可以提高数据在在网络和磁盘中的写入速率。在数据写入网络或磁盘时,先设置一个缓冲池,当数据达到一定的数量或缓冲时间超时时,在将数据批量发送出去,可以减少请求并发,也可以减少请求额外数据带来的带宽和磁盘消耗。

在 Mysql 中,Innodb 在多个地方使用缓冲来提升写入性能。比如插入缓冲,将多个插入请求合并到一个操作中,这样可以将之前的一些非顺序写入变成相对的顺序写入,以提高写入效率。另一方面也可以按磁盘物理页写入数据,这样充分利用了磁盘的写入特性。

在 Elastisearch 和 Kafka 的客户端中,都采用了缓冲批量写入的功能来减少写入并发情况。

 

磁盘
在磁盘的读写优化上,经常可以看到以下技术:

 ● 按磁盘页读写数据:磁盘读写的单位是页。为了减少读写数据时磁盘访问频率,数据库系统通常都按页读写数据。
 ● 预读数据:一些数据库系统认为用户访问了一部分数据,那么在它相邻的放的数据下次被访问的可能性也很大,所以会预先读取多个页的数据。
 ● 磁盘内存映射(MMP):即盘扇区映射到进程的虚拟内存空间的过程。MMP 读写数据时跨过了页缓存,减少了数据的拷贝次数;实现了用户空间和内核空间的高效交互方式;可以缓解系统内存不足的压力。
本文对各种技术浅尝辄止,其实每一个技术点都可以深入讲解,感兴趣的同学请持续关注我们后期的文章。

推荐阅读

 

参考:

《Designing Data-Intensive Applications》
《Database Software Market:The Long-Awaited Shake-up》
《Distributed systems for fun and profit》
《How does a relational database work》
《七周七数据库》
《Mysql 技术内幕——InnoDB 存储引擎》
《数据库系统概念》
《Dynamo: Amazon's Highly Available Key-value Store》
http://arthurchiao.art/blog/amazon-dynamo-zh/
https://zhuanlan.zhihu.com/p/35622907
https://baike.baidu.com/
https://hbase.apache.org/
https://zh.wikipedia.org/
https://clickhouse.tech/
https://druid.apache.org/
https://www.elastic.co/

 

希望读者 「点赞」「分享」「在看」三连就是最大的鼓励。

 

 

文章转载自公众号:码哥字节

已于2022-8-4 15:21:20修改
收藏 1
回复
举报
回复
    相关推荐