GreenPlum 调研笔记
1. 概述
GreenPlum中文社区的介绍中,将Greenplum定位成开源大数据平台,而不仅仅是一个MPP数据查询引擎。
Greenplum的优势:
- 处理和分析各种数据源的数据的平台:包括hadoop、Hive、HBase、S3等等,支持结构化、半结构化、非结构化数据
- 数据水平分布、并行查询执行、专业优化器、线性扩展能力、多态存储、资源管理、高可用、高速数据加载
- 接口可扩展,支持SQL、JDBC和ODBC等行业标准
- 集成数据分析平台:MADlib (Github 245个Star,半死不活)
- 在金融、保险、证券等领域有众多应用案例,具备较为完善的生态
- 采用 ** Apache 2 协议 **
架构
Greenplum基本架构包括:Master、SegmentHost。
- Master:Greenplum数据系统的入口,Client连接Master提供SQL。Master管理了全局系统目录,包含了有关Greenplum数据库本身的元数据(系统表)。Master的主备基于WAL预写式日志来实现主/备镜像。
- SegmentHosts:基于Postgresql 8.3的定制数据库,负责存储和处理用户数据。 一台Segment主机通常运行2至8个Greenplum的Segment。
- Interconect:Interconect是Greenplum数据库架构中的网络层,默认协议UDPIFC,如果使用TCP协议,那么Greenplum限制1000个Segment。
事务控制
Greenplum支持事务控制,当并发更新时Greenplum通过MVCC模型来保证事务数据一致性。
MVCC模型基于快照机制是Postgresql中的一个特性,能够管理数据行的多个版本。
MVCC
数据库ACID特性的描述:
Atomicity:事务的操作结果要么全部执行要么全部不执行
Consistency:总是从一个一致的状态转换到另一个一致的状态
Durability:事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
Isolation:事务的修改结果在什么时间能够被其他事务看到(SQL1992规范),隔离级别包括以下四个:
- 未提交读:事务能够看到其他事务没有提交的修改,当另一个事务又回滚了修改后导致读取到脏数据,这种情况又称为 脏读
- 已提交读:事务能够看到其他事务提交后的修改,这时会出现一个事务内两次读取数据不一致,这种模式下事务是不可重复读的。
- 可重复读:在两次读取时读取到的同一行数据是一致的,但是两次查询可能查到行数不一致(其他事务出现新的插入),这种情况称为幻读。
- 序列化级别:不允许出现幻读、脏读、不可重复读。
Greenplum中未提交读、已提交读隔离模式的效果和标准SQL一致;可重复读模式避免了不可重复读和幻读;Greenplum数据库并不完全支持可串行化模式(该模式时自动退化到可重复读模式),并且数据操作并非真正串行化的。
上述特性中,Isolation是关键,不同数据库实现了不同级别的隔离性,并且通常情况下使用锁来解决这些问题。
传统方案采用读写锁(读锁和读锁之间不互斥,写锁互斥其他所有锁),MVCC是一种完全使读写操作并发的方案(完全抛弃锁)。
用户执行事务时可以在SQL中指定,事务隔离级别:
1 | BEGIN; |
MVCC的实现:
在PostgreSQL中,每一个事务(包括单条SQL)都会得到一个被称作为 XID 的事务ID。Session请求事务操作时,PostgreSQL递增XID并赋给这个事务。
每一行记录都存储了事务相关信息,这些信息用于判断当前事务是否可见。
- xmin:在创建记录时,记录此时的事务id,后面每次update也会更新。
- xmax:在更新或删除或lock时,记录此时的事务id;如果记录没有被删除,那么此时为0。
- cmin:多语句事务存储创建这个元组的Command ID
- cmax:多语句事务删除这个元组的Command ID
一个事务会看到 xid < xmin 的行(这些行已经commit),并且这些行 xid > xmax (这些行已经被删除)。
cmin/cmax:用于多语句事务中,只在事务期间有意义,事务开始时该序列被重置为0。
每一个Segment数据库都有其自己的XID序列,Master会使用一个分布式事务ID,称为gp_session_id,Segment会会维护一个分布式事务ID到其本地XID的映射。
当一个Segment上的事务失败,会回滚所有Segment的修改。
一行支持二十亿个事务,这之后这一行将成为一个新行,通过一次VACUUM操作可以避免这样的情况。可以配置xid_warn_limit和 xid_stop_limit控制事务上限告警。
MVCC的实现存储了多个数据版本,非常容易造成表膨胀。VACUUM命令会标记过期行所使用的空间可以被重用。通常可以使用以下策略运行VACUUM命令:
- 重度更新的表,可能每天需要运行几次VACUUM。
- 运行了一个更新或者删除大量行的事务之后运行VACUUM。
- VACUUM FULL命令会把表重写为没有过期行,并且将表减小到其最小尺寸,同时该操作会锁表。
- 运行VACUUM VERBOSE tablename来得到一份Segment上已移除的死亡行数量、受影响页面数以及有可用空闲空间页面数的报告。
用户可以使用LOCK LOCK命令显示加锁([参考](https://gp-docs-cn.github.io/docs/ref_guide/sql_commands/LOCK.html))。
数据冗余和故障切换
部署Greenplum数据库系统时,Segment可以配置Mirror实例,当Primary节点宕机时,Mirror节点提供服务,如果系统中存在Segment没有配置Mirror,那么Segment会成为整个系统的单点故障。
Greenplum数据库中Segment镜像拓扑:
用户可以选择一台不同于Master节点的主机上部署一个Master实例的备份或者镜像。
后备Master利用事务日志复制进程保持与主Master同步,复制进程运行在后备Master上并且负责在主备Master主机之间同步数据。如果主Master失效,日志复制进程会停止,并且后备Master会被激活以替代它的位置。Master失效时,主备切换不会自动发生,需要外部激励触发。
2. 安装部署
官方Github上提供了从源码编译gpdb和gporca的完整步骤,同时也提供了预编译好的RPM和DEB包,以下安装不步骤参考网络上的一些文档,并非官方推荐的安装步骤(我没找到!!)。
准备工作
所有节点配置NTP服务
更新以下系统配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33sudo bash -c 'cat >> /etc/sysctl.conf <<-EOF
kernel.shmmax = 500000000
kernel.shmmni = 4096
kernel.shmall = 4000000000
kernel.sem = 500 1024000 200 4096
kernel.sysrq = 1
kernel.core_uses_pid = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.msgmni = 2048
net.ipv4.tcp_syncookies = 1
net.ipv4.ip_forward = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.conf.all.arp_filter = 1
net.ipv4.ip_local_port_range = 1025 65535
net.core.netdev_max_backlog = 10000
net.core.rmem_max = 2097152
net.core.wmem_max = 2097152
vm.overcommit_memory = 2
EOF'
sudo bash -c 'cat >> /etc/security/limits.conf <<-EOF
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072
EOF'
sysctl -p在每个节点中创建gpadmin用户用于管理Greenplum,并且打通该节点的集群免密
1
2
3
4
5
6
7groupadd -g 530 gpadmin
useradd -g 530 -u 530 -m -d /home/gpadmin -s /bin/bash gpadmin
echo "ruijie" | passwd --stdin gpadmin
su - gpadmin
只需要打通第一个节点到其他节点的ssh,之后执行 gpssh-exkeys -f hostlists 打通所有节点之间的互信
ssh-copy-id gpadmin@node11 && ssh-copy-id gpadmin@node12 && ssh-copy-id gpadmin@node13
安装Greenplum DB
下载RPM包,执行以下命令:
1 | yum localinstall -y greenplum-db-6.0.0-rhel7-x86_64.rpm |
安装完成后,安装目录为/usr/local/greenplum-db,同时还要将greenplum-db中的lib添加到ld.so.conf中:
1 | sudo bash -c 'cat >> /etc/ld.so.conf.d/greenplum.conf <<-EOF |
在/home/gpadmin目录下配置环境变量、修改目录权限、创建配置目录
1 | # /usr/local/greenplum-db/greenplum_path.sh 添加以下内容 |
初始化数据库
登录master的gpadmin用户,验证免密是否成功:
1 | 验证免密是否可用 |
配置文件模板位于/usr/local/greenplum-db/docs/cli_help/gpconfigs目录中,参考gpinitsystem_config创建配置文件/home/gpadmin/conf/gpinitsystem_config
1 | RRAY_NAME="Greenplum Data Platform" |
执行gpinitsystem -c /home/gpadmin/conf/gpinitsystem_config 初始化数据库。
如果需要使用冗余配置,则执行
1 | gpinitsystem -c gpinitsystem_config -h hostfile_exkeys -s {master备份节点} -S {master备份目录} |
配置文件
初始化完成后,master节点的 MASTER_DIRECTORY 目录下会自动生成gpseg-1目录,该目录中的文件类似pg的配置文件,包含:postgresql.conf、pg_hba.conf等内容。
初始化成功后,Greenplum会自动创建管理员用户(默认情况下为执行初始化化程序的用户)。
初次启动时,用户需要使用管理员用户登录,并创建Client使用的账号以及修改账号登录方式(pg_hba.conf)。
基本操作
1 | 下面的所有操作在Master节点上运行,且使用gpadmin用户 |
配置文件
Greenplum集群中包括:master参数和本地参数,这些参数存储每个实例的postgresql.conf、pg_hba.conf文件中。
master参数:
- 系统范围参数:编辑$MASTER_DATA_DIRECTORY/postgresql.conf文件
- 数据库级别参数:使用ALTER DATABASE xxx SET xxx TO xxx修改
- Role级别参数:使用ALTER ROLE xxx SET xxx TO xxx;修改
- 会话基本参数:在会话中使用SET XXX TO XXX修改
本地参数:本地参数保存在每一个postgresql.conf文件(包括:primary和mirror)中,要更新参数,可以使用 gpconfig 命令(如,gpconfig -c xxx -v xxx),也可以使用这个命令查看Seg的参数(如,gpconfig –show xxx)。
关于参数配置说明,可以参考服务器配置参数。
日志文件
以下方式可以查看GP集群的日志文件:
- 每个Master和Segment实例都在其数据目录的 pg_log中有它们自己的日志文件。
- Master的日志文件包含了大部分信息,应该总是首先检查它。
- gplogfilter工具可以用来检查Greenplum数据库日志文件。 如果要检查segment日志文件,使用gpssh在segment主机上执行gplogfilter工具。默认查找$MASTER_DATA_DIRECTORY 目录下的日志文件,用户也可以手工指定。
3. 高可用
高可用方案
- 硬件级别RAID:在磁盘级别实现数据冗余
- 数据存储总和校验:该机制是默认开启的,数据被写入磁盘时会计算校验和,下一次读取时检查校验和,从而达到防止磁盘上数据损坏的目的(涉及的配置项包括:ignore_checksum_failure和HEAP_CHECKSUM)。
- Segment镜像
- Master镜像
- 双集群:双ETL方案、”备份/恢复”方案
- 备份和恢复:gpbackup/gprestore工具备份/恢复Greenplum数据库,参考
配置Segment镜像
默认情况下,在GP集群运行时执行gpaddmirrors -p 10000,就能在本集群内创建Segment镜像,执行期间会提示输入mirror数据的存储位置。10000表示mirror服务的端口号在原primary基础上加上10000。
上述命令,以group方式创建mirror,如果用户需要mirror分散部分或者分布在另外的HOST上,那么需要定义文件指定mirror到primary的映射(参考)。
gp_segment_configuration表记录了所有primary和mirror的状态,以及连接信息,这张表常用用于判断mirror的状态。这张表中mode字段描述了Seg的三种状态:
- Change Tracking Mode :没有找到mirror实例
- resync:重新同步
- in-sync:同步完成
当mirror因为一些原因同步失败时,可以使用 gprecoverseg 进行一次增量同步,或者使用 gprecoverseg -F 进行全量同步。
gp_segment_configuration表的role和preferred_role表示 Segment 表示当前的状态,以及偏好状态。当它们不匹配时,就可能有每台硬件主机上活动主Segment数量造成的倾斜。为了重新平衡该集群并且让所有的Segment回到它们的首选角色,可以用-r选项运行gprecoverseg命令。
当Segment故障时,有以下恢复手段:
- 在Master节点执行gprecoverseg,将下线Segment重新上线。gprecoverseg会恢复数据文件,此时数据库的写活动被禁止。
- 当所有Segment状态为Synchronized时,可以运行gprecoverseg -r使Segment回到它们的首选角色。
- gprecoverseg -F是全量恢复手段:从活动segment实例(当前主实例)复制数据前, 删除离线segment实例的数据目录。
- gprecoverseg -i recover_config_file将失效Segment恢复到其他主机,参考
配置Master镜像
当GP集群正在运行时,通过gpinitstandby -s {standby_host}能够快速启动一个Master的镜像。
通过gpstate -f,可以检查Master Mirror的运行状态,正常情况下:standby master的状态应该是passive,WAL sender状态应该是streaming。
需要注意:StandbyMaster不能提供任何服务!
主master故障时,需要手工执行gpactivatestandby(如,gpactivatestandby -d /data/master/gpseg-1)来激活后备Master。激活Master主机后,可以执行psql dbname -c ‘ANALYZE;’。
关于Master恢复的一些问题:
激活后备Master后,官方建议一直将该Master作为主Master使用,并且初始化一个新的后备Master
要恢复原来的主Master遵循下面的步骤(下面将原Master主机成为MHost,当前Master主机称为SMHost):
- 备份 MHost 上的gpseg-1
- 在 SMHost 上运行:gpinitstandby -s MHost
- 检查 MHost 上后备Master的状态:gpstate -f(standby master 状态应该是passive,WAL sender状态应该是streaming)
- 停止 SMHost 上的Master:gpstop -m (即把当前的主master停掉)
- 在MHost上运行:gpactivatestandby -d $MASTER_DATA_DIRECTORY(即将当前备升级为主Master)
- 移除 SMHost 上的gpinitstandby,并在MHost上执行:gpinitstandby -s SMHOST
4. 数据备份和恢复
数据备份和恢复有以下两种方式:
- 并行:每台Segment主机都同时把其数据写入到本地的磁盘存储上
- 非并行:数据必须通过网络从Segment被发送到Master,后者把所有的数据写入它的存储中。
推荐使用并行方式,非并行方式时间上是将GP集群当做一个pg来执行任务。
gpbackup和gprestore
gpbackup和gprestore在github上是一个独立项目,不属于gpdb工程,其release是两个可执行文件,下载后放到gpadmin用户目录下就可以使用。
gpbackup 和 gprestore 支持以下功能:
- 并行备份恢复
- 全量备份、增量备份
- 备份整个数据库,或者 数据库特定scheme和表
- gpbackup将元数据和数据分开成不同文件可读文件,这些文件放在各个节点上
1 | 基本备份操作 |
其他关于GP集群备份的内容:
5. 扩容
对GP集群进行扩容需要注意的几点:
当Segment使用Mirror时,一次扩容最少需要两台机器(如果不使用Mirror则没有这种要求);
括容之后Segment需要对表进行重平衡:
- 重平操作是一次数据重写,会极大消耗磁盘IO,以及占用磁盘空间
- 表在重平衡期间不可用
- 用户可以控制表的重平衡顺序
- 重平衡不影响新创建的表
扩容之前的数据备份文件不可用,需要重新备份
扩容步骤:
准备节点:
- 配置系统变量,必要时候进行性能测试
- 安装Greenplum软件
- 创建gpadmin用户
- 配置SSH免密
初始化新节点:这个步骤将新的节点添加到GP集群中
- 创建扩容文件,这个文件可以手工编辑,也可以通过 gpexpand 命令生成(如何生成该文件参考)。
- 运行gpexpand -i input_file,将扩容实例上线,如果上述过程失败可以执行gpexpand –rollback回滚。
重分布表:此步骤一旦开始,那么需要重平衡的表变得不再可读写
- 执行gpexpand -d 60:00:00可以开始表扩容操作,-d表示重分布的最大时间限制
- 进行重分布时,通过gpexpand.status、gpexpand.expansion_progress、gpexpand.status_detail表可以查看重分布表的状态,调整gpexpand.status_detail的rank值还可以控制重分布表的顺序。
移除扩容操作
- gpexpand -c
6.数据对象
数据库
Greenplum中数据库有模板的概念,用户可以从模板创建数据库,新的数据库会拥有模板的所有表和数据。
- 默认模板包括:template1所有新建库的默认模板、template0系统数据库(如postgres)的模板
- 从模板克隆数据库:CREATE DATABASE new_dbname TEMPLATE old_dbname;
- 本质上模板和数据库等价,任何数据库都能当做模板
- 查看当前数据库:\l、查看pg_database表
表空间
表空间用于将数据库中的对象(如表、索引等)到不同的存储介质上,不同表空间的区别在于存储介质不同。
1 | -- 创建一个表空间,其存放目录要事先创建,并且所有Seg都能访问 |
查询pg_tablespace可以得到当前环境的所有表空间,Greenplum创建之后包含默认表空间:
- pg_default :默认表空间。由template1和template0数据库使用,存储位置为$PADATA/base/。
- pg_global :用于共享系统的catalogs,存储位置为$PADATA/global/。
Greenplum中的表空间和PG是一致的,可以参考这个文章。
SCHEMA
Schema从逻辑上组织一个数据库中的对象和数据。 Schema允许用户在同一个数据库中拥有多于一个对象(例如表)具有相同的名称而不发生冲突,只要把它们放在不同的Schema中就好,Public是默认SCHEMA。
用户可以设置search_path配置参数来指定在其中搜索对象的可用schema的顺序。 在该搜索路径中第一个列出的方案会成为默认schema。 如果没有指定方案,对象会被创建在默认schema中。
1 |
|
表
表分布策略
支持三种分布策略:
- DISTRIBUTED BY(哈希分布)
- DISTRIBUTED RANDOMLY(随机分布)
- DISTRIBUTED REPLICATED(全分布)
关于分布策略有以下几点需要注意:
不显示指定分布策略时,表如何分布取决于gp_create_table_random_default_distribution
使用随机分布时,不能在表中指定PRIMARY KEY 或者 UNIQUE 列
对于DISTRIBUTED BY可以自定义操作符
表存储模型
堆存储:
- 默认配置,模型和PostgreSQL相同
- 堆表存储在OLTP类型负载下表现最好,适合频繁修改的的小表
- 行级存储方式
追加优化存储:指定appendoptimized=true
- 成批地被载入并且被只读查询访问的事实表;
- 不推荐单行的INSERT语句
- 更新表时有功能限制(如事务中不支持UPDATE和DELETE等)
选择面向行或者面向列的存储:列表(appendoptimized=true, orientation=column)
- 支持行,列或两者的组合
- 面向列的表存储只能用于追加优化表
- 频繁的插入时,行表优于列表
压缩表: 指定(appendoptimized=true, compresstype=zlib, compresslevel=5);
- 只适用于追加优化表
- 可以进行整个表的压缩、或者指定列的压缩
参考介绍:选择表存储模型