写点什么

解锁数据库运维秘籍:掌握 AntDB-T 动态共享内存,提升进程间通信效率

  • 2023-11-21
    浙江
  • 本文字数:4248 字

    阅读完需:约 14 分钟

动态共享内存是 AntDB 数据库通信的重要手段,本文主要阐述 AntDB-T 数据库动态共享内存的实现原理、实现方式与使用方法。


AntDB-T 数据库是一款企业级通用分布式关系型数据库,其数据库内核是基于进程模型实现的,因此进程间通信(IPC)是实现分布式架构间进行任务协作和数据共享的关键。

实现进程间通信的方式有多种,例如管道、消息队列、信号量、共享内存等。在程序运行过程中,AntDB-T 数据库为了实现进程之间更高效的通信和数据传输,采用了共享内存的方式。例如,AntDB-T 数据库在并发任务需要创建多个工作进程的情况下,工作进程与后端进程之间的通信和数据传输将通过动态创建的共享内存来实现。       


(一)AntDB-T 动态共享内存实现原理

那接下来本部分内容就为各位小伙伴慢慢解析 AntDB-T 数据库动态共享内存的原理。


AntDB-T 动态共享内存是什么    

动态共享内存(dynamic shared memory):简称 DSM,在数据库运行期间可以动态创建出来的共享内存,动态共享内存允许 AntDB-T 在运行时动态地分配和释放内存,从而提高系统的性能和可伸缩性。


 AntDB-T 中动态共享内存实现方式            

在 AntDB-T 中动态共享内存的实现方式有多种,由 dynamic_shared_memory_type 参数控制,默认是 posix 是指使用 shm_open 分配的 POSIX shared memory。


图 1:dynamic_shared_memory_type 配置参数


dynamic_shared_memory_type 参数定义如下表:

启用动态内存共享之后,当 AntDB-T 数据库启动后会在/dev/shm 目录下有所体现,关了 AntDB-T 数据库之后,这些文件就没有了:


图 2:AntDB-T 数据库启动后/dev/shm 目录情况


图 3:AntDB-T 数据库关闭后/dev/shm 目录情况


AntDB-T 为什么要引入动态共享内存

动态共享内存可以在运行时动态地分配和释放内存,从而使得内存管理更加灵活和高效,并且动态共享内存还可以实现延迟初始化(lazy initialization)和重新配置(reconfiguration)等特性,从而提高了系统的性能和可伸缩性。


在实际 AntDB-T 数据库中,动态共享内存在很多地方会用到,举个例子比如动态共享内存在并行中会用到,因为对于并行查询而言,执行时创建的 DN worker 进程与 DN leader 进程通过共享内存实现数据交互。但这部分内存无法像普通的共享内存那样在系统启动时预先分配,毕竟直到真正执行时才知道有多少 DN worker 进程,以及需要分配多少内存。动态共享内存,即在执行时动态创建,用于 DN leader 与 DN worker 间通信,执行完成后释放。    


(二)AntDB-T 动态共享内存实现方式

下面将针对动态共享内存机制进行源码说明。本次以 AntDB-T 的代码为例,来解析动态共享内存的实现方式。

在 AntDB-T 源码中,dsm.c、dsm_impl.c 文件提供了动态共享内存的功能,实现了共享内存的动态申请和释放。动态共享内存通过一个 handle(typedef uint32 dsm_handle;)与一块内存进行映射,这个 handle 是一个 32 位无符号整数。在创建动态共享内存时,需要指定一个 handle 作为标识符,而访问动态共享内存时也是通过这个 handle 进行访问。不同进程之间通过传递 handle 来告知对方动态共享内存的位置,其他进程则通过 handle 来访问该动态共享内存。       


1.基础数据结构

dsm_control_header 和 dsm_control_item 是动态共享内存里最基础的 2 个数据结构。定义如下图所示:    

图 4:dsm_control_header 和 dsm_control_item 数据结构


dsm_control_header 是动态共享内存的控制结构头,dsm_control_item 记录每个分配的动态共享内存的状态,字段 nitems 表示动态共享内存当前已经使用的数量,字段 maxitems 表示动态共享内存的最大数量,字段 refcnt 表示 /* 2+ = active, 1 = moribund, 0 = gone */,字段 impl_private_pm_handle 表示仅在 Windows 上需要,字段 pinned 表示是否固定动态共享内存段,dsm_handle 表示动态共享内存段的名字。

dsm_segment 表示申请的一个共享内存段,对于动态共享内存的 api 来说这是代表共享内存的最小单位,定义如下图所示:

图 5:dsm_segment 数据结构    


每个后端进程都可以通过使用 dsm_segment 来访问共享内存,dsm_segment 包含了内存分配和释放等操作所需的信息,并提供了一组函数来管理和操作共享内存,每个会话(session)可以有一个或多个 dsm_segment。其中字段 mapped_address 代表需要返回的当前映射共享内存的起始地址,字段 resowner 表示该动态共享内存段资源所有者,control_slot 表示在控制动态共享内存段(dsm_control_header)里面的第几个 item。   

  

2.初始化 AntDB-T 动态共享内存(DSM)

在 postmaster 主进程启动时,调用 dsm_postmaster_startup(PGShmemHeader *shim)函数,进行动态共享内存相关的初始化,其主要逻辑如下:


 1)计算 dsm_control 结构所需要的内存大小:

1>计算所需共享内存的最大数量 maxitems,

maxitems=PG_DYNSHMEM_FIXED_SLOTS+ PG_DYNSHMEM_SLOTS_PER_BACKEND * MaxBackends =64+5* MaxBackends
复制代码

其中:PG_DYNSHMEM_FIXED_SLOTS 为 64,PG_DYNSHMEM_SLOTS_PER_BACKEND 为 5

该值(maxitems)与 MaxBackends 大小有关,MaxBackends 为最大的 backend 进程的数量,和配置的最大连接数(max_connections)、autovacuum worker 进程的最大个数(autovacuum_max_workers)、并发进程的最大数量(max_worker_processes)、wal sender process 的最大数量有关。

2>根据 maxitems 计算 dsm_control 结构所需要的内存大小 segsize,

segsize = dsm_control_bytes_needed(maxitems);
复制代码

其中函数 dsm_control_bytes_needed 定义:  

static uint64dsm_control_bytes_needed(uint32 nitems){      return offsetof(dsm_control_header, item)            + sizeof(dsm_control_item) * (uint64) nitems;}
复制代码


2)调用 dsm_impl_op() 函数,该函数根据 dynamic_shared_memory_type 参数调用不同的接口创建用于 dsm_control 结构的动态共享内存,地址赋值给 dsm_control 变量,该变量的类型为 dsm_control_header 。


3)初始化 magic、nitems、maxitems 变量,其中 maxitems 表示 AntDB-T 该 DN 节点所有进程能够申请的动态共享内存的最大数量,nitems 表示当前已使用的动态共享内存数量,每一次动态共享内存申请,对应一个 dsm_control_item。

其函数大致调用关系如下:

main(int argc, char *argv[])PostmasterMain(int argc, char *argv[])reset_shared(void)CreateSharedMemoryAndSemaphores(void)dsm_postmaster_startup(PGShmemHeader *shim)
复制代码


3. 清理 AntDB-T 动态共享内存(DSM)

在 postmaster 主进程关闭时,会调用 dsm_postmaster_shutdown() 函数进行 dsm 的清理,这个函数是在初始化动态共享内存(dsm_postmaster_startup())时就指定了 on_shmem_exit(dsm_postmaster_shutdown, PointerGetDatum(shim));


清理动态共享内存的主要逻辑:首先检查动态共享内存段是否已经损坏,如果损坏了就记录错误日志直接返回,如果没有损害时就遍历 dsm_control->nitems 数组,对其中正在使用的 item 对应的动态共享内存(DSM)进行销毁 ,最后再销毁 dsm_control 自身对应的 动态共享内存(DSM) 内存 。


(三)AntDB-T 动态共享内存实践分享


使用动态共享内存之前,需要先对其进行创建。AntDB-T 启动时已经初始化好了动态共享内存,后面使用的时候只需要创建动态共享内存,挂载动态共享内存,解除挂载动态共享内存,销毁共享内存。AntDB-T 数据库使用动态共享内存的地方有很多,下面举个最简单的并行查询的例子来解说下如何使用动态共享内存,举例的表字段和并行查询的执行计划如下图所示:


图 6:AntDB-T 并行查询的例子


可以从上图的执行计划里面明确看到有使用到了并行查询,并且并行的 worker 个数是 2。先进行简单的并行查询的原理介绍,图如下所示:DN backend 主进程拉起从进程,DN backend 主进程在处理时,发现需要进行并行处理,就会在启动从进程时,会调用 LaunchParallelWorkers 函数,这个函数会调用 RegisterDynamicBackgroundWorker ,此时会给 Postmaster 进程发一个信号,请求 Postmaster 进程启动一个 background 进程,Postmaster 进程收到信号后就会启动一个新后台进程来处理查询。

    图 7:AntDB-T 并行查询的流程        


在 AntDB-T 的源码中,上述 SQL 例子在并行查询中使用动态共享内存(DSM),其主要逻辑如下:

1.DN backend 主进程在判断需要进行并行处理时,就会初始化并行执行计划 ExecInitParallelPlan,在 ExecInitParallelPlan 函数中,会评估共享内存大小:通过使用 shm_toc_estimate_chunk、shm_toc_estimate_keys 宏定义向 estimate 中增加数据结构,可以多次调用,然后使用 shm_toc_estimate 得出需要创建的动态共享内存的总大小,最后调用 dsm_create()函数 创建动态共享内存(DSM)。创建并行的工作进程时,将动态共享内存(DSM)对应的 handle 作为参数传递给 并行的 worker 进程,其调用关系如下:

ExecGather(PlanState *pstate)ExecInitParallelPlan(PlanState *planstate, EState *estate,                               Bitmapset *sendParams, int nworkers,                               int64 tuples_needed)InitializeParallelDSM(ParallelContext *pcxt)dsm_create(Size size, int flags)LaunchParallelWorkers(ParallelContext *pcxt)worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(pcxt->seg));
复制代码


2.并行的子进程(DN worker 进程)先调用 dsm_attach() 函数挂载到动态共享内存,然后调用函数 ParallelQueryMain 处理查询业务该函数里面使用了动态共享内存,当并行的子进程执行结束时,会调用 dsm_detach() 函数解除挂载的 dsm 共享内存,其大致的调用关系如下:

ParallelWorkerMain(Datum main_arg)seg = dsm_attach(DatumGetUInt32(main_arg));ParallelQueryMain(dsm_segment *seg, shm_toc *toc)area = dsa_attach_in_place(area_space, seg);dsa_detach(area)dsm_detach(area->segment_maps[i].segment);
复制代码


总结

本文主要讲述了 AntDB-T 动态共享内存的基本概念、引入动态共享内存带来的能力提升、基本数据结构、动态共享内存机制原理和使用方法。限于篇幅,动态共享内存的其他函数接口比如:dsm_pin_mapping、dsm_unpin_mapping、dsm_pin_segment、其他使用动态共享内存的场景、动态共享内存中涉及的锁等相关内容没有涉及,小伙伴们请持续关注 AntDB 数据库公众号。       

    

关于 AntDB 数据库

AntDB 数据库始于 2008 年,在运营商的核心系统上,为全国 24 个省份的 10 亿多用户提供在线服务,具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔电信核心交易,保障系统持续稳定运行近十年,并在通信、金融、交通、能源、物联网等行业成功商用落地。    

用户头像

企业数据库创新实践者 2021-07-26 加入

AntDB数据库始于2008年,服务于全国20多个省份的10亿多用户提供在线服务;具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔电信核心交易,并保障系统持续0故障运行近十年。 官网:asiainfoah.com

评论

发布
暂无评论
解锁数据库运维秘籍:掌握AntDB-T动态共享内存,提升进程间通信效率_亚信科技_亚信AntDB数据库_InfoQ写作社区