暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

Halo数据库的体系结构看这一篇就够了

贾桂权 2024-10-08
682

前⾔:

 在任何数据库的学习中,如果想深⼊的理解⼀种数据库系统,对于体系结构的理解和掌握都是重中 之重,本篇开始为⼤家正式开始HaloDB的体系结构介绍。

⼀、HaloDB的体系结构:

如下图1-1所⽰,Halo数据库的体系结构。数据库实例主要包含共享内存区域、本地内存区域和⼀系 列后台进程。其中共享内存区域主要由共享缓存、事务⽇志缓存构成。后台进程主要由Background Writer(数据写进程)、WALWriter(事务⽇志写进程)、Checkpointer(检查点进程)、Statistic Collector(统计信息收集进程)、Autovacuum(⾃动清理进程)等构成。数据库群集主要由数据⽂ 件、事务⽇志⽂件及其它⼀些辅助⽂件组成。


1、HaloDB中的共享内存区域和本地内存区域:

在我们的HaloDB中,内存架构部分主要分为,本地内存区域(LocalMemoryArea)和共享内存区域 (SharedMemoryArea)两个部分,下⾯针对每个部分做详细的说明; a.本地内存区域(LocalMemoryArea):本地内存区域是每个后台进程(BackendProcess)独⽴ 使⽤的内存空间。每个后台进程都有⾃⼰的本地内存区域,⽤于存储会话相关的数据和临时数据。本 地内存区域包括以下⼏个重要的组件:

栈(Stack):⽤于存储函数调⽤和局部变量等信息。

上下⽂(Context):⽤于管理内存分配和释放,每个上下⽂都有⼀个⽗上下⽂,形成⼀个层次结 构。

缓冲区(Buffer):⽤于存储查询结果集的数据,以及排序和哈希操作的中间结果。

连接信息(ConnectionInformation):⽤于存储与客⼾端连接相关的信息,如会话状态、权限等。

b.共享内存区域(SharedMemoryArea):共享内存区域是多个后台进程共享的内存空间,⽤于存储全局数据和缓存数据,以提⾼性能和效率。共享内存区域包括以下⼏个重要的组件:

缓冲池(BufferPool):⽤于缓存磁盘上的数据⻚,减少磁盘访问次数。

内存上下⽂(MemoryContext):⽤于管理共享内存的分配和释放。

后台进程信息(BackendProcessInformation):⽤于存储后台进程的状态和信息。

锁表(LockTable):⽤于管理并发访问的锁信息。

WAL(Write-AheadLogging)缓冲区:⽤于存储事务⽇志的中间结果。

• 共享内存区域的⼤⼩是在启动HaloDB时配置的,可以根据系统的硬件资源和负载情况进⾏调整。 本地内存区域的⼤⼩则由每个后台进程独⽴管理,通常受到系统的内存限制。


HaloDB的后台进程

后台进程:

1、BackgroundWriter(数据写进程):

主要作⽤:后台写进程负责将脏数据⻚(DirtyBuffer)从共享缓冲池(SharedBuffer)异步写⼊ 磁盘,以减少磁盘写⼊的频率。它根据⼀定的策略来选择需要写⼊的数据⻚,并通过延迟写⼊ (DelayedWrite)机制来提⾼性能。

 BackgroundWriter(数据写进程)⼯作过程如下:

a.监控脏数据⻚:BackgroundWriter定期扫描数据库缓冲区,监控其中的脏数据⻚。脏数据⻚是指 已经被修改但尚未写⼊磁盘的数据⻚。

b.决定写⼊时机:BackgroundWriter根据⼀定的策略决定何时将脏数据⻚写⼊磁盘。这个策略通常 基于缓冲区的使⽤情况、脏数据⻚的数量和系统负载等因素。

c.异步写⼊数据:⼀旦决定将脏数据⻚写⼊磁盘,BackgroundWriter将这些数据异步地写⼊磁盘,⽽不是等待前台进程需要这些数据时再写⼊。这样可以减轻前台进程的写⼊压⼒,提⾼数据库的性能。

d.更新元数据:BackgroundWriter在写⼊数据的同时,还会更新相关的元数据信息,包括系统表中 的数据库统计信息。这些统计信息⽤于查询优化器,以帮助⽣成更有效的查询计划。 通过执⾏这些操作,BackgroundWriter减轻了前台进程的写⼊压⼒,提⾼了数据库的性能和响应能 ⼒。它异步地将脏数据⻚写⼊磁盘,并更新相关的元数据信息,以保证数据的⼀致性和持久性。同 时,BackgroundWriter的⼯作是基于⼀定的策略,以适应不同的系统负载和数据库使⽤情况。

 简单画了⼀个BackgroundWriter的⼯作流程图如下,⽅便各位理解


2、WALWriter(事务⽇志写进程):

主要作⽤:

  WAL写进程负责将事务⽇志(Write-AheadLog)从共享内存区域异步写⼊磁盘。它将事务的修改操作记录到事务⽇志中,以保证数据库的持久性和恢复能⼒。WAL写进程通过批量写⼊和延迟写⼊等 技术来提⾼性能。

WALWriter⼯作过程如下:

a.监控WAL缓冲区:WALWriter定期扫描WAL缓冲区,监控其中的WAL⽇志条⽬。WAL缓冲区是⼀个 内存区域,⽤于暂存事务⽇志。

b.决定写⼊时机:WALWriter根据⼀定的策略决定何时将WAL⽇志条⽬写⼊磁盘。这个策略通常基于 WAL缓冲区的使⽤情况、WAL⽇志条⽬的数量和系统负载等因素。

c.异步写⼊⽇志:⼀旦决定将WAL⽇志条⽬写⼊磁盘,WALWriter将这些⽇志条⽬异步地写⼊磁盘, ⽽不是等待事务提交时再写⼊。这样可以提⾼数据库的性能,因为事务提交时不需要等待⽇志写⼊完 成。

d.更新WAL位置:WALWriter在写⼊⽇志的同时,还会更新WAL位置(WALLSN)。WAL位置是⼀个 递增的标识符,⽤于记录已经写⼊磁盘的WAL⽇志的位置。这个位置信息对于数据库的恢复和故障恢 复⾮常重要。

通过执⾏上述的操作,WALWriter确保了事务⽇志的持久性和⼀致性。

简单画了⼀个WALWriter的⼯作流程图如下,⽅便各位理解


3、Checkpointer(检查点进程):

主要作⽤:

a.触发检查点:Checkpointer定期触发检查点操作,以将内存中的数据写⼊磁盘。检查点的触发可以 基于时间间隔、⽇志⼤⼩或其他策略来确定。

b.写⼊脏⻚:⼀旦检查点被触发,Checkpointer开始将脏⻚(已被修改但尚未写⼊磁盘)写⼊磁盘。 脏⻚是指在内存中已被修改的数据⻚。

c.停⽌写⼊:在开始写⼊脏⻚之前,Checkpointer会通知其他进程停⽌向磁盘写⼊新的脏⻚。这是为 了确保在检查点期间不会有新的修改被写⼊磁盘,以保持⼀致性。

d.写⼊过程:Checkpointer按照⼀定的顺序将脏⻚写⼊磁盘。在HaloDB中,Checkpointer使⽤了⼀ 种称为"Write-AheadLogging"(WAL)的机制。它将脏⻚的修改操作写⼊到WAL⽇志⽂件中,然后再 将脏⻚本⾝写⼊磁盘。这种⽅式可以提⾼写⼊的效率和可靠性。

e.更新检查点位置:在写⼊完成后,Checkpointer会更新检查点位置,以记录已经完成的检查点。这 样,在系统恢复时,可以根据检查点位置来确定从哪⾥开始进⾏恢复操作。

f.恢复写⼊:⼀旦检查点完成并且检查点位置被更新,Checkpointer会通知其他进程可以继续向磁盘 写⼊新的脏⻚。

此外:

在我们的HaloDB中,Checkpointer还有⼀些额外的⼯作:

a.⾃适应检查点:HaloDB的Checkpointer会根据系统的负载情况和性能指标来⾃动调整检查点的触 发频率,以平衡写⼊性能和系统负载。

b.后台写⼊:HaloDB的Checkpointer可以与其他后台进程(如BackgroundWriter)协同⼯作,以 提⾼写⼊的效率和并发性。

通过Checkpointer的⼯作,HaloDB数据库可以保证数据的持久性和⼀致性。它定期将内存中的数据写 ⼊磁盘,并使⽤WAL机制来确保写⼊的可靠性。这样,在系统故障或崩溃时,可以通过检查点位置和 WAL⽇志来进⾏数据恢复和⼀致性保证。


4、StatisticCollector(统计信息收集进程):

主要作⽤:

StatisticCollector(统计信息收集进程)是PostgreSQL数据库中的⼀个重要组件,它负责收集和更新 数据库对象的统计信息,以供查询优化器使⽤。

a.⽬的:StatisticCollector的主要⽬的是收集和维护数据库对象的统计信息,包括表、索引、列等。 这些统计信息对于查询优化器来说⾮常重要,它们帮助优化器选择最佳的查询计划,提⾼查询性能。

b.统计信息类型:StatisticCollector收集的统计信息包括⾏数、唯⼀值数量、空值数量、最⼩值、最 ⼤值等。这些信息可以帮助优化器估计查询的选择性和数据分布情况。

c.统计信息更新:StatisticCollector会定期扫描数据库对象,收集最新的统计信息。它会根据配置的 参数(如autovacuum参数)来确定统计信息更新的频率和⽅式。通常情况下,当表或索引的数据发⽣ 变化时,StatisticCollector会⾃动触发统计信息的更新。

d.统计信息存储:StatisticCollector将收集到的统计信息存储在系统表pg_statistic和 pg_statistic_ext中。这些表包含了每个数据库对象的详细统计信息,以及⼀些全局统计信息。

e.查询优化器使⽤:查询优化器在⽣成查询计划时会使⽤StatisticCollector收集的统计信息。通过分 析统计信息,优化器可以选择最佳的索引、连接顺序和操作符等,以提⾼查询性能。

f.配置参数:在PostgreSQL的配置⽂件中,可以通过⼀些参数来控制StatisticCollector的⾏为,如 autovacuum参数⽤于控制统计信息的⾃动更新频率。

 总之,StatisticCollector是PostgreSQL数据库中负责收集和维护统计信息的重要组件。它通过定期扫 描数据库对象,收集最新的统计信息,并存储在系统表中。这些统计信息对于查询优化器来说⾮常重 要,它们帮助优化器选择最佳的查询计划,提⾼查询性能。

⼯作过程如下:

a.启动:StatisticCollector在PostgreSQL数据库启动时⾃动启动,并在后台运⾏。

b.扫描对象:StatisticCollector会定期扫描数据库中的表、索引和列等对象,以收集它们的统计信 息。扫描的频率和⽅式可以通过配置参数进⾏调整。

c.统计信息收集:当StatisticCollector扫描到⼀个对象时,它会收集该对象的统计信息。这些统计信 息包括⾏数、唯⼀值数量、空值数量、最⼩值、最⼤值等。

d.统计信息更新:StatisticCollector会将收集到的统计信息与已有的统计信息进⾏⽐较,并根据⼀定 的算法和策略来更新统计信息。通常情况下,当表或索引的数据发⽣变化时,StatisticCollector会⾃ 动触发统计信息的更新。

e.统计信息存储:StatisticCollector将更新后的统计信息存储在系统表pg_statistic和 pg_statistic_ext中。这些表包含了每个数据库对象的详细统计信息,以及⼀些全局统计信息。

f.查询优化器使⽤:查询优化器在⽣成查询计划时会使⽤StatisticCollector收集的统计信息。通过分 析统计信息,优化器可以选择最佳的索引、连接顺序和操作符等,以提⾼查询性能。

g.⾃动更新:StatisticCollector可以根据配置参数(如autovacuum参数)来确定统计信息的⾃动更 新频率和⽅式。这样可以确保统计信息始终与实际数据保持⼀致。

5、Autovacuum(⾃动清理进程):

主要作⽤:

  HaloDB中的Autovacuum(⾃动清理进程)是⼀个重要的后台进程,负责⾃动管理表的清理和维护 ⼯作。

⼯作内容如下:

a.清理过期⾏:Autovacuum会检查表中的过期⾏(已被标记为删除但尚未被实际清理的⾏),并将 其删除。这有助于回收磁盘空间,并提⾼查询性能。

b.合并碎⽚化的⻚⾯:当表中的⾏被删除时,可能会导致⻚⾯碎⽚化。Autovacuum会合并碎⽚化的 ⻚⾯,以减少磁盘访问和提⾼查询性能。

c.更新统计信息:统计信息对于查询优化器的性能决策⾮常重要。Autovacuum会更新表的统计信 息,以确保查询优化器能够做出准确的执⾏计划。

d.⾃动分析:Autovacuum还负责⾃动分析表的统计信息。它会检查表的更新频率和配置参数,判断 是否需要进⾏⾃动分析。⾃动分析将收集表的统计信息,以便查询优化器能够做出更好的执⾏计划。

e.配置参数:PG数据库提供了⼀些配置参数,⽤于控制Autovacuum的⾏为。这些参数包括⾃动清理 的阈值、⾃动分析的频率、并发清理的并发度等。管理员可以根据实际需求进⾏配置。

f.⾃动触发:Autovacuum会根据表的更新情况和配置参数⾃动触发清理和分析操作。它会根据表的更 新频率、删除操作、空闲空间等因素来判断是否需要执⾏⾃动操作。

g.⼿动触发:除了⾃动触发,管理员也可以⼿动触发Autovacuum操作。这可以通过执⾏VACUUM、 ANALYZE或VACUUMANALYZE语句来实现。

h.进程调度:PG数据库可以同时运⾏多个Autovacuum进程,以处理多个表的清理和维护⼯作。进程 调度器会根据系统负载和配置参数来决定启动和停⽌Autovacuum进程。


⼆、HaloDB的物理结构:

在HaloDB中,软件的安装⽬录是在/u01/app/halo/product/dbms/14⽬录下。⼀般⽤环境变量 HALO_HOME作为数据库软件安装的根⽬录。数据⽂件存放位置则根据环境变量HALOHOME来⾃定义 指定。

 ⽬录的初始化在pg_ctlinit-D/data/halo动作完成后,数据⽬录会⽣成若⼲配置⽂件,如下所⽰:


下⾯针对这些配置⽂件,做些简单的说明:

postgresql.conf:HaloDB的主配置⽂件,基本所有的参数配置均在此⽂件中。

postgresql.auto.conf:HaloDB的附加配置⽂件,使⽤后altersystem修改的配置存储在该⽂件中。

pg_hba.conf:HaloDB数据库的认证配置⽂件。

pg_ident.conf:ident认证⽅式的⽤⼾映射⽂件。

postmaster.opts:记录服务器上次启动的命令⾏参数,此⽬录下还会⽣成若⼲的⼦⽬录。


1、数据存储结构:

在Halo数据库中,数据库群集是⼀组数据库的集合。每个数据库⼜是⼀组对象的集合。详细的架构 图如下图所⽰:


在Halo数据库体系中,数据库群集(DatabaseCluster)类似⼀个容器,在该容器内可以创建多个独 ⽴的数据库,分别对应不同的系统,即多租⼾。数据库群集初始化后,会创建3个默认的数据库: halo0root、template1和template0。

halo0root:管理库,群集管理使⽤,请不要删除。

template1:正如其名称所⽰,这是⼀个模板库,后⾯通过CREATE DATABASE命令创建的库默认 都以它为模板进⾏创建。

template0:也是⼀个模板库。和template1的区别在于,通过template1创建的库部分库属性, 如字符集是⽆法更改的。⽽通过template0就可以。 上图所述表空间所存放的物理位置放置在$HALODATA/base⽬录下,该⽬录下的存放很以OID命名的⽂ 件夹,就是该集簇下数据库存放的物理位置。接下来我们看下具体例⼦: 查询⽬前HaloDB中现有的数据库

halo0root=\l

List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges

-----------+-------+----------+-------------+-------------+------------------

halo0root | halo | UTF8 | en_US.UTF-8 | en_US.UTF-8 | halozz1 | halo | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/halo

template0 | halo | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/halo +| | | | | halo=CTc/halo

template1 | halo | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/halo +| | | | | halo=CTc/halo

testzz | halo | UTF8 | en_US.UTF-8 | en_US.UTF-8 |

(5 rows)

 

查询每个数据库所对应的OID号码

halo0root=# select oid,datname from pg_database; oid | datname

-------+-----------

14509 | halo0root

 1 | template1

 14508 | template0

 16385 | testzz

 24987 | halozz1

(5 rows)

进⼊到物理存储位置:


如上图所⽰,14509所对应的halo0root模板库的OID为14509跟物理路径下的⽂件夹名称是⼀⼀对 应关系,该⽂件下下存放该库的表,索引等数据⽂件。图1-2描述了这种关系。其中,表的数据⽂件 内部⼜被划分为固定⻓度的⻚(Page),通常为8KB。每个⽂件中的⻚从0开始按顺序编号,该编号 即为⻚号。⻚通常⼜被划分为⻚头和数据,即PageLayout中的内容。数据按⾏(Row)进⾏存储, 每⼀⾏⼜被划分为⾏头和实际数据,即RowLayout中的内容。索引的布局与表的布局类似。

2、HaloDB数据库内核架构:

HaloDB数据库的核⼼设计思想是插件式内核,这也是Halo数据库的⼀个最显著的特性。


图1-3描述了Halo数据库实例的主要成分。通过插件式内核的设计,可以⾮常灵活的实现多种协 议的兼容、多种语法的兼容、以及分布式存储引擎(HFSX,发展中技术)的⽀持等,这个重要特性也 是Halo能够称之为新⼀代统⼀数据库的重要原因。如果有对内核层⾯感兴趣的朋友,可以考虑加⼊我 们公司进⾏深⼊的学习和体验。

三、HaloDB的逻辑架构:

说到逻辑结构,确实对新⼿来说理解起来有⼀些的难度,来话不多说,直接上图。


1、数据库集簇(Databasecluster):

它是指有单个HaloDB服务器实例管理的数据库集合,组成数据库集群的这些数据库使⽤相同的全 局配置⽂件和监听端⼝、共⽤进程和内存结构。⼀个DataBaseCluster可以包括:多个DataBase、多 个User、以及Database中的所有对象。如上图所⽰。

2、数据库(Database):

在HaloDB中,数据库本⾝也是数据库对象,并且在逻辑上彼此分离,除数据库之外的其他数据库 对象(例如:表、索引等等)都属于他们各⾃的数据库。

3、表空间(tablespace):

在HaloDB中,数据库在逻辑上分成多个存储单元,称作表空间。表空间⽤作把逻辑上相关的结构 放在⼀起。数据库逻辑上是由⼀个或多个表空间组成。初始化的时候,会⾃动创建pg_default和 pg_global两个表空间。

 

halo0root=# \db

 List of tablespaces Name | Owner | Location

------------+-------+-----------

halozz_tbs | halo | /data/tbs ###⾃⾏创建的表空间,⾮默认

pg_default | halo |

pg_global | halo |

(3 rows)

创建表空间的语句可以参考如下:

halo0root=# create tablespace 表空间名称 location '所创建表空间的物理路径';

4、模式(Schema):

在HaloDB中,当创建⼀个数据库时,会为其创建⼀个名为public的默认Schema。Schema是数 据库中的命名空间,在数据库中创建的所有对象都是在Schema中创建,⼀个⽤⼾可以从同⼀个客⼾端 连接中访问不同的Schema。⽽不同的Schema中可以有多个同名的Table、Index、View、 Sequence、Function等等数据库对象。可以通过下⾯的⽅式来查看当前数据库的Schema:

halo0root=# \dn

List of schemas Name | Owner

--------+-------

public | halo

sys | halo

(2 rows)

5、段(segment):

在HaloDB中,⼀个段是分配给⼀个逻辑结构(⼀个表、⼀个索引或其他对象)的⼀组区,是数据 库对象使⽤的空间的集合;段可以有表段、索引段、回滚段、临时段和⾼速缓存段等。

6、区(extent):

在HaloDB中,区是数据库存储空间分配的⼀个逻辑单位,它由连续数据块所组成。第⼀个段是由 ⼀个或多个盘区组成。当⼀段中间所有空间已完全使⽤,为该段分配⼀个新的范围。

7、块-block(Page):

数据块是HaloDB管理数据⽂件中存储空间的单位,为数据库使⽤的I/O的最⼩单位,是最⼩的逻 辑部件。默认值8K。

halo0root=# SHOW block_size;

block_size

------------

8192

(1 row)

8、数据库对象(Databaseobject):

在HaloDB中的所有数据库对象⽐如表、视图、索引、序列、函数都由各⾃的对象标识符(OID) 进⾏内部的管理。例如,数据库的OID存储在pg_database系统表中,可以通过下⾯的语句进⾏查询。

testzz=# select oid,relname,relkind,relfilenode from pg_class where relname ='emp';

oid | relname | relkind | relfilenode

-------+---------+---------+-------------

16391 | emp | r | 16391

(1 row)

⽽数据库中的表、索引、序列等数据库对象的OID则存在了pg_class系统表中,例如可以通过下⾯ 的语句查询前⾯创建的表的OID。

testzz=select oid,relname,relkind,relfilenode from pg_class where relname ='emp';

oid | relname | relkind | relfilenode

-------+---------+---------+-------------

16391 | emp | r | 16391

(1 row)

⼩tips:pg_database,pg_class这两个视图真的很常⽤,请务必熟悉~

 

最后:

请大家持续关注Halo数据库,如需试用请直接联系我们。

 

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论