2. 环境准备:把CentOS 7的底子打好
如果说数据存储区是Greenplum的心脏,那操作系统环境就是这套集群的骨架。骨架不正,后面全是麻烦。我见过不少人跳过这一步直接装软件,结果初始化集群时冒出一堆莫名其妙的报错,回头排查才发现是系统参数没配好。这一章节把环境准备拆开揉碎讲清楚,照着做就行。
2.1 用户规划:为什么必须用gpadmin账号
Greenplum官方安装文档第一条就是创建gpadmin用户,这不是走形式。Greenplum的管理进程(master和segment)在生产环境里必须用非root用户启动,原因有两点:一是安全考虑,数据库进程一旦被提权攻击,root权限就是灾难;二是Greenplum自身的管理工具(如gpadmin身份执行的gpconfig、gpstop)会校验运行用户,用root跑往往会报权限错误。
创建用户时建议把家目录放在独立分区,别跟根分区挤在一起。GP在运行时会往家目录写日志、配置文件、备份文件,随着运行时间增长体积不小。我的习惯是单独划一个/data分区给数据库用,家目录放在/data/gpadmin下面:
groupadd gpadmin useradd -g gpadmin -d /data/gpadmin -s /bin/bash gpadmin注意最后面的shell参数,务必指定为/bin/bash。Greenplum的很多脚本依赖bash特性,如果用默认的sh,后面跑gpinit时可能遇到诡异的解析问题。
创建好后设置密码,顺便把ssh免密配了。Greenplum集群内部通信大量依赖SSH,多机环境下必须让gpadmin用户能免密登录到所有节点(包括自己)。这一步可以在装完软件后再做,但先把用户建好总没错。
2.2 系统内核参数:照着这份配置抄作业
Greenplum对共享内存、信号量、文件句柄的要求比普通应用高出一个量级。原因很简单:Greenplum架构是基于PostgreSQL的MPP实现,每个segment实际上就是一个独立的PostgreSQL实例,每个实例都要申请共享内存、信号量、进程数。一台机器上跑8个甚至16个segment实例时,默认的内核参数根本扛不住。
我整理了一份经过多次验证的sysctl配置,直接放到/etc/sysctl.conf里即可:
kernel.shmall = 1073741824 kernel.shmmax = 1099511627776 kernel.shmmni = 4096 vm.overcommit_memory = 2 vm.overcommit_ratio = 95 fs.aio-max-nr = 1048576 fs.file-max = 6815744 net.core.rmem_max = 1048576 net.core.wmem_max = 1048576 net.core.rmem_default = 262144 net.core.wmem_default = 262144 net.ipv4.ip_local_port_range = 1024 65535这里挑几个容易踩坑的说:
- kernel.shmmax这个值建议设为物理内存的一半以上。如果机器是256GB内存,设成128GB是比较稳妥的。设小了,PostgreSQL共享内存分配会直接失败。
- vm.overcommit_memory = 2配合vm.overcommit_ratio = 95,意思是告诉内核:允许进程申请的内存可以达到物理内存的95%。Greenplum每个segment进程都有内存预算,如果不开放这个限制,segment启动时申请内存会被操作系统拒绝。
- fs.file-max决定整个系统能打开的文件句柄上限。Greenplum每个segment会打开大量数据文件,这个值设到6815744是官方建议值,实际生产中可以更高。
改完执行sysctl -p生效。还要给gpadmin用户单独提高ulimit限制,编辑/etc/security/limits.conf:
gpadmin soft nofile 65536 gpadmin hard nofile 65536 gpadmin soft nproc 131072 gpadmin hard nproc 131072这两组限制的意义:nofile是文件句柄数,nproc是进程数上限。Greenplum一个节点上所有segment的进程加起来可能上百个,默认的1024进程限制会直接卡死初始化过程。
2.3 关闭防火墙和SELinux:别让安全机制成为绊脚石
这一步在官方文档里一笔带过,但实际生产中最容易在这里翻车。Greenplum集群内部通信端口范围很广:master端口是5432,Segment端口从40000开始往后排,还有镜像段的端口,加上GP使用的高端口范围,防火墙规则很难精确放行。既然是在内网部署,直接关闭防火墙最省事:
systemctl stop firewalld systemctl disable firewalld sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/configSELinux也必须关。它的强制访问控制机制会拦截PostgreSQL对数据文件的读写,而且报错信息非常隐蔽,通常是文件权限正确但就是无法写入,排查起来极为耗时间。改完SELinux配置后需要重启或者执行setenforce 0临时关闭。
提示:如果你所在环境严格要求不能关闭防火墙,至少需要放行5432、40000-41000之间的TCP端口,以及GPDB监控代理使用的端口段。但说实话,在内网环境里因为防火墙问题排查网络不通的精力,远大于写几条规则的精力。
2.4 磁盘文件系统与挂载配置
数据存储区最终落在一堆目录上,这些目录所在文件系统的性能直接决定Greenplum的IO表现。我强烈建议数据目录使用XFS文件系统,而不是ext4。XFS对大数据文件的支持、并发IO性能、动态inode分配都比ext4更适合分析型数据库场景。
创建文件系统时的几个细节:
mkfs.xfs -f -n ftype=1 /dev/sdb1ftype=1这个参数容易被忽略。它控制XFS是否记录文件类型信息,默认情况下CentOS 7的mkfs.xfs会开启,但如果你用了老旧的工具版本,可能出现ftype=0,这会导致数据库创建工作目录时报错。用1确保打开。
挂载时建议加noatime参数,减少不必要的磁盘写入:
mount -o noatime,allocsize=64k /dev/sdb1 /dataallocsize=64k是XFS的预分配块大小,可以降低小文件碎片的概率。把挂载信息写进/etc/fstab,注意加上_netdev选项,防止网络相关的文件系统在网络上电之前挂载导致系统启动失败。
如果机器有多块盘,建议用RAID10做底层存储。Greenplum本身有数据副本机制(Mirror),但是RAID10的条带化带来的性能提升,加上Mirror的安全保障,两者叠加才能扛得住大数据量分析查询。
3. 安装Greenplum 6.8软件本体
环境准备好之后,开始装Greenplum软件本身。安装包从官网获取,整个安装过程本身不复杂,但是有几个细节会直接影响后续的存储区创建,值得展开说说。
3.1 安装包获取与解压校验
Greenplum 6.8的安装包大概是几百MB的rpm文件。下载后第一件事不是急着安装,而是校验文件完整性:
md5sum greenplum-db-6.8.0-rhel7-x86_64.rpm拿官方公布的MD5值比对,防止下载损坏。我遇到过rpm包下载不完整但能解压成功的情况,后期初始化集群时疯狂报错,排查半天才发现是安装包的问题。
解压后是一个可执行文件,运行后会释放出真正的rpm包:
unzip greenplum-db-6.8.0-XXXXXX.zip ./greenplum-db-6.8.0-rhel7-x86_64.bin这个过程需要root权限,安装到默认路径/usr/local下面是常规做法。安装完成后,greenplum的二进制文件位于/usr/local/greenplum-db-6.8.0,同时会出现一个软链接/usr/local/greenplum-db指向最新版本。这个软链接很关键,后续所有环境变量都依赖它。
3.2 环境变量配置:GP的PATH和LD_LIBRARY_PATH
安装完软件后,切换回gpadmin用户,需要配置环境变量。打开/data/gpadmin/.bashrc,加入以下内容:
source /usr/local/greenplum-db/greenplum_path.sh export MASTER_DATA_DIRECTORY=/data/gpadmin/data/master export PATH=$PATH:$MASTER_DATA_DIRECTORYgreenplum_path.sh这个脚本是Greenplum自带的,会自动设置PATH、LD_LIBRARY_PATH、PYTHONPATH等环境变量。注意务必在gpadmin用户的环境配置里source它,root用户不需要。
MASTER_DATA_DIRECTORY这个变量是本篇文章主角——数据存储区——的关键一环。它指定了master节点的数据目录位置。Greenplum的架构里,master节点只保存元数据和全局数据字典,不存实际业务数据,但缺少这个目录,集群无法启动。我习惯把master数据目录放在独立路径下,跟segment数据目录分开管理。
全部配置好后,执行source ~/.bashrc验证greenplum命令是否可用。
3.3 配置/etc/hosts与SSH免密
Greenplum集群内节点之间的通信走TCP/IP,而主机名解析依赖/etc/hosts。在每台机器上配置统一的主机名映射:
192.168.10.11 gp-master 192.168.10.12 gp-seg1 192.168.10.13 gp-seg2IP地址换成你自己的。这里有个小坑:主机名不要用带下划线或特殊符号的名字,Greenplum有些脚本对主机名校验很严格,纯字母加横线是最稳的。
SSH免密配置是初始化集群的前置条件。在gpadmin用户下执行:
ssh-keygen -t rsa -N "" cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys然后把公钥分发到所有节点的gpadmin用户的authorized_keys里。单机环境(测试用)也要做这一步,因为master和segment可能在同一台机器上通过SSH连接来交换状态信息。
做完这步,验证一下:ssh gp-master执行hostname,能免密返回结果就说明配置成功。
4. 数据存储区设计:创建之前先想明白这几个问题
现在到了本篇核心内容。我见过太多人一上来就gpinitsystem,然后被一堆参数搞晕。实际上创建数据存储区,本质上是回答三个问题:目录放哪里、目录叫什么名字、每个节点放多少个segment实例。想清楚了再动手,一次就能成功。
4.1 Greenplum的存储架构与数据目录逻辑
Greenplum的数据存储区和单机数据库完全不同。在单机数据库中,数据目录就是一个目录,比如PostgreSQL默认的/var/lib/pgsql/data。Greenplum中,每个segment实例都有自己独立的数据目录,master也有自己的数据目录,它们一起构成一个集群级的“数据存储区”概念。
用一张表来理清结构:
| 组件 | 数据目录 | 作用 |
|---|---|---|
| Master | 保存pg_control、全局系统表 | 管理元数据,不存业务数据 |
| Primary Segment | 保存用户表数据分片 | 对外提供查询服务 |
| Mirror Segment | 保存Primary的副本 | 主段故障时自动接管 |
每个Segment数据目录下都有类似PostgreSQL的目录结构:base、pg_xlog、pg_clog等。这些目录由gpinitsystem自动创建,不需要手动mkdir。
理解这层关系后,目录设计就有了判断依据。生产环境里,最好让不同segment的数据目录落在不同的物理磁盘上,这样可以避免多个segment并发写同一块盘的IO瓶颈。如果磁盘资源有限,至少要做到多个segment目录散落在不同挂载点。
4.2 目录规划:SEG_PREFIX、端口号与数据目录的命名规则
gpinitsystem初始化时,需要指定数据目录的路径和命名前缀。规划方式直接影响后续扩容、维护的便利性。
我常用的目录结构是这样的:
/data/gpadmin/data/primary/gpseg0 /data/gpadmin/data/primary/gpseg1 /data/gpadmin/data/primary/gpseg2 /data/gpadmin/data/mirror/gpseg0 /data/gpadmin/data/mirror/gpseg1 /data/gpadmin/data/mirror/gpseg2这里有两个关键参数:
- SEG_PREFIX:数据目录的前缀。上面例子中我用的前缀是gpseg,数字部分是gpinitsystem自动编号的。Segment编号从0开始递增,master数据目录则固定使用gpseg-1(负数表示master)。
- 数据目录路径:就是存储区的物理位置。每个segment目录必须提前创建好还是交给gpinitsystem自动创建?答案是:如果使用DATA_DIRECTORY数组指定路径,gpinitsystem会自动创建segment目录,但父目录(比如/data/gpadmin/data/primary)必须存在且属主为gpadmin。
端口号分配方面,Greenplum会自动从PORT_BASE开始,按每台机器上segment的数量递增。比如设置PORT_BASE=40000,那么第一台机器上第一个segment端口是40000,第二个是40001,以此类推。Mirror端口由MIRROR_PORT_BASE指定,例如41000。
注意:端口号不能和系统已有服务冲突,也不能在段与段之间重复。设计时留出足够的间隔,比如primary从40000开始,mirror从41000开始,两者间距根据segment数量定。
4.3 计算Segment数量与内存分配
Segment数量是数据存储区规划中最需要计算的参数。设少了浪费硬件性能,设多了会把内存吃光。
核心公式是这样的:Segment建议总数不要超过CPU核数。这个约束的原因是:每个segment进程是单线程模型,如果segment数超过CPU核数,就会发生多个segment竞争CPU的情况,反而降低整体吞吐。
内存方面的计算更关键。假设机器有64GB内存,一般建议给操作系统预留16-24GB,剩下的分配给segment。每个segment占用的内存大致可以估算:默认情况下,每个segment的work_mem和shared_buffers加起来,再乘以segment数量,不能超过剩余内存的70%,剩下留给操作系统的page cache。
举个例子,一个单机测试环境:4核8GB内存的虚拟机,算下来每台机器建议2个segment。如果非要跑到8个segment,初始化和启动能成功,但跑查询时会频繁触发操作系统swap,性能惨不忍睹。
实际经验:宁可segment数量更少但每台机器硬件更强大,也不要过度拆分。GP的优化器在segment数量增多时,分布式计划的调度开销也会增加,这个拐点大约在单机8个segment左右。
4.4 决定是否配置Mirror(数据镜像)
Mirror是Greenplum高可用的核心机制。开启Mirror后,每个Primary Segment的副本会存放到另一台机器的Mirror Segment上,Primary故障时系统会自动切换到Mirror继续服务。
创建数据存储区时要不要启用Mirror?我的建议是:
- 生产环境:必须启用。没有Mirror的Greenplum就像没有RAID的数据库服务器,任何一块磁盘损坏都可能导致整个集群不可用。
- 测试环境:可以不启用,节省一半的磁盘空间和内存占用。
- 磁盘预算不足时优先考虑降低segment数量,而不是砍掉Mirror。
Mirror目录的规划和Primary对称,放在不同的物理磁盘上,避免Primary和它的Mirror共享同一块物理盘(否则等于没有镜像)。
5. 手把手创建数据存储区:gpinitsystem完整实操
规划做好了,就进入实际操作。Greenplum创建数据存储区的核心命令是gpinitsystem——相当于对集群的一次“格式化”。它读取一个配置文件(通常命名为gpinitsystem_config),根据配置在每台机器上初始化master和所有segment的数据目录。这一节完整走一遍过程,包含配置文件的每一个字段说明。
5.1 编写gpinitsystem_config配置文件
在gpadmin用户下创建一个目录专门放配置文件:
mkdir /data/gpadmin/gpconfigs创建gpinitsystem_config文件,下面是一份可用的模板:
# 集群名称,标识GP集群用 ARRAY_NAME="Greenplum Data Platform" # master主机名 MASTER_HOSTNAME=gp-master # master数据目录位置 MASTER_DATA_DIRECTORY=/data/gpadmin/data/master # master端口 MASTER_PORT=5432 # segment数据目录的父路径,注意是数组 declare -a DATA_DIRECTORY=(/data/gpadmin/data/primary /data/gpadmin/data/primary) # mirror数据目录路径 declare -a MIRROR_DATA_DIRECTORY=(/data/gpadmin/data/mirror /data/gpadmin/data/mirror) # segment前缀 SEG_PREFIX=gpseg # 每个Segment主实例对应的端口起始值 PORT_BASE=40000 # 镜像端口起始值 MIRROR_PORT_BASE=41000 # 选择数据库的编码格式 ENCODING=UNICODE # 写数据库登录方式 TRUSTED_SHELL=/usr/bin/ssh逐个字段解释含义:
- MASTER_HOSTNAME必须与/etc/hosts中的master主机名一致,不能写IP。如果写错,gpinitsystem会一直卡在SSH连接上。
- DATA_DIRECTORY是数组,数组元素个数必须等于每台机器上要创建的Primary Segment数量,而不是总Segment数。也就是说,如果机器A放4个segment、机器B放4个segment,数组里必须写4个路径。gpinitsystem用这个数组的索引顺序去跟hostfile里的主机顺序匹配,后面再细说。
- PORT_BASE从40000开始的原因,是为了避开了PostgreSQL默认端口5432和高端口临时段。如果你有其他服务使用40000段,自行调整。
- ENCODING建议用UNICODE,匹配大多数统计分析场景。
注意:这里DATA_DIRECTORY的数组数量和布局,决定了segment在物理机上的分布。如果你想在一台机器上创建6个Segment,就写6个相同的路径。如果想分散到多块盘,就写不同的挂载点路径,前提是这些路径都存在且属主是gpadmin。
5.2 hostfile文件:决定Segment分布的核心
创建seg_hosts文件(或叫hostfile),内容很简单——列出所有运行segment的机器主机名:
gp-seg1 gp-seg2这个文件里的主机顺序至关重要。假设gpinitsystem_config中DATA_DIRECTORY只有2个元素,而hostfile有2台机器,那么每台机器各分配1个Segment。如果hostfile有2台机器,DATA_DIRECTORY有4个元素,那么每台机器分配2个Segment——前2个元素给gp-seg1,后2个给gp-seg2。
这里是最容易踩坑的地方。我见过有人把DATA_DIRECTORY数组写6个元素,hostfile写2台机器,期望每台3个Segment,结果gpinitsystem按顺序交替分配,瞬间创建出不符合预期的布局。记住这个规则:gpinitsystem就是按数组索引依次分配给hostfile中的机器,循环分配。最简单的方式是让每台机器上的segment数量相同,并且DATA_DIRECTORY按机器顺序成组书写。
5.3 执行gpinitsystem初始化
配置文件写完,执行创建命令:
source /usr/local/greenplum-db/greenplum_path.sh gpinitsystem -c /data/gpadmin/gpconfigs/gpinitsystem_config -h /data/gpadmin/gpconfigs/seg_hosts-c指定config文件,-h指定主机列表文件,是后面整个初始化流程的输入。执行过程中会要求确认一些信息,包括是否启用mirror(如果配了MIRROR_DATA_DIRECTORY会自动启用):
- 它会先检查所有机器的目录可写性、文件系统类型、内存、内核参数。
- 然后初始化master数据目录。
- 接着在每台segment机器上创建Primary Segment的目录(目录名如gpseg0、gpseg1)。
- 如果是带上mirror的配置,再创建Mirror Segment目录。
- 最后启动master和所有segment进程。
初始化过程会输出大量日志,重点是注意有没有WARNING。有些WARNING是可以忽略的,比如关于检查文件系统挂载选项的提示;但ERROR必须处理,否则会中断初始化。
执行完成后,你会看到类似文字提示,同时master数据目录下的pg_log目录产生了初始化日志。此时可以检查segment进程是否正常运行:
gpstategpstate会列出集群所有segment的运行状态。正常情况下所有Primary和Mirror都应该是Up状态。
5.4 初始化的关键检查点:目录、进程、磁盘占用
初始化成功后,我习惯做三轮检查,确认数据存储区真的没问题。
第一轮查目录结构是否完整:
ls /data/gpadmin/data/master/gpseg-1 ls /data/gpadmin/data/primary/gpseg0正常时这两个目录下面有PG_VERSION、pg_hba.conf、postgresql.conf、base目录等文件。注意目录名称里的负号:master的目录名固定是gpseg-1(SEG_PREFIX是gpseg的情况下)。
第二轮查进程是否存活:
ps -ef | grep postgres每台机器上看到的进程数应该是固定的几个:master有一个postmaster进程,每个segment有一个postmaster进程。如果进程数少于预期,可能是初始化中途失败但gpinitsystem没报错。
第三轮查磁盘占用:
du -sh /data/gpadmin/data/*刚初始化的数据目录占用很小,每个目录大概几百MB(主要是预分配的WAL文件和系统表数据)。如果某个segment目录异常庞大,说明初始化出了问题,最常见的是redo日志预分配写满了目录。
6. 常见问题与排查技巧
安装和数据存储区创建这两步,几乎没有人能一次通过。把最常见的坑整理成速查表,按概率排序。
6.1 gpinitsystem执行失败的三大典型报错
我遇到过最多的初始化失败可以归纳为三类,每一类都有对应的排查路径。
第一类:SSH连接失败。
报错信息通常包含Connection refused或者Host key verification failed。原因要么是hostfile里的主机名解析不了,要么是gpadmin的SSH免密没有配置好,要么是目标机器SSH服务没启动。排查方式是在执行gpinitsystem的机器上手动ssh一次目标主机名,看看能否免密登录。
第二类:共享内存分配失败。
报错关键词including asshmmax or shmall or shared memory。这是内核参数没生效,多半是改了sysctl.conf后没执行sysctl -p,或者当前登录会话的ulimit没刷新。执行sysctl -p后重新登录gpadmin会话再试。
第三类:数据目录创建权限失败。
报错关键词Permission denied。原因很直接——父目录的属主不是gpadmin。创建/data/gpadmin/data时用了root账号,忘了chown。解决办法:
chown -R gpadmin:gpadmin /data/gpadmin/data6.2 初启动后segment显示Down状态的应对方法
数据存储区创建成功,但gpstate查到某些segment状态异常,这是第二高发的问题。常见原因有:
- 端口被占用:检查端口号范围是否和其他应用冲突,lsof -i:40000这种命令逐个排查。
- 内存不足:segment进程起不来,看master的pg_log目录里最新的日志,文件是stderr开头的csv日志,里面会明确写内存分配失败。此时需要减少segment数量或者加大机器内存。
- 磁盘写入失败:segment目录所在文件系统满了,清理空间后手动重启segment。
手工重启sevice segment的方法是:
gpstop -M fast gpstart如果gpstart都无法正常工作,就用gpstart -m进入维护模式单独把master拉起来排查问题。
6.3 关于数据存储区的扩容与后期维护
数据存储区创建完成不是终点。集群运行一段时间后,可能需要加机器、加segment来扩容。Greenplum支持在线扩容(gpexpand),原理就是为新增的segment创建新的数据目录,然后把已有表数据重新分布。
每个数据目录的完整路径,以后调整备份策略、加块盘、迁移数据时都要用到。我强烈建议在集群刚创建好的黄金时间(数据量还小)就做好目录规范文档和备份策略,而不是等到跑了大半年后再回来看这些目录——到那时候数据迁移的代价会非常大。
6.4 日常巡检数据存储区的核心检查项
即使集群一切正常,定期巡检仍然有必要。我自己的巡检周期和内容大致如下:
- 每周检查一次各segment目录所在文件系统的剩余空间,Greenplum如果磁盘写满会直接停止该segment,导致集群处于降级状态。
- 每两周执行一次gpstate -e查看mirror同步状态,确认mirror没有滞后。
- 每月检查master数据目录下的pg_log增长情况,及时归档日志文件,防止日志目录占满磁盘。
7. 实操过程中的个人心得
再分享几条基于实际项目的经验,它们对数据存储区的运行稳定性都有直接影响。
首先,如果你是在虚拟机上做测试,建议先关闭透明大页(Transparent Huge Pages)。Greenplum对内存访问模式很敏感,THP会导致查询期间出现间歇性的性能毛刺:
echo never > /sys/kernel/mm/transparent_hugepage/enabled同时把它写进rc.local保证重启后仍生效。
其次,不要轻易调整segment的postgresql.conf里的shared_buffers参数。gpinitsystem初始化时会根据内存自动设置一套还不错的默认值,手动改大不一定提升性能,反而可能因为内存超分导致操作系统OOM。真要调优,优先考虑work_mem和effective_cache_size。
第三,master的数据目录虽然不存业务数据,但它的pg_wal目录会持续增长。如果master数据目录和segment数据目录放在同一个文件系统,master的WAL增长可能挤占segment的空间。我习惯给master数据目录单独一个挂载点,哪怕只有几十GB,也能有效隔离风险。
最后,初始化完成后马上做一个全库备份是值得的。Greenplum的pg_dumpall可以把整个集群的元数据导出,这份备份在后续做恢复演练、架构变更时都是重要的基线。等数据量跑大了再回头备份,耗时长、风险高,远不如刚开始的几分钟来得划算。
数据存储区是Greenplum集群的根基。花点时间在规划和创建阶段,远比后期运维时处理各种数据目录错乱、磁盘泄漏问题省力得多。希望这篇实操分享能帮你少踩几个坑,一次就把存储区建好。