文章目录
PG-Strom总结
- 用GPU来加速SQL上的操作
- 其GPU代码生成器根据SQL语句生成
- 对应的在英伟达的CUDA(统一计算架构)的GPU程序
- 它的“SSD-to-GPU Direct SQL”机制
- 允许直接将数据从NVME的固态硬盘传到GPU
- 他的“PL/CUDA”和“gstore_fdw”允许运行高计算密度的问题。
要求配置
-
硬件服务器:
- 64位的能运行支持CUDA Toolkit(用来开发CUDA程序的工具)的Linux操作系统的x86硬件。
- “SSD-to-GPU Direct SQL”需要支持NVMe规范的固态硬盘,且和GPU安装在同一个PCIe Root Complex下。
-
GPU设备:至少一个支持CUDA Toolkit的计算能力6.0的GPU
-
操作系统:由CUDA Toolkit支持的x86 64位Linux
-
PostgreSQL:9.6版本之后的PostgreSQL。
- 因为9.6版本为CPU并行执行和GROUP BY更新了自定义扫描接口,
- 允许协调外部模块提供的定制计划。
-
9.1版本的CUDA Toolkit,
- PG-Strom提供半精度浮点型(float2)
- 内部使用half_t类型的CUDA.C,
- 所以老版本不行
PG-Strom实现原理细节
1 NVME-Strom module
- NVME-Strom内核模块是与PG-Strom的核心功能密切配合,
- 如“SSD-to-GPU Direct SQL Execution”。
- NVME-Strom内核收到SSD-to-GPU的直接数据传输请求时,
- 首先,他检查需要的数据块是否在OS的页缓冲中
- 如果“fast_ssd_mode”=0
- NVME-Strom将立刻将所请求的数据所在的页缓存
- 写回给调用者的用户缓存空间中,
- 然后指示应用程序通过CUDA API调用正常主机 ->设备数据传输。
- 它适用非快速NVME-SSD,如PCIe x4等级
- 使用PCIe x8级别的快速NVME-SSD或分段模式下的多个固态硬盘,传输将更快
- ”fast_ssd_mode”!=0,
- NVME-Strom将踢出SSD-to-GPU直接数据传输请求。
- NVME-Strom内核模块为SSD-to-GPU直接的数据传输使用DMA请求,然后将他们排到NVME设备的IO队列。
- 当异步的DMA请求过多时,DMA请求延迟将变得糟糕,因为NVME-SSD控制器是按到达顺序处理DMA请求的。
- 当DMA请求的时间太长就可能会被认为出错
EXPLAIN指令看query语句是否由GPU执行
- Query语句被分成多个部分并执行
- PG-Storm能在GPU上并行执行SCAN,JOIN和GROUP BY,
- 看到GpuScan,GpuJoin,GpuPreAgg证明被GPU执行
- PG-Strom会与query优化器交互,会执行优化器提供的query执行计划。
- PG-Storm能在GPU上并行执行SCAN,JOIN和GROUP BY,
CPU-GPU混合式并行:
- CPU并行模式下,Gather节点启动多个后台工作进程,
- 并收集后台进程的执行结果。
- PG-Strom提供的自定义扫描执行支持将执行交给后台工作,
- 他们单独通过GPU执行他们的部分任务。
- CPU内核为提供数据给GPU而建立缓存比在GPU上执行SQL更花时间,
- 所以CPU和GPU的混合式有更好性能
- 另一方面,每个进程都会创建用于与GPU的交互的CUDA文件和消耗一定的GPU资源。
如果啥,则并不会有更好的性能。
- GPU执行SCAN后写回主机缓冲区,然后执行JOIN时又从缓冲区中发送给GPU,执行完后又写回主机缓冲区,
- 会让数据在CPU和GPU来回传输
- PG-Strom有一种特殊的模式来“上拉子底层计划”
- 在GPU内核的一次单独调用时执行许多工作
- 这些操作的组合会上拉子计划:
- SCAN+JOIN;
- SCAN+GROUP BY;
- SCAN+JOIN+GROUP BY
- 执行GpuJoin时会把SCAN嵌套在里面执行,
- 而不一个个执行
MPS daemon(多进程服务守护进程):
- 一个MPS daemon可为48个客户端提供服务。
- 不支持dynamic parallelism(动态并行性)。
- PL/CUDA用户定义的函数可能在CUDA设备运行时调用子内核使用动态并行性,所以不能用MPS来调用PL/CUDA函数。
索引:PG-Strom只支持BRIN-index。BRIN-index是在物理存储的相邻的记录有相似的键值,如果当块范围内的记录明显不符合scan的限定词,那么将跳过这些块。PG-Strom也利用了BRIN-index的这些特点,会跳过这些明显不必要的要加载到GPU的块。
划分:表划分是PostgreSQL支持的新的机制,他将逻辑上的大表划分成物理上的小表,在扫描是会跳过那些明显不符合的子表。当PG-Strom与表划分的PostgreSQL一起使用时,他的优化器会选择GpuScan扫描每个单独的将要扫描的子表,在Append节点合并GpuScan结果。通过GUC参数“pg_strom.enable_partitionwise_gpujoin”和“pg_strom.enable_partitionwise_gpupreagg”,PG-Strom可以将JOIN/GROUP BY应用到子表上,在子表上执行了JOIN/GROUP BY再执行Append。而不是让Append在SCAN和JOIN/GROUP BY中间执行,因为这样的话会让数据在内存和GPU之间来回传递。
“pg_strom.enabled”参数可以开关PG-Strom,以此来看错误是出在PG-Strom还是PostgreSQL上。
Crash dump:对于进程崩溃时生成崩溃转储(CPU端),需要更改操作系统对PostgreSQL服务进程可以产生的核心文件大小的资源限制。对于GPU内核的错误产生的崩溃转储,需要将PostgreSQL服务进程的“CUDA_ENABLE_COREDUMP_ON_EXCEPTION”环境变量设为1。
SSD-to-GPU Direct SQL Execution:SSD-to-GPU Direct SQL Execution通过PCIe总线连接NVMe-SSD和GPU,这样提供以接近硬件有线速度的数据流来快速执行SQL。通常对于将存储中的数据块加载到CPU内存后会有大量的数据被过滤掉,结果数据集只是原数据集的一小部分,所以我们消耗了PCIe的带宽来移动垃圾数据。
SSD-to-GPU Direct SQL Execution改变了读存储的流,它直接将数据块使用DMA传到GPU,然后执行SQL语句来减少传给CPU的数据量。也就是说,他把GPU当作一个SQL语句的预处理器。这个功能的内部是用NVIDIA GPUDirect RDMA,它通过Linux 内核模块进行协调在GPU设备内存和第三方设备之间的PCIe总线来端到端传送。该机制要求DMA的两端设备必须链接到同样的PCIe root complex,并且推荐用专用的PCIe交换器链接两端。
因为PG-Strom用不了MVCC的可见性检查,所以PostgreSQL有一个可见性映射的基础结构,是一组用于指定特定数据块中记录是否可见的标识。SSD-to-GPU Direct SQL Execution利用这个结构来检查可见性,只有所有都可见的块会通过DMA来读取。可通过使用VACUUM指令来让PostgreSQL构建可见性映射表。
11 GPU Memory Store(gstore_fdw
- PG-Strom对GPU内存的使用只是临时目的
- gstore_fdw是一种保存GPU内存并将数据初始加载到内存的功能,它不需为PL/CUDA函数的每次调用设置参数和加载,且消除了1GB的可变长度数据限制
- 字面上,gstore_fdw通过使用pg的外部数据包装器实现的,
- 可用由gstore_fdw管理的外部表中的“INSERT,UPDATE,DELETE”来改GPU设备的数据结构
- PL/CUDA函数可通过外表引用存在GPU设备内存中的数据。
- 目前通过SQL表述生成的GPU程序不能引用设备内存,
- 未来将加这功能。
- Gstore_fdw外表只能接受单个事务修改
- 任何写入该表的内容在事务提交前对其他对话不可见,
- 保证事务原子性
- 建议修改大量的行之后再提交事务
- gstore_fdw的外表是易丢失的,
- 因此,加载到gstore_fdw外表上的内容应该可以由其他数据源重构
- 任何写入该表的内容在事务提交前对其他对话不可见,
12 PL/CUDA:
- Pg支持通过CREATE LANGUAGE语句添加编程语言来实现SQL函数。
- PL / CUDA是一个支持CREATE LANGUAGE命令的语言处理程序。
- 允许用户运行手动实现为SQL函数的任意GPU程序,不仅仅是基于SQL的PG-Strom自动生成的GPU程序。
- 参数是可以由PG-Strom支持的数据类型,
- 参数通过PL/CUDA隐式的载入到GPU设备内存。
- 也可以使用由gstore_fdw定义的外表作为PL/CUDA的参数,
- 这样就没有必要为每个调用载入数据到GPU,且可以使用大于1GB的数据。
一旦PL/CUDA用CREATE FUNCTION声明一个函数
- 他会生成一个嵌套该函数定义的CUDA源码,然后用GPU设备构建他
- 除了SQL函数提供的参数和要写回结果外,他和普通GPU软件一样。
- PL/CUDA实现的CUDA程序会作为子进程在Pg后台执行,
- 他有独立的地址空间和从PostgreSQL获取的操作系统/GPU资源。
- CUDA程序包含宿主系统的宿主代码还有GPU上执行的设备代码。
- 宿主代码可用C来写,且出于安全考虑只允许数据块超级用户能定义PL/CUDA。
- PL/CUDA的语言处理器根据代码块构造单独的CUDA.C源文件,
- 然后用nvcc编译器在声明或执行时进行编译,
- 如果包含“#plcuda_include”,源代码只会在执行时构建,如果是已经构造过的相同的CUDA程序,我们可以重复使用。
- 当SQL指令调用PL/CUDA函数时,PL/CUDA语言处理器会通过管道复制SQL函数的参数然后使用之前已经构造好的程序来运行,这些参数都存储在CUDA程序的参数缓冲区中。CUDA C程序中引用的数据类型会在参数缓冲区中被初始化为指针,这是由”cudaMallocManaged()”分配的托管内存区域,这些指针在主机系统和GPU设备间没有显示DMA可用。一种特殊情况是如果参数有reggstore类型,实际上Gstore_Fdw外表的OID(32位整数)如果被提供为PL/CUDA参数,就会用gstore_fdw外表替换GPU设备内存的引用。
- 数据量小,可用PosgtgreSQL支持的数组类型……太大,应该用Gstore_fdw外表
参考链接
- https://blog.csdn.net/Han_L/article/details/88814664?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
来源:CSDN
作者:fgh431
链接:https://blog.csdn.net/zhoutianzi12/article/details/104754590