中文----pg的gpu加速扩展技术总结

不想你离开。 提交于 2020-03-09 18:21:18

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执行计划。

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!