1.线程模型简介
1.1 线程模型整体设计
Vastbase数据库是一个单进程多线程的数据库,客户端可以使用JDBC/ODBC/Libpq/Psycopg等驱动程序,向Vasbase的主线程(Postmaster)发起连接请求。
1.2 多线程设计的优势
- 优势一: 线程启动开销远小于进程启动开销。
与进程相比,它是一种非常“节俭”的多任务操作方式。
在linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种“昂贵”的多任务工作方式。
而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间。 - 优势二: 线程间方便的通信机制: 对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。
线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便。 - 优势三: 线程切换开销小于进程切换开销,对于linux系统来讲,进程切换分两步:
1.切换页目录以使用新的地址空间;
2.切换内核栈和硬件上下文。
对线程切换,第1步是不需要做的,第2步是进程和线程都要做的,所以明显线程切换开销小。
1.3 Vastbase进程
ps -ef |grep vastbase
查看进程一般是vasthome下的bin目录的vastbase。
1.4 Vastbase数据库请求处理过程
1.Vatsbase服务启动后创建Vastbase进程,该进程在服务器上注册数据库服务端口。
2.客户端使用IP+PORT连接Vastbase数据库并发送SQL请求。
3.后端线程接收客户端SQL请求并完成SQL的执行。
4.后端线程由一系列线程组成,这些线程各司其职,共同完成Vastbase中的各项任务。

1.5 Vastbase后端线程
将进程号代入,查看线程:
ps -T -p 20157


2.核心线程介绍
2.1 Postmaster线程
线程功能:
Postmaster线程是Vastbase第一个启动的线程。
Postmaster线程启动后负责内存结构、全局信息等资源的初始化。
Postmaster线程还会启动其他的Vastbase线程并且监控其他线程状态。
Postmaster线程作为Vastbase数据库主线程,循环接收客户端的请求(类似一种死循环的写法)。当客户端发送连接请求给Postmaster线程后,Postmaster线程会将SQL请求交给一个vastbase线程,由vastbase线程完成后续的任务。(Postmaster线程不处理请求,只负责监听。)
Postmaster线程角色:
- 1.全局管理线程。
- 2.其他线程的创建者与监控者。
- 2.客户端访问接口。
2.2 Vastbase线程
线程功能:
Vastbase线程接收Postmaster线程分配的客户端请求,Postmaster线程会将客户端请求SQL交给Vastbase线程,Vastbase线程接收到Postmaster发送过来的查询SQL后,会使用Vastbase的SQL引擎对SQL语句进行词法解析、语法解析、语义解析、查询重写等处理操作,然后使用查询优化器生成最小代价的查询路径计划。SQL执行器会按照已制定的最优执行计划对SQL语句进行执行,并将执行结果反馈给客户端。

2.3 BgWriter&PageWriter
线程功能:
BgWriter&PageWriter线程的功能是将缓冲区中的脏页数局写入磁盘。
脏页从缓冲区落盘到Vastbase数据库需要PageWriter和BgWriter两个线程,操作系统数据块大小一般是4k,数据库-般是8k/16k/32k,Vastbase页默认是8kb,这样就有可能造成页面断裂问题,一个数据库数据块刷到操作系统的过程中可能发生因宕机而造成块损坏从而导致数据库无法启动的问题。
Pagewriter线程负责将脏页数据拷贝至双写(doublewriter)区域并落盘,然后将脏页转发给Bgwriter子线程进行数据落盘操作(从双写区拷贝),这样可以防止该现象的发生,因为如果发生数据页”折断”的问题,就会从双写空间里找到完整的数据页进行恢复。
在开启了增量检查点的情况下(小批量刷盘),Vastbase默认开启,Pagewriter 线程组负责执行增量检查点的主要工作,也就是Pagewriter线程完成脏页从缓存到落盘的过程,Bgwriter将不再参与缓存落盘任务,Pagewriter会启动包含一个主线程(main pagewriter)和多个子线程(sub pagewriter)的持续小批量的完成脏页从缓存到磁盘的数据持久化操作。
Pagewriter会在周期性的触发完成脏页落盘操作,也就是在间隔一定时间触发一次,触发后脏页持久化存储,这样的设计使得Vastbase处于连续低IO负荷运行,提升vastbase运行性能。
线程工作原理:

线程相关参数:
- pagewriter_sleep: 控制后端写线程pagewriter刷页频率。
- bgwriterk_delay: 控制后端写线程bgwriter刷页频率。
- bgwriter_lru_maxpages: 设置后台能够多写入的脏页数。
- max_io_capacity: pagewriter线程和bgwriter线程批量刷页每秒的I/O上限。
- dirty_page_percent max: 脏页数量占shared buffers的百分比。达到这个设定值时,后台刷页线程将以设置的max_io_capacity计算出的最大值刷脏页。
2.4 Walwriter线程
线程功能:
Walwriter线程是Vastbase的预写日志写线程。
Walwriter日志写线程在Vastbase中负责将内存中的预写日志(WAL)页数据刷新到预写日志文件中,确保那些已提交的事务都被永久记录,不会丢失。
预写日志(WAL)和主流数据库中常见的重做日志功能类似,里面记录了Vastbase数据文件的变更操作,数据库在执行SQL操作时会先将这些变更操作记录在预写日志文件中,也就在SQL更新数据提交后,日志写线程将内存中的预写日志缓存写入预写日志文件,保障提交后的数据不丢失,即使系统调研宕机,Vastbase重启后也会读取已经落盘持久化的数据进行数据Recovery,提交后的脏页数据至由PageWriter& Bgwriter线程定期写入数据文件中,这样的设计可以让IO资源平均分配。
Walwriter作为保证数据库数据持久性和完整性的核心线程,Walwriter日志写线程在Postmaster线程启动后就会启动,当这个线程的刷盘频率无法满足系统需求时,其他常规的后端线程仍然有权限执行预写日志页的刷盘操作。如果Walweriter日志写线程意外崩溃,则Postmaster线程会认为整个Vastbase后端线程崩溃,此时将调用SIGQUIT强制关闭所有后端线程,重置共享内存以恢复后端线程。
线程工作原理:

线程相关参数:
- wal_writer_delay: WalWriter线程的写间隔时间。(不推荐)
- commit_delay: 表示一个已经提交的认值为0,也就是事务提交后立即写入WAL数据在 WAL缓冲区中存放的时间,默日志文件。Vastbase默认设置commitdelay值为0目的就是让事务提交后立即触发Walwriter线程将事务变更写入预写日志持久化落盘,这种方式避免了已提交事务的数据丢失,保证数据完整性,这个参数在实际情况下需要保证配置为0,无特殊情况,不能修改。
2.5 Checkpointer线程
线程功能:
Checkpointer是Vastbase检查点线程。
Checkpointer检查点线程会周期性的发起数据库检査点,检査点(CHECKPOINT)是一个事务日志中的点,所有数据文件都在这个点被更新,然后将数据脏页刷新到磁盘的数据文件中,确保数据库一致,也就是在检查点(CHECKPOINT)触发时,在这个LSN之前所有的缓存中的脏页都会全部写入磁盘持久化。当数据库从崩溃状态恢复后,已经做过checkpoint的更改就不再需要从预写日志中恢复,这大大加快了数据库系统crash后的恢复速度,Vastbase的检査点有全量检査点和增量检査点。增量检査点开关打开的时候将不再使用full-page_writes防止页面折断,而是依赖双(double-writer)特性保护,当增量检査点打开后会小批量分阶段的滚筒式进行脏页刷盘,同时更新lsn信息,回收不需要的xlog日志。
Checkpointer线程周期性触发,手动触发,Wal日志保存到达阈值后也会触发,开关机也能够触发Checkpointer线程。
线程相关参数:
- checkpoint_timeout: 设置自动 WAL检查点之间的最长时间,这个参数配置两个检查点之间的间隔,在Vastbase中默认的参数是15min。
- checkpoint_segments:设置checkpoint_timeout周期内所保留的最少WAL日志段文件数量。
2.6 Statcollector线程
线程功能:
StatColector统计线程在Vastbase数据库负责统计Vastbase数据库的信息,这些信息包括:物理硬件资源使用信息对象属性及使用信息、SQL运行信息、会话信息、锁信息、线程信息等,并且将这些收集到的统计信息保存在pgstat.stat文件中。这些统计信息对于查询优化器(QueryPlanner)的决策、性能监控和维护任务至关重要,也会被用来做性能分析、故障分析、健康检查和状态监控等。
Statcollector会收集数据库系统运行中的统计数据,如在一个表和索引上进行了多少次插入与更新操作、磁盘块的数量和元组的数量、每个表上最近一次执行清理和分析操作的时间等,
线程相关参数:
- track_counts:控制收集数据库活动的统计数据,数据变更等,默认值on。
- track_activities:控制收集每个会话中当前正在执行命令的统计数据,执行命令,等待事件等,默认值on。
2.7 AutoVacLauncher& AutoVacWorker线程
线程功能:
AutoVacLauncher& AutoVacWorker:Vastbase数据库清理线程。
Vatsbase默认使用MVCC(Multi-Version Concurrency Control)来保证事务的原子性和隔离性。
在Vastbase的MVCC机制中数据库的更新和删除记录实际不会被立即删除并释放存储空间,而是标记为历史快照版本,Vastbase使用MVCC机制和这些历史快照实现数据的读写不冲突。
但是这样会使得操作频繁的表积累大量的过期数据,占用磁盘空间,当扫描查询数据时,需要更多的IO消耗,降低查询效率。所以需要一个线程对这些过期数据进行清理,并回收存储空间。Autovacuum操作相关的线程就是这个后台清理线程,负责回收表或B-Tree索引中已经删除的行所占据的存储空间,这个线程也是由一个发起线程和一个执行线程组成,在Vastbase中分别被命名为AutoVacLauncher和AutoVacWorker。
AutoVacLauncher监控进程,维护一个AutoVacWorker线程列表,用来监控AutoVacWorker的运行状态,并调度Autovacuum操作到AutoVacWorker线程上去。
AutoVacWorker由Postmaster生成,AutoVacWorker线程程在启动之后遍历数据库中所有的表,按照表清理规则对表进行vacuum和analyze操作。
线程相关参数:
- autovacuum: 控制数据库自动清理线程(autovacuum)的启动,默认值on。
- autovacuum_max_workers: 设置能同时云行的自动清理线程的最大数量,也就是Vastbase启动AutoVac*线程的最大数量,默认值为3。
- autovacuum_naptime: 设置两次自动清里操作的时间间隔,默认值20s。
- autovacuum_vacuum_threshold: 设置触发VACUUM的阈值。当表上被删除或更新的记录数超过设定的阈值时才会对这个表执行VACUUM操作。
- autovacuum_analyze threshold:ANALYZE操作的阈值。当表上被删除、插设置插入或更新的记录数超过设定的阈值时才会对这个表执行ANALYZE操作。
2.8 WalSender & WalReceiver线程
线程功能:
WalSender & WalReceiver线程主要负责Wal日志的发送与接收。
WalSender& WalReceiver线程只在开启了主从复制的Vatsbase数据店启动,Walsender线程启动在复制主机上,WalReceiver启动在主从复制的数据库备机上。
Walsender 工作流:


线程相关参数:
max_wal senders: 指定事务日志发送进程的并发连接最大数量。
wal_sender_timeout: 设置本端等待事务日志接收端接收日志的最大等待时间,默认6s。
wal_receiver_timeout: 设置从主机接收数据的最大等待时间,默认6s。
wal_receiver_connect_timeout: 设置连接主机的最大等待超时时间,默认2s。
3.线程架构设计

注:图中应为双向箭头