
简介Greenplum 6.19.0 完整源码包面向数据库内核开发者、数据平台运维人员及希望深入理解MPP架构的进阶学习者。作为全球首个开源、多云大数据分析平台Greenplum在经典与实时数据分析产品中占据独特地位源码可用于二次开发、编译部署及源码级学习。包体共12935个文件压缩后约60.94MB以C/C源码、SQL脚本、XML配置、SGML文档、Makefile构建脚本及Python工具为主并包含大量测试用例、平台适配脚本与Dockerfile等目录覆盖内核、工具链、文档和测试多个模块便于从构建到验证进行全链路研究。目前已有398人浏览学习。研读源码可以掌握Greenplum查询优化器、存储引擎、分布式事务等核心模块的设计思路理解基于PostgreSQL的扩展机制也能通过测试与平台脚本快速上手二次开发为定制化开发或生产调优打下基础。1. 拿到 gpdb-6.19.0.tar.gz 的第一件事别急着 ./configuregreenplum-dbgpdb-6.19.0.tar.gz是 Greenplum 6.x 系列的完整源码包2019 年被 Gartner 列为全球十大经典和实时数据分析产品中唯一开源数据库。和大多数人的直觉相反这个包解压之后不能直接./configure make6.x 的编译链路比 PostgreSQL 9.4 内核本身要长得多——你至少需要准备 78 个系统级依赖、特定的 Python 版本、以及足够的内存否则编译到一半会在pg_config或orca子目录上报出匪夷所思的错误。这篇文章从零拆一遍这个包先讲清楚 6.x 的 MPP 架构里哪些组件在编译期就会被激活再给出我实际跑通过的完整步骤、参数表和排错记录。适合两类人一类是想在测试机或 Docker 里快速拉起一个 Greenplum 环境的开发另一类是准备研究 GPORCA 优化器或 AO 表存储源码的读者。2. 解压与源码结构tar.gz 打开之后先看什么gpdb-6.19.0.tar.gz解压后是一个标准的 PostgreSQL 派生工程顶层目录里既有src/、doc/、contrib/这些 PG 老面孔也有gpAux/、orca/、gpdb-doc/这类 Greenplum 特有目录。我习惯先执行下面这组命令把包解开并确认关键目录存在mkdir -p ~/gpdb-src cd ~/gpdb-src tar -xzf ~/downloads/greenplum-db-6.19.0.tar.gz mv greenplum-db-6.19.0/* . ls -F | grep /$解压时如果报tar.gz没有那个文件或目录多半不是 tar 命令的问题而是-C指定的目标目录不存在或者压缩包路径写错。先ls -l ~/downloads/确认文件真在再用绝对路径解压。vscode 里打开这个目录时我建议直接把根目录拖进工作区而不是打开src/因为后续grep跨模块搜符号会方便很多。目录结构上重点看四个地方src/backend是 PostgreSQL 9.4 内核改造后的执行器与存储管理代码src/backend/cdb是 Greenplum 的分布式执行核心dispatch/executor 的协调逻辑都在这里orca/是 GPORCA 优化器的 C 源码树gpAux/里则放着扩展工具和gpinitsystem等管理脚本的源文件。6.19.0 的版本号延续了 6.x 的规则内核基于 PostgreSQL 9.4所以你在src/include/pg_config.h.in里会看到PG_VERSION 9.4不要觉得奇怪这是 Greenplum 6 的基线。解压之后我的习惯是先跑一次版本探测把包自带的版本信息和当前系统的编译工具链做个对照head -30 configure | grep PACKAGE_VERSION gcc --version | head -1 python --version参数说明configure脚本顶部的PACKAGE_VERSION会打印出 GP_VERSION 字符串通常形如6.19.0如果这里显示6.19.0dev说明你拿的是 git checkout 而非 release tag编译行为略有差异。gcc版本建议 8.x 或 9.x过老的 gcc 会在orca编译时触发 C11 标准库兼容问题。Python 需要 2.7Greenplum 6 的gppkg和gpcheckperf脚本对 Python 2.7 有硬依赖系统默认 Python 3 的话需要在 configure 时显式指定。依赖方面下面这张表是我在 CentOS 7.9 和 Rocky Linux 8.6 上都验证过的最小集合依赖包作用阶段缺失时的报错特征bison / flexconfigure 生成解析器yacc: command not foundreadline-develpsql 交互编辑readline/readline.h: No such filezlib-devel压缩与备份恢复zlib.h: No such fileopenssl-devel加密连接与 gpfdistopenssl/ssl.h: No such filelibcurl-develPXF 与外部表curl/curl.h: No such fileperl / perl-develpg_upgrade 与辅助脚本ExtUtils/MakeMaker not foundcmake 3.x编译 GPORCACould NOT find CMAKE_ROOTapr / apr-util-develgpfdist 外部表apr_want.h: No such fileCentOS 系一行装齐的话yum install -y bison flex readline-devel zlib-devel openssl-devel libcurl-devel perl-devel cmake apr-devel apr-util-devel。Ubuntu 系对应的是libreadline-dev zlib1g-dev libssl-dev libcurl4-openssl-dev libapr1-dev libaprutil1-dev包名略有出入但缺哪个在 configure 阶段都会立刻暴露按提示补即可。3. 编译链路从 configure 到 make install 的完整参数拆解Greenplum 6.19.0 的 configure 参数比 PostgreSQL 多出一倍不止。最核心的一个决策是使用 ORCA 优化器生产推荐还是仅用 Postgres legacy planner。我的建议是首次编译就带 ORCA因为 6.x 里gp_default_gxact_id、gp_session_state这些分布键约束逻辑和 ORCA 的CXform变换是耦合成一体的后续调 SQL 时如果不带 ORCA很多并行计划的执行行为会对不上。下面这组参数我实际跑通过适用于 x86_64 的 CentOS/Rocky 环境./configure \ --prefix/usr/local/greenplum-db-6.19.0 \ --with-perl \ --with-python \ --with-libxml \ --with-gssapi \ --with-openssl \ --with-orca \ --enable-debug \ --enable-cassert \ --enable-depend \ --with-extra-version-custom每个参数的作用我拆开讲。--prefix决定安装路径建议直接带版本号后续升级/usr/local/greenplum-db软链时不用动系统 PATH。--with-perl和--with-python是为了让plperl、plpython语言扩展可用Greenplum 的gpload数据加载工具依赖 Python 客户端环境虽然不强制在服务端开启但缺了之后CREATE EXTENSION plpythonu会直接失败。--with-orca是编译 GPORCA 的开关源码树里orca/目录会独立走 CMake 流程configure 会检测 cmake 是否存在。--enable-debug保留-g调试符号体积会大 40% 左右但对后面gdb分析 executor 或写 UDF 排查段错误很有用。--enable-cassert开启断言检查跑测试时能提前暴露内存越界生产构建建议关掉。接下来是编译。Greenplum 的构建系统和上游 PostgreSQL 一样是递归 make但子模块多我的建议是用-j之外额外设一个环境变量来控制并发export GPDB_CC_FLAGS-O2 -fno-omit-frame-pointer make -j$(nproc) 21 | tee /tmp/gpdb_make.log make install 21 | tee /tmp/gpdb_install.logGPDB_CC_FLAGS在 6.x 里会被src/Makefile.global读入追加到CFLAGS末尾-fno-omit-frame-pointer对性能影响很小但能让 perf 和 pstack 看到完整的用户态调用栈排查 CPU 打满时定位到具体函数非常关键。tee是常规操作但要注意编译日志通常有 5 万行以上后面如果报错grep -E error|Error /tmp/gpdb_make.log是最快的定位方式。链接阶段最常遇到的坑是libgpawl和libgpdb的符号冲突表现为undefined reference to gpos::CMemoryPool::Create之类这通常是 ORCA 的 debug/release 库混用导致的。原因在于--enable-debug会让orca/下的 CMake 构建默认带-DCMAKE_BUILD_TYPEDebug而 6.19.0 的 ORCA 代码里#ifdef GPOS_DEBUG分支较多一旦底层库没跟着编译成 Debug符号表就不一致。解决方法是 configure 之后手动进orca/build目录检查 CMakeCache.txt 里的CMAKE_BUILD_TYPE如果不是 Debug 就重新 cmake 一次再回顶层执行 make。安装完成后的一个加分项是把 Greenplum 的环境变量脚本装进 profile。官方安装包通常自带greenplum_path.sh源码编译后它生成在--prefix目录下echo source /usr/local/greenplum-db-6.19.0/greenplum_path.sh ~/.bashrc source /usr/local/greenplum-db-6.19.0/greenplum_path.shgreenplum_path.sh会把$GPHOME/bin、$GPHOME/lib和 Python 2.7 环境全部注入当前 shell其中PYTHONHOME和PYTHONPATH也被改成指向包内自带的 Python这一步不做的话gpstate和gpinitsystem会提示找不到gpAdminLogs。4. 集群初始化从 segment 规划到 gpinitsystem 参数详解源码编译完只是拿到了一堆二进制离「能用」还差一个初始化。Greenplum 6.19.0 的集群初始化逻辑集中在gpAux/gpinitsystem脚本里核心概念是一个 master 实例接管 SQL 入口多个 primary segment 各持一部分数据分片每个 primary 可以带一个 mirror 做冗余。单机演练环境下我倾向于初始化一个 master 2 个 primary、不带 mirror 的最小集群因为 mirror 在单机上要额外占一组端口且gpaddmirrors的恢复演练在多块磁盘上才能体现出效果。先准备数据目录和主机清单。即便只有一台机器gpinitsystem也要求通过 hostfile 指定 segment 节点mkdir -p /data/gpdata/{master,primary} echo $(hostname) /tmp/gp_hostlist chown -R gpadmin:gpadmin /data/gpdata注意gpinitsystem不允许以 root 执行源码编译产物的归属如果不是 gpadmin要先chown -R gpadmin:gpadmin /usr/local/greenplum-db-6.19.0。这是整个部署流程里最容易忽略的一步官方 README 只提了一句但实际报错是could not open file /data/gpdata/master/gpseg-1/PG_VERSION: Permission denied首次遇到很容易误判成目录权限或 SELinux 问题。集群配置模板通常叫gpinitsystem_config位于$GPHOME/docs/cli_help/gpconfigs/。复制出来后按下面这份最小配置改# 文件: /home/gpadmin/gpconfigs/gpinitsystem_config ARRAY_NAMEGP_6_19_DEMO MACHINE_LIST_FILE/tmp/gp_hostlist SEG_PREFIXgpseg PORT_BASE40000 MASTER_PORT5432 MASTER_HOSTNAME$(hostname) MASTER_DIRECTORY/data/gpdata/master DATADIRECTORY/data/gpdata/primary TRUSTED_SHELLssh ENCODINGUNICODE参数说明PORT_BASE是 primary segment 的起始端口每个 segment 会按序号 1规划时至少要避开 5432 和系统服务占用段。SEG_PREFIX是 segment 数据目录的前缀初始化后 master 目录形如/data/gpdata/master/gpseg-1primary 目录形如/data/gpdata/primary/gpseg0这个命名规则在gpstate输出和排查磁盘占用时会反复用到。TRUSTED_SHELLssh意味着初始化脚本要通过 SSH 到各节点执行命令单机环境需要保证gpadmin用户ssh localhost免密如果不想配密钥至少要在/etc/ssh/sshd_config里允许当前用户空密码登录。接着执行初始化source /usr/local/greenplum-db-6.19.0/greenplum_path.sh gpinitsystem -c /home/gpadmin/gpconfigs/gpinitsystem_config \ -h /tmp/gp_hostlist \ -s $(hostname) \ --max_connections100-s指定 standby master单机演练时可以不配但生产至少需要一个 standby否则 master 宕机只能手动从 pg_ctl 拉起。--max_connections100这个参数很多人会漏掉默认值是 250如果机器内存只有 8GB每个 backend 进程的shared_buffers加上work_mem峰值会直接把内存吃满。初始化成功后输出里会看到Greenplum Database instance successfully created并且会提示你下一步去psql -d postgres验证。连接验证这边我习惯同时确认数据库版本和集群拓扑两个层面psql -d postgres -c SELECT version(); psql -d postgres -c SELECT gp_segment_id, hostname, status FROM gp_segment_configuration;第一个命令返回的版本字符串里应该能看到Greenplum Database 6.19.0和PostgreSQL 9.4内核标识这两个信息同时出现是正常的不要当成版本错乱。第二个命令的返回里gp_segment_id -1的行代表 master0和1代表两个 primary segmentstatus为u表示可用up如果出现d就要去cat /data/gpdata/primary/gpseg0/log/startup.log看具体原因。这个查询信息量其实很大role列区分 primary/mirrorport列可以反推实际监听端口和PORT_BASE的偏移关系排查网络策略时先看这张表永远比看配置文件高效。5. 排错速查编译期与运行期最常见的三个坑源码安装 Greenplum 6.19.0 的过程里排错比执行本身更花时间。我把遇到概率最高的三个问题连同定位方式一起列出来这些都直接影响能否走到psql这一步。第一个坑是编译期报configure: error: readline library not found但明明rpm -qa | grep readline显示了包存在。原因是 readline 的运行时库libreadline.so和开发头文件readline.h分属不同包Ubuntu/Debian 系里readline-common只提供/usr/lib/x86_64-linux-gnu/libreadline.so.7而编译需要libreadline-dev里的.so软链。检查方式不要只看 rpm 包名直接ls /usr/include/readline/readline.h更可靠。缺了就用包管理器补齐不要手动去拷.so会污染系统库路径。第二个坑出现在gpinitsystem阶段报[WARN] master data directory /data/gpdata/master/gpseg-1 already exists。这个提示通常不是真的目录里已有数据而是上一次初始化失败残留的空目录。Greenplum 6.x 对 master 目录有内容检测只要存在PG_VERSION就拒绝覆盖所以清理时不能只删顶层目录得递归删干净rm -rf /data/gpdata/master/gpseg-1 rm -rf /data/gpdata/primary/gpseg0 /data/gpdata/primary/gpseg1删除之后还要检查/tmp/.s.PGSQL.*之类的 socket 文件是否残留否则psql连接时可能报could not connect to server: No such file or directory而实际端口又被占着。快速验证端口占用用ss -lntp | grep 5432看到残留进程就先gpstop -M fast再初始化。第三个坑是启动后 SQL 执行报ERROR: failed to acquire memory或FATAL: out of memory。这个和编译参数关系不大基本是资源队列或vm.overcommit设置不合理。Greenplum 的 segment 进程默认会预留一块很大的内存池vm.overcommit_memory2的机器上特别容易触发。常规解法是在/etc/sysctl.conf里设vm.overcommit_ratio90并sysctl -p同时在会话级别调低gp_vmem_protect_limitALTER SYSTEM SET gp_vmem_protect_limit 4096; SELECT pg_reload_conf();gp_vmem_protect_limit的单位是 MB它控制单个 segment 在一条 SQL 里最多能使用的虚拟内存。4GB 的设定适合 8GB 内存的测试机生产环境一般按物理内存 * 0.7 / segment 数来算。这个参数对 5 年以上经验的人来说也是一个容易踩的边界场景调大了并发高时 OOM调小了复杂 join 直接被 shield 杀掉日志里会出现postmaster: 8134 gpadmin被 kill 的记录。修改后不要急着重启先gpstate -e检查各 segment 状态确认没有 segment 处于 change tracking 状态再继续。掌握这三个排错点配合前面的 configure 和 gpinitsystem 参数基本能在一小时内从零跑起一个可用的 6.19.0 集群。之后如果想深入源码建议从src/backend/cdb/cdbdisp_query.c开始读那是 SQL 语句从 master 分发到 segment 的必经之路也是 Greenplum 与标准 PostgreSQL 分道扬镳的原点。本文还有配套的精品资源点击获取