PolarDB开源数据库进阶课18 通过pg_bulkload适配pfs实现批量导入提速

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
简介: 本文介绍了如何修改 `pg_bulkload` 工具以适配 PolarDB 的 PFS(Polar File System),从而加速批量导入数据。实验环境依赖于 Docker 容器中的 loop 设备模拟共享存储。通过对 `writer_direct.c` 文件的修改,替换了一些标准文件操作接口为 PFS 对应接口,实现了对 PolarDB 15 版本的支持。测试结果显示,使用 `pg_bulkload` 导入 1000 万条数据的速度是 COPY 命令的三倍多。此外,文章还提供了详细的步骤和代码示例,帮助读者理解和实践这一过程。

背景

穷鬼玩PolarDB RAC一写多读集群系列已经写了几篇:

本篇文章介绍一下如何修改pg_bulkload, 适配PFS, 加速批量导入PolarDB数据库. 实验环境依赖 《在Docker容器中用loop设备模拟共享存储》 , 如果没有环境, 请自行参考以上文章搭建环境.

pg_bulkload是PostgreSQL加速逻辑数据导入的工具, 可以绕过wal, shared_buffer, 并且支持并行、支持使用binary方式(绕过PG datatype序列化和反序列化过程)直接写入PostgreSQL数据文件. 实现几倍于copy的导入性能. 但是PolarDB的数据文件存放于PFS内, 读写接口都改成了pfs接口, pg_bulkload无法直接使用, 在PolarDB 11版本内通过如下方式进行修改, 支持了本地盘使用pg_bulkload, 但还没有在pfs上尝试过, 本文将使用PolarDB 15进行尝试.

pg_bulkload 适配PFS

b站视频链接

Youtube视频链接

有了前面的背景介绍, 我们可以直接修改writer_direct.c, 参看如下pfs头文件:

$ ll PolarDB-for-PostgreSQL/src/include/storage/polar*  
-rw-r--r--  1 digoal  staff   3.3K Dec 20 15:24 polar_bufmgr.h  
-rw-r--r--  1 digoal  staff   3.9K Dec 20 15:24 polar_copybuf.h  
-rw-r--r--  1 digoal  staff    13K Dec 20 15:24 polar_fd.h  
-rw-r--r--  1 digoal  staff   3.4K Dec 20 15:24 polar_flush.h  
-rw-r--r--  1 digoal  staff   5.6K Dec 20 15:24 polar_io_stat.h  
-rw-r--r--  1 digoal  staff   3.4K Dec 20 15:24 polar_lock_stats.h  
-rw-r--r--  1 digoal  staff   7.9K Dec 20 15:24 polar_procpool.h  
-rw-r--r--  1 digoal  staff   5.3K Dec 20 15:24 polar_rsc.h  
-rw-r--r--  1 digoal  staff   5.5K Dec 20 15:24 polar_xlogbuf.h  
  
$ ll PolarDB-for-PostgreSQL/src/include//polar_vfs/*  
-rw-r--r--   1 digoal  staff   1.2K Dec 20 15:24 polar_bufferio.h  
-rw-r--r--   1 digoal  staff   2.3K Dec 20 15:24 polar_directio.h  
-rw-r--r--   1 digoal  staff   1.5K Dec 20 15:24 polar_pfsd.h  
-rw-r--r--   1 digoal  staff   2.2K Dec 20 15:24 polar_vfs_fe.h  
-rw-r--r--   1 digoal  staff   3.4K Dec 20 15:24 polar_vfs_interface.h

进入pb1 容器

docker exec -ti pb1 bash

克隆代码

cd /data  
git clone -c core.symlinks=true --depth 1 -b VERSION3_1_22 https://github.com/ossc-db/pg_bulkload

修改如下, 替换了一些write,BasicOpenFilePerm,fsync,lseek接口为pfs的对应接口.

# 你修改时可以打开vi number
# :set number
$ diff pg_bulkload_for_polar/lib/writer_direct.c pg_bulkload/lib/writer_direct.c   
8d7  
< #include "storage/polar_fd.h"  
223c222  
<   self->lsf_fd = polar_open(self->lsf_path,  
---  
>   self->lsf_fd = BasicOpenFilePerm(self->lsf_path,  
233,234c232,233  
<   if (polar_write(self->lsf_fd, ls, sizeof(LoadStatus)) != sizeof(LoadStatus) ||  
<     polar_fsync(self->lsf_fd) != 0)  
---  
>   if (write(self->lsf_fd, ls, sizeof(LoadStatus)) != sizeof(LoadStatus) ||  
>     pg_fsync(self->lsf_fd) != 0)  
629c628  
<       int len = polar_write(loader->datafd, buffer + written, total);  
---  
>       int len = write(loader->datafd, buffer + written, total);  
695c694  
<   fd = polar_open(fname, O_CREAT | O_WRONLY | PG_BINARY, S_IRUSR | S_IWUSR);  
---  
>   fd = BasicOpenFilePerm(fname, O_CREAT | O_WRONLY | PG_BINARY, S_IRUSR | S_IWUSR);  
702c701  
<   ret = polar_lseek(fd, BLCKSZ * (blknum % RELSEG_SIZE), SEEK_SET);  
---  
>   ret = lseek(fd, BLCKSZ * (blknum % RELSEG_SIZE), SEEK_SET);  
726c725  
<     if (polar_fsync(loader->datafd) != 0)  
---  
>     if (pg_fsync(loader->datafd) != 0)  
729c728  
<     if (polar_close(loader->datafd) < 0)  
---  
>     if (close(loader->datafd) < 0)  
750,751c749,750  
<   polar_lseek(loader->lsf_fd, 0, SEEK_SET);  
<   ret = polar_write(loader->lsf_fd, ls, sizeof(LoadStatus));  
---  
>   lseek(loader->lsf_fd, 0, SEEK_SET);  
>   ret = write(loader->lsf_fd, ls, sizeof(LoadStatus));  
756c755  
<   if (polar_fsync(loader->lsf_fd) != 0)  
---  
>   if (pg_fsync(loader->lsf_fd) != 0)

编译修改后的pg_bulkload

cd /data/pg_bulkload  
sudo chown -R postgres:postgres /home/postgres/tmp_polardb_pg_15_base  
USE_PGXS=1 make install

安装pg_bulkload插件

$ psql  
psql (PostgreSQL 15.10 (PolarDB 15.10.2.0 build d4f5477d debug) on aarch64-linux-gnu)  
Type "help" for help.  
  
postgres=# create extension pg_bulkload ;

使用pg_bulkload导入PolarDB 15 on PFS举例

1、参考满哥的这篇文章( https://www.modb.pro/db/1754101551677394944 ), 创建一张foo表, 生成一些测试数据, 并使用pg_bulkload命令行往PolarDB foo表进行导入.

进入pb1 容器

docker exec -ti pb1 bash

2、在PolarDB中建表

create table foo(a int, b varchar);

3、生成点数据

cd /data/pg_bulkload    
    
seq 100000| awk '{print $0",foo"}' > foo.csv

4、使用pg_bulkload命令行往PolarDB 15 foo表进行导入

$ pg_bulkload -i ./foo.csv -O foo -l test_foo.log -p 5432 -o "TYPE=csv" -o "DELIMITER=," -d postgres -U postgres    
NOTICE: BULK LOAD START  
NOTICE: BULK LOAD END  
  0 Rows skipped.  
  100000 Rows successfully loaded.  
  0 Rows not loaded due to parse errors.  
  0 Rows not loaded due to duplicate errors.  
  0 Rows replaced with new rows.

5、pg_bulkload通过direct模式导入的数据需要重启才能被看到, 和PolarDB relation size cache mode有关(11 对应这个参数 polar_nblocks_cache_mode).

postgres=# select count(*) from foo;  
 count   
-------  
     0  
(1 row)  
  
# 重启PolarDB  
pg_ctl restart -m fast -D ~/primary  
  
postgres=# select count(*) from foo;  
 count    
--------  
 100000  
(1 row)

PolarDB 15可以通过polar_enable_rel_size_cache参数来控制.

postgres=# alter system set polar_enable_rel_size_cache=off;
ALTER SYSTEM
# 重启PolarDB  
pg_ctl restart -m fast -D ~/primary

关闭polar_enable_rel_size_cache后, pg_bulkload导入的数据可以立即被看见.

6、检查一下数据文件是不是写在pfs里?

postgres=# select pg_relation_filepath('foo');  
        pg_relation_filepath          
------------------------------------  
 /nvme1n1/shared_data//base/5/24692  
(1 row)

没错

$ pfs -C disk stat /nvme1n1/shared_data//base/5/24692  
  file: /nvme1n1/shared_data//base/5/24692  
  size: 3629056         blocks: 8192  
device: pbd-0   inode: 658 links: 1  
access: 0, Thu Jan  1 08:00:00 1970  
modify: 1735801813, Thu Jan  2 15:10:13 2025  
change: 1735801813, Thu Jan  2 15:10:13 2025

7、使用1000万数据对比, pg_bulkload速度是COPY 3倍多.

$ time pg_bulkload -i ./foo.csv -O foo -l test_foo.log -p 5432 -o "TYPE=csv" -o "DELIMITER=," -d postgres -U postgres  
NOTICE: BULK LOAD START
NOTICE: BULK LOAD END
  0 Rows skipped.
  10000000 Rows successfully loaded.
  0 Rows not loaded due to parse errors.
  0 Rows not loaded due to duplicate errors.
  0 Rows replaced with new rows.
real  0m4.172s
user  0m0.002s
sys 0m0.011s
postgres=# \copy foo from './foo.csv' with (format csv);
COPY 10000000
Time: 14377.082 ms (00:14.377)

参考

《穷鬼玩PolarDB RAC一写多读集群系列 | 在Docker容器中用loop设备模拟共享存储》

《穷鬼玩PolarDB RAC一写多读集群系列 | 如何搭建PolarDB容灾(Standby)节点》

《穷鬼玩PolarDB RAC一写多读集群系列 | 共享存储在线扩容》

《穷鬼玩PolarDB RAC一写多读集群系列 | 计算节点 Switchover》

《穷鬼玩PolarDB RAC一写多读集群系列 | 在线备份》

《穷鬼玩PolarDB RAC一写多读集群系列 | 在线归档》

《穷鬼玩PolarDB RAC一写多读集群系列 | 实时归档》

《穷鬼玩PolarDB RAC一写多读集群系列 | 时间点恢复(PITR)》

《穷鬼玩PolarDB RAC一写多读集群系列 | 读写分离》

《穷鬼玩PolarDB RAC一写多读集群系列 | 主机全毁, 只剩共享存储的PolarDB还有救吗?》

《穷鬼玩PolarDB RAC一写多读集群系列 | 激活容灾(Standby)节点》

《穷鬼玩PolarDB RAC一写多读集群系列 | 将“共享存储实例”转换为“本地存储实例”》

《穷鬼玩PolarDB RAC一写多读集群系列 | 将“本地存储实例”转换为“共享存储实例”》

《穷鬼玩PolarDB RAC一写多读集群系列 | 升级vector插件》

《穷鬼玩PolarDB RAC一写多读集群系列 | 使用图数据库插件AGE》

《穷鬼玩PolarDB RAC一写多读集群系列 | 接入私有化大模型服务》

《穷鬼玩PolarDB RAC一写多读集群系列 | 接入PostGIS插件全功能》

《穷鬼玩PolarDB RAC一写多读集群系列 | 接入pg_duckdb支持数据湖功能,且OLAP性能数量级提升》

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
打赏
0
1
1
1
20702
分享
相关文章
【瑶池数据库训练营及解决方案本周精选(探索PolarDB,参与RDS迁移、连接训练营)】(5.30-6.8)
本周精选聚焦数据库迁移训练营、快速连接云数据库RDS训练营及智能多模态搜索解决方案。为用户提供模拟教程与实战演练,学习RDS MySQL实例连接与数据管理技能,助力企业智能化发展。每周解锁数据库实战新场景,抓紧时间,精彩不容错过!
MyEMS开源系统安装之数据库
本文详细讲解MyEMS的安装步骤,重点介绍数据库架构与脚本部署。MyEMS支持MySQL 8.0、MariaDB 10.5及SingleStore 7.0等数据库服务器。通过命令行或客户端工具执行SQL脚本完成安装,包括多个数据库(如myems_billing_db、myems_energy_db等)。此外,提供解决常见问题的方法,如“用户拒绝访问”、“COLLATE设置”和“MAX_ALLOWED_PACKET错误”。注意,不建议在生产环境中将数据库安装于Docker容器内。
53 1
阿里云PolarDB与沃趣科技携手打造一体化数据库解决方案,助推国产数据库生态发展
阿里云瑶池数据库与沃趣科技将继续深化合作,共同推动国产数据库技术的持续创新与广泛应用,为行业生态的繁荣注入更强劲的技术动力。
阿里云PolarDB与沃趣科技携手打造一体化数据库解决方案,助推国产数据库生态发展
客户说|知乎基于阿里云PolarDB,实现最大数据库集群云原生升级
近日,知乎最大的风控业务数据库集群,基于阿里云瑶池数据库完成了云原生技术架构的升级。此次升级不仅显著提升了系统的高可用性和性能上限,还大幅降低了底层资源成本。
PolarDB开源:云原生数据库的架构革命
本文围绕开源核心价值、社区运营实践和技术演进路线展开。首先解读存算分离架构的三大突破,包括基于RDMA的分布式存储、计算节点扩展及存储池扩容机制,并强调与MySQL的高兼容性。其次分享阿里巴巴开源治理模式,涵盖技术决策、版本发布和贡献者成长体系,同时展示企业应用案例。最后展望技术路线图,如3.0版本的多写多读架构、智能调优引擎等特性,以及开发者生态建设举措,推荐使用PolarDB-Operator实现高效部署。
170 2
PolarDB开源数据库入门教程
PolarDB是阿里云推出的云原生数据库,基于PostgreSQL、MySQL和Oracle引擎构建,具备高性能、高扩展性和高可用性。其开源版采用计算与存储分离架构,支持快速弹性扩展和100%兼容PostgreSQL/MySQL。本文介绍了PolarDB的安装方法(Docker部署或源码编译)、基本使用(连接数据库、创建表等)及高级特性(计算节点扩展、存储自动扩容、并行查询等)。同时提供了性能优化建议和监控维护方法,帮助用户在生产环境中高效使用PolarDB。
718 21
PolarDB开源:云原生数据库的新篇章
阿里云自研的云原生数据库PolarDB于2023年5月正式开源,采用“存储计算分离”架构,具备高性能、高可用及全面兼容性。其开源版本提供企业级数据库解决方案,支持MySQL、PostgreSQL和Oracle语法,适用于高并发OLTP、核心业务系统等场景。PolarDB通过开放治理与开发者工具构建完整生态,并展望更丰富的插件功能与AI集成,为中国云原生数据库技术发展贡献重要力量。
296 17
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
154 1
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库

相关产品

  • 云原生数据库 PolarDB
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等

    登录插画

    登录以查看您的控制台资源

    管理云资源
    状态一览
    快捷访问