|
|
Greenplum Database 管理员指南 V6.2.1
群,比如,安装GP数据库软件,建立新旧主机之间的ssh互信,执行性能评估测试,在
这些准备工作全部完成并且确认性能测试结果符合扩容条件后,即可开始下一步的数据
库扩容操作。
对于性能测试,首先应该在用于扩容的新主机上进行测试,在确认新主机的性能测
试符合预期之后,再计划一个业务空闲的时间窗口,或者完全没有业务的时间窗口,对
所有主机进行性能测试,因为,用户访问会影响测试结果的真实性,不利于对整体集群
的情况进行准确的评估。
在完成性能测试之后,如果性能测试的结果不理想,需要对集群的配置情况进行评
估,之后再排查可能导致性能不符合预期的原因,如果修改了某方面的配置,则需要重
新进行性能测试,直到性能测试的结果符合预期为止。
注意:性能测试非常重要,其反应的是主机的基本性能指标,是未来集群运行性能的基
础参考。编者提醒,主机的操作系统安装和Raid配置,以及操作系统参数的修改等,
一定要严格按照GP数据库安装要求逐项落实,毕竟性能测试不是真实的生产压力,不
可能发现所有的潜在问题,比如Raid策略和参数设置,连续IO读写测试与真实的多并
发IO请求完全不同,如有疏漏,等到真正开始数据重分布并承载业务压力时再发现,
就迟了,势必会拖长扩容的时间,影响业务的正常恢复。
将新的主机加入 ssh 互信
几乎所有的GP管理命令都依赖ssh互信,所以,首先要完成的是,所有新主机与现
有主机之间,完成ssh互信。不管是新建还是扩容,gpadmin用户的互信是必须要建的,
否则,数据库一定无法正常运行,虽然SQL命令一般不依赖ssh互信,但是,应该不可
能有哪个集群,永远不需要使用管理命令。
为了便于进行多机安装和配置,GP要求root用户也要建立ssh互信,使用编者的
自动安装部署脚本,不需要建立root用户的ssh互信,只需要运行安装的用户有sudo
权限即可,而ssh互信只会在gpadmin用户之间建立。在有些环境,甚至不允许使用
root用户来登录操作系统,所以,这时候的手动安装可能会比较麻烦一些。编者需要
提醒的是,无论如何,必须要有sudo权限,否则,无法正常的安装GP数据库,也无法
正常的进行扩容前的准备工作。
GP集群的主机名称,按照惯例,采用sdwN的形式,其中sdw是前缀,N是数字后
缀,如果需要,可以将前缀改为任何Alpha字符串,建议不要使用任何的特殊字符或者
大写字符,建议使用容易记住和辨识的前缀,这对于后续的使用和运维是有帮助的,特
别拗口的名称并不利于交流和书写记忆。另外,编者提醒,数字后缀,应该采用定长数
字,不足的位置为使用0补位,因为,比如在GPCC中,在gpinitsystem时,主机名
是按照字符串进行排序的,sdw2会排在sdw1之后,而sdw1x则会排在sdw2之前。
版权所有:Esena(陈淼 ) 编写:陈淼 - 350 -
Greenplum Database 管理员指南 V6.2.1
对于多子网端口的主机来说,按照惯例,一般采用在主机名之后,添加-M的形式
来命名子网端口,比如,主机名为sdw001,不同的子网端口可以是,sdw001-1、
sdw001-2等。建议不要使用其他特殊字符(比如下划线),而是遵守GP数据库的惯例。
建立 root 用户的 ssh 互信
1. 将集群中所有主机的主机名和子网端口,在一个主机名文件中列出,每行一个主机
名或者子网端口名称,不要有其他无关字符,编者还会把主机名和子网端口名称对
应的IP地址也一并列出,确保所有可能用得到的访问地址,都建立了ssh互信。另
外,对于用于扩容的新主机,将这些新主机的主机名在另一个单独的文件中列出,
因为,后续的一些只针对新主机的操作会用到该文件。
例如,Master的主机名为mdw001,Standby主机名为mdw002,现有两个计算节
点主机为sdw001和sdw002,新增2台主机的主机名为sdw003和sdw004,且,每
个计算节点主机对应2个子网端口。例如,all_hosts的内容如下:
172.28.4.250
mdw01
172.28.4.251
mdw02
172.28.4.1
sdw01
sdw01-1
172.28.8.1
sdw01-2
172.28.4.2
sdw02
sdw02-1
172.28.8.2
sdw02-2
172.28.4.3
sdw03
sdw03-1
172.28.8.1
sdw03-2
172.28.4.4
sdw04
sdw04-1
172.28.8.4
sdw04-2
版权所有:Esena(陈淼 ) 编写:陈淼 - 351 -
Greenplum Database 管理员指南 V6.2.1
new_hosts的内容如下:
sdw003
sdw004
2. 使用root用户登录Master主机,执行如下命令:
$ su -
# source /usr/local/greenplum-db/greenplum_path.sh
3. 对于6版本,需要先建立Master与每个主机的ssh互信。例如:
# ssh-copy-id -i ~/.ssh/id_rsa.pub root@sdw03
4. 使用gpssh-exkeys命令建立全局互信:
# gpssh-exkeys -f all_hosts
对于6之前的版本,不需要上一步操作,可以直接执行gpssh-exkeys命令,并根据提
示输入密码:
***Enter password for root@hostname: <root_password>
创建 gpadmin 用户
1. 使用之前创建的new_hosts文件,在所有新主机上创建gpadmin用户,例如:
# gpssh -f new_hosts -e 'groupadd -r -g 300 gpadmin'
# gpssh -f new_hosts -e 'useradd -r -m -g gpadmin -u 300 gpadmin'
2. 为gpadmin用户设置密码:
# gpssh -f new_hosts -e 'echo gpadmin | passwd gpadmin --stdin'
3. 确认gpadmin用户已经正确创建:
# gpssh -f all_hosts -e 'ls -l /home|grep gpadmin'
版权所有:Esena(陈淼 ) 编写:陈淼 - 352 -
Greenplum Database 管理员指南 V6.2.1
# gpssh -f all_hosts -e 'id gpadmin'
注意:预期的结果是,所有主机上,gpadmin用户都有相同的home目录,所有主机上
gpadmin用户的id命令输出完全一致。
建立 gpadmin 用户的 ssh 互信
1. 使用gpadmin用户登录Master主机,对于6版本,需要先建立Master与每个主机
的ssh互信。例如:
# ssh-copy-id -i ~/.ssh/id_rsa.pub gpadmin@sdw03
2. 使用gpssh-exkeys命令建立全局互信:
# gpssh-exkeys -f all_hosts
对于6之前的版本,不需要上一步操作,可以直接执行gpssh-exkeys命令,并根据提
示输入密码:
***Enter password for gpadmin@hostname: <gpadmin_password>
检查磁盘 IO 性能和网络性能
通过执行gpcheckperf命令来对新主机进行性能测试,包括磁盘的性能测试和网
络性能测试,详情可参考"系统性能检查"章节。例如,进行磁盘性能测试:
$ gpcheckperf -r d -f new_hosts -d /data1 -d /data2 -D -V
缺省的测试尺寸可能会很大,所以,请按照"系统性能检查"章节的建议逐渐加大
尺寸测试,该测试可能会耗时较久。这里不再详细介绍如何进行性能测试,"系统性能
检查"章节已经介绍的比较详细。需要注意的是,在对新主机完成全部的性能测试,并
对结果进行评估,确认新主机性能满足扩容要求之前,不能贸然进入下一步扩容操作。
版权所有:Esena(陈淼 ) 编写:陈淼 - 353 -
Greenplum Database 管理员指南 V6.2.1
新旧主机一起做性能测试
在开始正式初始化新的Instance之前,有必要做一个整体的性能测试,以评估新
主机和现有主机的整体性能基准,至少要确保新主机的性能不能低于现有主机的性能。
如果有可能,尽量进行离线测试,即停掉现有的GP数据库集群的服务,然后进行整体
的性能测试,如果无法满足离线的要求,也要尽可能做到在无作业时间窗口来完成整体
的性能测试,避免数据库任务对测试结果产生影响。具体测试方法,请参考"系统性能
检查"章节。磁盘的IO性能与已使用容量的百分比有关,尤其是使用百分比达到甚至超
过70%时,性能下降会非常严重,这种情况下,新主机与现有主机之间的磁盘性能对比,
不能只是简单看测试结果,还要考虑使用容量导致的性能下降,因为,新主机的IO性
能也会随着使用容量的上升而下降,如果有可能,应该用新主机的测试结果,与现有主
机第一次上线前的性能测试结果做对比。
初始化新 Instance
通过执行gpexpand命令来完成新Instance的初始化操作。总体上来说,需要分
三个阶段来运行gpexpand命令。第一阶段,通过运行gpexpand命令,生成扩容配置
文件,一般来说,这个阶段只需要运行一次gpexpand命令。第二阶段,通过运行
gpexpand命令,并指定扩容配置文件,gpexpand命令会创建新的Instance,并更
新系统表信息,生成包含用于数据重分布的信息的gpexpand模式。第三阶段,通过运
行gpexpand命令来完成数据的重分布,这一阶段,可能会多次运行gpexpand命令,
数据重分布过程是可以中断并继续运行的,所以,允许管理员灵活的安排数据重分布的
时间,直至所有数据表完成数据重分布。
生成扩展配置文件
gpexpand命令需要一个配置文件,来确定需要在哪些主机,以什么样的方式,创
建哪些新的Instance,这个文件需要通过-i参数来提供。在GP数据库的Master主机
上第一次执行gpexpand命令,而且没有指定-i参数,命令会进入一个交互界面,以获
取必要的信息,然后自动生成一个扩容配置文件。
在交互式界面,需要提供新增的主机名,或者,通过gpexpand命令的-f参数提供
一个主机名列表文件,如果指定了-f参数,只是不会再提示输入主机名,而其他信息
仍然需要交互式确认。当然,如果可以自行生成扩容配置文件,这一步可以跳过。
版权所有:Esena(陈淼 ) 编写:陈淼 - 354 -
Greenplum Database 管理员指南 V6.2.1
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 运行gpexpand命令。命令启动并进入交互界面,提示输入信息,以确定如何进行
扩容操作,并提示,退出还是继续。
3. 比如,不带任何参数的执行gpexpand命令,将会是如下形式的交互过程:
Would you like to initiate a new System Expansion Yy|Nn (default=N):
> y
Enter a comma separated list of new hosts you want
to add to your array. Do not include interface hostnames.
**Enter a blank line to only add segments to existing hosts**[]:
> sdw002
How many new primary segments per host do you want to add? (default=0):
>
Generating configuration file
Input configuration file was written to
'gpexpand_inputfile_20200817_225256'.
Please review the file and make sure that it is correct then re-run
with: gpexpand -i gpexpand_inputfile_20200817_225256
[INFO]:-Exiting...
4. 首先会询问是否要进行一个扩容操作,输入[y]以继续。
5. 如果没有通过-f参数来指定一个扩容主机名清单文件,则会要求输入主机名,当
有多个主机名时,使用英文逗号[,]分隔,不要输入子网端口的名称。例如:
**Enter a blank line to only add segments to existing hosts**[]:
> sdw002,sdw003,sdw004
如果只是要为现有集群中计算节点主机,增加Primary的数量,这一步不需要输
入任何内容,直接按回车继续即可。
6. 如果现有集群有Mirror,则会提示选择一个Mirror策略,可选项有spread、
group,缺省如果不选择,Mirror策略为group。
7. 询问希望为现有集群的每个计算节点主机,增加几个Primary,缺省为0,即,不
增加现有计算节点主机上的Primary数量。新扩容主机上Primary的数量会保持
与现有主机上Primary的数量一致。所以,假如现有每个计算节点主机上有6个
版权所有:Esena(陈淼 ) 编写:陈淼 - 355 -
Greenplum Database 管理员指南 V6.2.1
Primary,如果不输入或者输入0,则,新扩容主机上Primary的数量也会是6个,
如果输入数字2,则,扩容之后,所有计算节点主机上,都有8个Primary。
How many new primary segments per host do you want to add? (default=0):
>
8. 对于6之前的版本,还会询问Primary的目录位置,这样,生成的扩容配置文件中,
将会生成以输入的路径为参考路径的Primary工作目录,不要输入具体的工作目
录的名称,gpexpand命令会在指定的目录下自动生成数据库的工作子目录。
例如,现有的数据库工作目录为:
/data/primary/gpseg0
/data/primary/gpseg1
为新扩容Primary指定的路径应该是这样:
/data/primary
/data/primary
gpexpand会自动在/data/primary下创建gpseg2和gpseg3子目录。
9. 对于6之前的版本,如果有Mirror,会询问Mirror的目录位置,这样,生成的扩
容配置文件中,将会生成以输入的路径为参考路径的Mirror工作目录,不要输入
具体的工作目录的名称,gpexpand命令会在指定的目录下自动生成数据库的工作
子目录。
例如,现有的数据库工作目录为:
/data/mirror/gpseg0
/data/mirror/gpseg1
为新扩容Mirror指定的路径应该是这样:
/data/mirror
/data/mirror
gpexpand会自动在/data/mirror下创建gpseg2和gpseg3子目录。
在上述步骤中需要输入的目录,在新扩容的主机上,必须已经存在,否则后续的扩
容操作会报错说目录不存在,这些目录,gpadmin用户要有创建子目录的权限。在所
有信息收集完成后,gpexpand命令会在当前路径生成一个库容配置文件。例如:
gpexpand_inputfile_20200817_225256
版权所有:Esena(陈淼 ) 编写:陈淼 - 356 -
Greenplum Database 管理员指南 V6.2.1
扩容配置文件的格式
使用交互式界面生成扩容配置文件,可以满足一般的需求,如果对Mirror策略有
特殊需求,则需要对扩容配置文件进行自定义。
GP6版本的扩容配置文件的格式是这样的:
hostname|address|port|datadir|dbid|content|preferred_role
例如:
sdw003|sdw003-1|40000|/data/primary/gpseg4|6|4|p
sdw003|sdw003-2|40001|/data/primary/gpseg5|7|5|p
sdw004|sdw004-2|50000|/data/mirror/gpseg4|8|4|m
sdw004|sdw004-1|50001|/data/mirror/gpseg5|9|5|m
对于每一行记录,实际上对应的是一个,即将新初始化的扩容Instance的信息,
不同属性的含义如下:
属性
有效值
描述
hostname
主机名
生成扩容配置文件时,不会检查主机名是否存在。
address
网络端口名称
可以是同一个主机名的不同子网端口。
port
服务端口号
基于现有集群的端口号的 BASE 来增长。
对应gp_segment_configuration系统表的
datadir
目录名称
datadir字段,是数据库运行的系统表空间。
是系统中每个 Instance 的 ID,对应的是
整数,不能与现有
gp_segment_configuration 系统表中的 dbid
dbid
Instance 有冲突
字段,这个值是唯一的,而且最好是连续且没有空
缺的。
是系统中每个 Instance 的 content ID,对应的
整数,不能与现有
是 gp_segment_configuration 系统表中的
content
Instance 有冲突
content 字段,配对的 Primary 和 Mirror 具有
相同的值,整个系统中,必须是唯一且连续的。
该 Instance 是 Primary 还是 Mirror,p 表示
preferred_role
p 或者 m
Primary,m 表示 Mirror。
GP6之前版本的扩容配置文件的格式是这样的:
hostname:address:port:fselocation:dbid:content:preferred_role:replication_port
版权所有:Esena(陈淼 ) 编写:陈淼 - 357 -
Greenplum Database 管理员指南 V6.2.1
其中fselocation与6版本中的datadir的含义相同,都是数据库Instance的
工作目录。replication_port是6版本之前的概念,指的是,该Instance与配对的
Primary或者Mirror进行同步的服务进程的端口,如果要在6之前的版本自定义扩容
配置文件,这个端口要格外小心,因为很容易改出端口冲突的结果。
在6版本中,如果有除了缺省的表空间以外,还有其他表空间,还需要提供一个同
名且以(.ts)为后缀的表空间的配置文件,其格式为:
tableSpaceNameOrders=tablespace1_name[|tablespace2_name . . .]
tableSpaceOidOrders=tablespace1_oid[|tablespace2_oid . . .]
dbid|/path/for/tablespace1[:|/path/for/tablespace2 . . .]
dbid|/path/for/tablespace1[:|/path/for/tablespace2 . . .]
在6之前的版本中,如果除了缺省的文件空间以外,还有其他文件空间,还需要提
供一个同名且以(.fs)为后缀的文件空间的配置文件。其格式为:
filespaceOrder=filespace1_name:filespace2_name: ...
dbid:/path/for/filespace1:/path/for/filespace2: ...
dbid:/path/for/filespace1:/path/for/filespace2: ...
注意:在生成扩容配置文件之后,如果要定制化Mirror策略,请按照需要修改该文件,
可以自由的将任意的Mirror放置到任意主机的任意目录下,指定任意的端口,不过,
为了后期维护的方便,还是建议按照某种规律来安排Mirror策略。
初始化新 Instance
在完成了扩容配置文件的准备工作之后,就可以开始真正的扩容操作了,这一步,
才是真正的让 GP 数据库集群的 Instance 数量增加的操作,之前一直都是在为这一步
做充足的准备工作,因为,一旦初始化新的 Instance 成功了,是不可以回退的,所
以,要在这之前,把性能测试做周密,确保扩容后可以达到预期的效果。
这一步操作,要么成功,要么失败报错,几乎没有什么步骤,如果报错,先进行扩
容回退,然后,根据报错的信息解决问题,之后再重新尝试。
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 执行gpexpand命令,通过-i参数指定扩容配置文件。例如:
$ gpexpand -i input_file
版权所有:Esena(陈淼 ) 编写:陈淼 - 358 -
Greenplum Database 管理员指南 V6.2.1
如果是 6 之前的版本,还需要配合-D 参数来指定一个用于存储扩容模式的数据库。
在 GP6 中,由于扩容过程中数据重分布的机制的变化,不再需要特定的数据库来存储
这些信息,而是内置使用 postgres 数据库来存储。
gpexpand 命令会检查是否已经有扩容模式存在,如果有,则不会继续执行,而
是报错退出,所以,如果之前已经扩容成功了,要及时清理 gpexpand 模式,通过执
行 gpexpand -c 来完成。如果在存储扩容模式的数据库中有用户定义的模式叫
gpexpand,那么,很不幸,建议先修改这个名称,待扩容完成之后再改回这个名称,
编者想说的是,在业务中使用这个模式名称,一定是一位神人。
在完成了新 Instance 初始化并启动,创建完成 gpexpand 模式,生成重分布的
信息之后,gpexpand 命令会输出成功的消息,并退出。
在完成新 Instance 的初始化之后,就可以在 postgres 数据库的 gpexpand 模
式中,查看业务表的重分布的信息了。对于 6 之前的版本,不是 postgres 数据库,
而是-D 参数指定的那个数据库。
扩容失败回退
如果扩容失败了,也就是 gpexpand -i 这一步操作,出现了报错失败,命令会
提示,执行回退操作。如果此时数据库处于 Down 的状态,则,需要先将 Master 启动,
再执行回退命令,启动 master only 模式,使用 gpstart -m 来完成。
扩容失败的回退操作,执行 gpexpand,配合-r 参数或者--rollback 参数。例如:
$ gpexpand -r
或者:
$ gpexpand --rollback
注意:如果扩容失败了,回退之后,首先要解决报错日志中提到的问题,之后再重新尝
试扩容,否则,直接重新尝试,可能会得到相同的失败结果。
数据表的重分布
完成了新Instance的初始化之后,数据库加入了新的Instance,也加入了新的
版权所有:Esena(陈淼 ) 编写:陈淼 - 359 -
Greenplum Database 管理员指南 V6.2.1
存储空间和计算资源,但原有的数据,仍然只存储在旧的Instance上,新的Instance
上还是空的。所以,需要对数据表执行数据重分布的操作来重新平衡数据的分布。
在进行数据重分布时,数据库是可以正常使用的,实际上,完成了扩容配置之后,
新的Instance已经成功加入数据库集群之中,从定性的角度来说,扩容已经完成,即
便不进一步执行数据重分布操作,数据库的规模也不能回退到扩容前的状态。
在完成了新Instance的初始化之后,新创建的表,数据是分布在包括新增
Instance在内的所有Instance上的,此时的集群,对于新创建的表来说,和直接初
始化得到相同规模的集群,效果是完全一样的。只是,原有的那些表,数据还是倾斜的,
数据只分布在之前规模较小的集群,这是通过gp_distribution_policy系统表的
numsegments字段来区分的。
调整表的重分布顺序
对于一个数据数据重分布耗时可能会很久的系统来说,可以通过调整gpexpand模
式下status_detail表的rank字段的值来调整数据表执行数据重分布的顺序,让一
些更重要的表,先执行数据重分布操作,以尽早消除数据倾斜,将数据倾斜的影响降到
最低。
要调整gpexpand.status_detail表的rank字段的值,需要先连接到
postgres数据库(6之前的版本是gpexpand命令的-D参数指定的数据库),然后通过
UPDATE命令来修改rank字段的值。例如:
=$ UPDATE gpexpand.status_detail SET rank=10;
=$ UPDATE gpexpand.status_detail SET rank=1 WHERE fq_name = 'public.lineitem';
=$ UPDATE gpexpand.status_detail SET rank=2 WHERE fq_name = 'public.orders';
这三条SQL命令,首先是,将所有表的优先级调整到10,gpexpand生成的rank
缺省值是2。然后将public.lineitem这张表的优先级调整为1,将public.orders
这张表的优先级调整为2。当开始执行数据重分布操作时,第一张被执行的表将是rank
值为1的表public.lineitem,其次是rank值为2的表public.orders,然后是
gpexpand.status_detail中记录的其他表。虽然可以将一些表的名称从
gpexpand.status_detail中删除,这样gpexpand就不会对这些表进行数据重分布
的操作,但是,编者建议不要这么做,因为这些表会一直以倾斜的状态遗留在系统中。
版权所有:Esena(陈淼 ) 编写:陈淼 - 360 -
Greenplum Database 管理员指南 V6.2.1
使用 gpexpand 重分布数据
一般来说,执行数据重分布的操作,都是通过继续执行gpexpand命令来完成,虽
然这个命令还有很多不如意的地方,比如,gpexpand命令对每张表,执行数据重分布
操作时,都会显式的BEGIN事务和COMMIT事务,会Cache系统的类型,这些动作,对
于一个规模很大的集群来说,会额外消耗很多的时间。编者最近也为此花了不少心思,
改写了gpexpand重分布逻辑,将UPDATE操作替换为INSERT,在所有版本中都避免了
UPDATE的锁冲突,同时,重新写了一个脚本来解决数据重分布的显式事务开销问题,
本来也想继续修改gpexpand,但是发现动作太大,还是重写一个脚本更实用。
使用gpexpand命令来完成数据重分布,如同之前的两个阶段的操作一样,就是执
行gpexpand命令即可。
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 运行gpexpand命令。可以通过-d参数或者-e参数来指定数据重分布的时间。-d
参数确定的是运行多长时间,-e参数确定的是结束的时间点。-d参数的格式是
hh:mm:ss,-e参数的格式是YYYY-MM-DD hh:mm:ss。例如:
$ gpexpand -d 60:00:00
命令会一直执行到,所有的表都已经完成了重分布,或者命令执行的时间长度达到
了-d参数指定的长度,或者-e参数指定的时间点。缺省的(产品自带版本),gpexpand
会在每完成一张表的数据重分布后,修改gpexpand.status_detail表中的状态。
同时,在开始和结束命令时,gpexpand还会向gpexpand.status表中插入任务的开
始和结束的记录,最后所有表都完成数据重分布时,gpexpand.status表中会插入一
条status值为'EXPANSION COMPLETE'状态的记录,在此之后,数据重分布全部结
束,再次执行gpexpand命令,将会检测gpexpand.status表中是否有status值为
'EXPANSION COMPLETE'状态的记录,如果有,gpexpand命令将会直接退出。
监测数据重分布
在第二阶段,初始化新的Instance时,在gpexpand模式中,会创建一个视图,
名为gpexpand.expansion_progress,在执行数据重分布期间,可以查询该视图
来查看数据重分布的进展情况,这个视图会展示整体的重分布情况,包括未重分布的表
数量,已经重分布的表的数量等信息,如果在第二阶段指定了-S参数,则会生成简单
信息的视图定义,否则,会生成信息更全的视图定义,信息多,自然需要收集的信息也
越多,在生成表清单时,即,在生成gpexpand.status_detail表的记录时,需要
计算数据库集群中每张业务表的尺寸,这是一个非常耗时的操作,编者认为一般不需要
版权所有:Esena(陈淼 ) 编写:陈淼 - 361 -
Greenplum Database 管理员指南 V6.2.1
这些详细信息。
对于每张表的重分布情况,可以查看gpexpand.status_detail表的记录,主
要是记录每张表的重分布信息,是否还未开始,何时开始,正在重分布,何时完成等。
假如在第二阶段未指定-S参数,登录到postgres数据库(6之前版本是gpexpand
命令的-D参数指定的数据库),查询gpexpand.expansion_progress视图来查看数
据重分布的详细情况。例如:
=# SELECT * FROM gpexpand.expansion_progress;
name
| value
------------------------------+-----------------------
Bytes Left
| 349539847977
Bytes Done
| 29872937423
Estimated Expansion Rate
| 891.2392397293 MB/s
Estimated Time to Completion
| 00:23:08.239082
Tables Expanded
| 32
Tables Left
| 293
(6 rows)
对于在第二阶段指定了-S 参数的情况来说,该视图只会显示处于不同状态的表的
数量,不会有尺寸的统计,也不会有时间预估,实际上,时间的预估并不会很准确,因
为数据重分布的性能不完全与尺寸相关,还与表的数量有很大关系,尺寸为 0 的表,
重分布的耗时并不是 0 秒,因为事务的时间开销与数据量没有关系。
清除扩容用的模式
在完成所有的数据表的重分布操作之后,需要清理gpexpand模式,这样,在以后
再进行扩容操作时,才不至于因为gpexpand模式已经存在而导致操作报错。对于6之
前的版本来说,清理了gpexpand模式之后,还有必要将专门用于扩容的数据库删除,
切记在6之前的版本,为扩容创建一个全新的空数据库,扩容完成之后,要清理并删除
该数据库。
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 使用带-c参数运行gpexpand命令。例如:
$ gpexpand -c
Do you want to dump the gpexpand.status_detail table to file? Yy|Nn
版权所有:Esena(陈淼 ) 编写:陈淼 - 362 -
Greenplum Database 管理员指南 V6.2.1
(default=Y):
> y
编者建议,当询问,是否将扩容的重分布信息备份为文件时,建议选择备份,以便
于以后还可以查看和再确认数据重分布的情况。
版权所有:Esena(陈淼 ) 编写:陈淼 - 363 -
Greenplum Database 管理员指南 V6.2.1
第十七章:数据库的升级
目前,能见得到的在用大版本,基本上只有4.3版本,5版本和6版本,更早的版本
几乎已经见不到了,所以,这里也不做介绍了。目前,已知的所有跨大版本的升级,都
是不能直接升级的,比如,4.3升级到5版本或者6版本,5版本升级到6版本,这些都
不能直接升级,必须通过重建集群,备份并恢复DDL,迁移数据,来间接的完成升级操
作。
小版本升级
小版本升级,指的是,Catalog版本号一致的版本之间的升级操作,按照
Greenplum的版本规则,4.3系列是一个大版本,5系列是一个大版本,6系列是一个
大版本,在大版本内的升级,全部属于小版本升级,小版本升级,主要是替换软件包,
除此之外,还可能会有一些函数或者功能的修补,这些都会在官方的版本发布文档中有
详细说明。
升级条件
检查运行GP数据库的主机硬件环境,以确保其符合GP数据库的运行要求。实际上,
这个操作,不仅仅是在升级之前要做,在日常运行中,也应该每个几个月做一次检查,
根据每次的检查结果进行纵向对比,以便于发现硬件性能的变化。
可以通过gpcheckperf命令来进行硬件的性能测试,更多关于硬件性能测试的介
绍,可以参考"系统性能检查"章节,或者参考gpcheckperf命令的说明。
如果需要执行gpcheckcat命令,应该在准备升级之前的几周之前,确定一个维护
时间窗口,因为执行gpcheckcat命令最好是在Restrict模式下进行,如果发现了
Catalog问题,需要在升级之前进行修复。
gpcheckcat命令位于$GPHOME/bin目录下,在执行该命令时,如果数据库不在
Restrict模式下,可能会得到不准确的结果。
如果gpcheckcat命令检查出了Catalog的不一致,可以尝试通过-g参数来生成
修复不一致的SQL脚本。不过,并不是任何的Catalog不一致都可以自动生成修复脚本
版权所有:Esena(陈淼 ) 编写:陈淼 - 364 -
Greenplum Database 管理员指南 V6.2.1
的。在执行了修复的SQL脚本之后,应该再次尝试执行gpcheckcat命令并生成SQL脚
本,以确保不再有Catalog不一致的情况。
注意:只有一些简单的Catalog问题可以自动生成修复SQL,如果gpcheckcat报错,
且无法生成修复SQL,可能需要专业技术支持来帮助解决这些Catalog问题。
如果在之前的版本配置了PXF,则,需要在升级之前,停止PXF的服务,备份PXF
的配置文件,以便于在升级之后恢复PXF的配置文件,以及重新配置PXF服务。具体操
作,请参考PXF相关的文档说明,编者不打算介绍任何PXF的内容。
如果在之前的版本配置了GPSS(Greenplum Streaming Server),同样需要
在升级之前停止GPSS的服务。在升级完GP数据库之后,再根据GPSS的版本要求进行相
应的升级操作,详情请参考GPSS相关的升级说明。
小版本升级步骤
1. 使用gpadmin用户登录到需要升级的GP集群的Master主机。例如:
$ su - gpadmin
2. 确保数据库中没有事务在运行。例如:
=# SELECT * FROM pg_stat_activity
WHERE state <> 'idle' AND pg_backend_pid() <> pid;
对于6之前的版本,这个SQL是不同的。例如:
=# SELECT * FROM pg_stat_activity
WHERE current_query <> '<IDLE>' AND pg_backend_pid() <> procpid;
3. 执行CHECKPOINT操作,确保数据库的所有修改都能及时刷到磁盘。例如:
$ psql -d postgres -c "CHECKPOINT"
4. 采用fast模式停止数据库,使用-a参数,不需要提示确认:
$ gpstop -af
5. 上传新的GP软件安装包。
对于rpm安装包来说,需要在所有主机上进行安装,所以,需要在每个主机上传安
版权所有:Esena(陈淼 ) 编写:陈淼 - 365 -
Greenplum Database 管理员指南 V6.2.1
装包,比如,上传到/tmp目录下。
对于6之前的版本来说,如果使用的是bin安装包,可以在Master上安装,之后将
安装后的目录打包分发到所有其他主机进行解压。
6. 使用root用户登录,安装GP数据库软件包。
例如,对于RHEL/CentOS操作系统来说,安装rpm安装包的方法:
$ sudo yum install greenplum-db-<version>-<platform>.rpm
对于使用bin安装包的情况,安装方法是使用bash命令。例如:
$ sudo bash greenplum-db-<version>-<platform>.bin
根据交互式提示,进行必要的输入以完成安装。
在6版本,已经支持Ubuntu操作系统,Ubuntu操作系统安装rpm的方法:
# apt install greenplum-db-<version>-<platform>.deb
7. 使用root用户,修改安装目录的权限。例如:
$ sudo chown -R gpadmin. /usr/local/greenplum*
8. 如果有必要,修改Master和Standby主机上的greenplum_path.sh文件。例如:
如果使用了LDAP认证,需要修改greenplum_path.sh文件加入LDAP的信息:
export LDAPCONF=/etc/openldap/ldap.conf
如果使用了PL/Java,可能需要在greenplum_path.sh文件修改
JAVA_HOME和LD_LIBRARY_PATH的设置。
最好将新版本的greenplum_path.sh文件与现有版本进行对比,对于一些扩展
功能需要使用到的设置,在新版本的greenplum_path.sh文件中进行同步的更
新。
9. 确保在gpadmin用户的.bashrc文件中已经正确的source了新版本的
greenplum_path.sh文件。例如:
将如下的一行信息:
source /usr/local/greenplum-db-<current_version>/greenplum_path.sh
版权所有:Esena(陈淼 ) 编写:陈淼 - 366 -
Greenplum Database 管理员指南 V6.2.1
修改为
source /usr/local/greenplum-db-<new_version>/greenplum_path.sh
如果使用的是软连接,也可以修改软连接,指向新的版本。例如:
$ rm -f /usr/local/greenplum-db
$ ln -s /usr/local/greenplum-db-<new_version> /usr/local/greenplum-db
10. source新的.bahsrc文件,或者使用gpadmin用户重新登录Master主机。例如:
$ . ~/.bashrc
11. 使用gppkg命令来重新安装一个需要使用的GP扩展。例如,pgcrypto, PL/R,
PL/Java或者PostGIS,需要重新从Network官网,下载对应新版本的安装包,
并使用gppkg命令进行安装。
还有一些其他的需要更新的扩展文件,比如JAR包,so文件等,一般来说,对于小
版本升级,这些文件是兼容的,直接从现有版本的安装目录COPY到新版本的对应
目录即可。
12. 所有主机的安装目录都完成了更新升级之后,就可以使用gpadmin用户来启动数
据库了。例如:
# su - gpadmin
$ gpstart -a
13. 如果在之前的版本配置了PXF,则,需要在升级之后,重新初始化PXF服务。具体
操作,请参考PXF相关的文档说明。
14. 如果在之前的版本配置了GPSS(Greenplum Streaming Server),在升级完
GP数据库之后,需要根据GPSS的版本要求进行相应的升级操作,详情请参考GPSS
相关的升级说明。
在完成升级之后,应尽快确认所有功能都可以正常工作。
排查升级失败
如果升级失败,请联系专业技术支持,编者也没有这方面的经验总结,故障总是有
各种各样的可能,专业技术支持,也是依靠报错日志的具体信息来判断问题,并采取合
版权所有:Esena(陈淼 ) 编写:陈淼 - 367 -
Greenplum Database 管理员指南 V6.2.1
适的措施来解决故障。当然,如果升级失败,还可以考虑降回之前的版本。
大版本升级
要实施大版本升级,将是一个复杂的工程,编者建议,如果有可能,最好获得专业
技术支持的帮助。从4.3版本向5版本和6版本升级,以及从5版本向6版本升级,可以
使用标准的备份恢复命令来做,也可以使用gpcopy来完成。编者提示,备份恢复的方
式升级大版本有一定的限制。
注意:GP开源版,只有5版本之后才有,5之前的版本都是商业版,没有开源版。
注意:目前不支持从4.3版本或者5版本直接升级到6版本,也不支持从4.3版本直接升
级到5版本。所以,这里介绍的大版本升级都是间接的升级方案。
本章节主要介绍大版本升级中可能遇到的一些问题,尤其是从4.3版本做大版本升
级时,会有比较多的语法等差异,所以,在从4.3版本做大版本升级时,需要做一些必
要的修改,以适应5版本或者6版本的特性。
准备一个新版本的 GP 集群
1. 使用新版本的GP软件部署一个新的GP集群。详情参见"安装部署与初始化"章节。
注意:gprestore只支持将备份数据恢复到规模完全相同的集群,而且
ContentID也必须保持一致。如果集群规模不同,则无法使用gprestore恢复来
完成升级的目标。当然,变通的方式也可以,比如,先建设一个相同规模的集群,
完成了gprestore的恢复之后,再对新版本的集群进行扩容。还可以使用gpcopy
等工具进行跨集群的数据迁移来完成不同规模集群的升级工作。
2. 安装部署gpbackup和gprestore命令。商业用户,可以从Network官网,下载
商业版安装包,或者,开源用户,可以从github下载源码进行编译安装。
3. 如果计划在现有集群的本地进行版本升级,需要确保有足够的磁盘空间可以使用。
考虑到现有版本集群存储了Primary和Mirror,占据了两份空间,完整的数据库
备份需要占据一份空间,新版本的Primary和Mirror也需要占据两份空间,所以,
整体上要占用5份空间,那么,现有版本集群的磁盘使用量,需要低于40%。如果
可以采用离线备份,将可以节省一些空间,新版本集群采用只初始化Primary的
方式,也可以节省一些空间,在完成升级之后再添加Mirror。
版权所有:Esena(陈淼 ) 编写:陈淼 - 368 -
Greenplum Database 管理员指南 V6.2.1
注意:不建议备份之后马上删除现有版本的集群,万一,通过备份来恢复集群的
操作出现异常,将会导致灾难性后果。
如果集群的磁盘空间不足,还想要在本地进行升级,那么gpcopy命令提供的
--truncate-source-after参数是一种选择,对于每一张表来说,当数据成功
被同步到新集群后,将现有版本的数据删除。这个方案并不是最佳的选择,因为,
一旦开始,想要回退到之前的版本,是非常困难的。
4. 在新版本的GP集群中安装现有版本中用到的扩展组件,比如MADlib、PostGIS
等,如果版本方面有不兼容的情况,可能还需要针对涉及的表进行单独处理。
5. 如果在现有的版本中使用了Oracle的兼容函数包,这个函数包在6版本中是不兼
容的,在6版本中使用数据库扩展组件的方式来支持Oracle兼容函数。例如:
$ psql -d dbname 'CREATE EXTENSION orafce'
对于其他的扩展组件,可以查看$GPHOME/share/postgresql/extension/
目录下的文件进行了解。目前6版本自带支持的扩展组件有:
citext
hstore
dblink
orafce
diskquota
pageinspect
fuzzystrmatch
pgcrypto
gp_sparse_vector
sslinfo
6.
要恢复一些基于PL语言的自定义函数,需要确保相关的LANGUAGE已经创建,如果
涉及到自定义的so文件,需要确保已经将特定的so文件已经按照新版本进行了编
译并放到了正确的路径。
7.
在GP6中提供了更成熟和完善的资源管理方案,资源组,用于替换原有的资源队列
的方案。通过设置gp_resource_manager参数为queue或者group来选择,使
用资源队列或者资源组。目前在6版本中,这个参数的缺省值是queue,但是从资
源组的发展来看,未来应该会是逐渐取代资源队列,成为缺省的资源管理方案。
如果是从4.3版本升级,缺省不需要关注这个问题,因为在4.3版本还没有资源组
的概念,直接使用原有的资源队列即可完成升级过程。如果希望平滑的从资源队列
向资源组切换,可以将资源组的内存管理模式保持与资源队列的行为一致,可以通
过设置资源组的MEMORY_LIMIT属性和MEMORY_SPILL_RATIO属性为0来实现。
更多关于资源组的介绍可以参见"使用资源组"章节。
版权所有:Esena(陈淼 ) 编写:陈淼 - 369 -
Greenplum Database 管理员指南 V6.2.1
通过备份恢复的方式升级
如果要使用备份恢复的方式来升级GP数据库,需要注意,4版本中,最低需要
4.3.22版本才能使用gpbackup和gprestore命令,而5版本中,最低需要5.5版本。
要在新版本恢复备份,必须要先获得一个全量备份。
下面是一些通过备份恢复的方式从4.3或者5版本升级到6版本的一些已知的问题。
在进行升级时,需要注意对现有版本进行相应的修改,以使得相关的特性适配新的版本。
如果是从5版本升级到6版本,且在5版本中配置了PXF,则需要根据PXF的升级说
明来完成PXF的升级。
在GP6中,不再支持gphdfs协议的外部表,所以,如果在之前的版本使用了gphdfs
协议的外部表,那么,在升级到6版本时,需要删除这些外部表,然后使用PXF协
议来重新创建相应的外部表。
4.3版本、5版本、6版本之间,系统表以及系统表的字段有了很多变化。所以,在
进行大版本迁移时,需要注意这些差异。
在6版本中,pg_class系统表的reltoastidxid字段被删除。
在6版本中,pg_stat_replication系统视图的procpid改为了pid。
在6版本中,pg_stat_activity系统视图的procpid改为了pid。
在6版本中,gp_distribution_policy系统表的attrnums字段改为了
distkey,增加了numsegments字段用于标识数据表的数据分布在多少个
Instance上。
在6版本中,删除了Filespace的概念,所以,也删除了pg_filespace和
pg_filespace_entry两张系统表。
对于DDL备份来说,如果UDF引用了的自定义类型或者其UDF,而该自定义类
型或者UDF的定义在DDL备份文件的后面部分,则UDF的恢复会失败,不过可
以尝试多执行几次DDL恢复来解决这类依赖问题。
在4.3版本,可读外部表支持INTO error_table,而该特性从5版本开始已经被
废止,虽然目前可以通过设置gp_ignore_error_table参数为ON来避免INTO
error_table语法报错,但是,已经没有error_table了,所以,外部表的定
义需要修改。
在6版本中不再提供只有一个参数的string_agg函数,在以前的版本中提供了只
版权所有:Esena(陈淼 ) 编写:陈淼 - 370 -
Greenplum Database 管理员指南 V6.2.1
有一个参数的string_agg函数,其效果与第二个参数为空字符是相同的。
在6版本中,lead和lag函数的第二个参数offset的参数类型从bigint改为了
integer,在4.3和5版本中,该参数的类型是bigint。
通过备份恢复的方式来升级GP版本会面临一个问题,那就是分布键字段在大版本
之间,有些字段的类型,其底层的二进制实现发生了改变。这种情况,将会导致,
gprestore不能正确的进行数据分布。这种情况在目前的4.3版本、5版本和6版
本之间都有存在。所以,如果可以使用跨集群传输数据的方式来完成大版本升级,
将不会发生这种情况,因为,gprestore是Instance本地的COPY,恢复时不会
有数据重分布的动作,然而,跨集群传输数据,一般采用外部表的方式,会自动进
行数据重分布。
在6版本中,abstime、reltime、tinterval、money和anyarray这些类型,
不能用于分布键。
在6版本中,YYYYMMDDHH24MISS这种日期格式,不支持直接转换为timestamp
类型。在4.3版本和5版本,这种日期格式是可以直接转换为timestamp类型的,
所以,这可能会是一个很麻烦的问题,比如,外部表加载的数据中有这种格式的时
间字段,那就很痛苦了。从用户的易用性角度来说,编者希望能重新支持这种格式。
在有些版本中,CREATE TABLE的DISTRIBUTED BY子句允许指定重复的字段作
为分布键,而后来这个问题被修复了,不再允许这种错误的行为,但是,gpbackup
备份出来的DDL信息中,分布键字段会包含这种重复字段。所以,选择一个更好的
DDL备份恢复工具,对大版本升级也很重要。
在4.3版本和5版本中,allow_system_table_mods隐藏参数的可选值有none、
ddl、dml和all(all不能在Session中设置),在6版本,这个参数变成了布尔
型,只能是ON或OFF和TRUE或FALSE。
从5版本开始,TEXT类型的隐式类型转换功能不再支持。
从5版本开始,Money,Numeric等类型的底层实现发生了变化,使用这些类型的
字段作为分布键的表,数据分布规律将发生改变。
从5版本开始,反斜线(\)缺省不再表现为转义符。而是需要使用(E'. . .')的
方式来显式的表明,字符串中的反斜线是转义符。
在进行大版本升级之前,做充分的测试是非常重要的。而且,备份恢复的方案未必
能够顺利的完成大版本的升级,编者建议,应该优先考虑数据同步的方案。大版本升级,
不仅涉及数据的搬迁,还涉及DDL的备份和修改适配,业务SQL的修改适配,各种管理
工具和客户端的适配。比如,4.3版本和5版本,6版本的系统表差异较多,一些客户端
工具会有各种各样的因系统表的不适配而导致语法报错。
版权所有:Esena(陈淼 ) 编写:陈淼 - 371 -
Greenplum Database 管理员指南 V6.2.1
通过数据同步的方式升级
1. 初始化新版本的集群,如果要进行本地升级,需要注意Instance的工作目录和端
口的配置,不能与现有集群有冲突。
2. 现有集群DDL备份。可以使用pg_dump、pg_dumpall等命令,编者也编写了一套
DDL的备份与恢复命令,可以根据即将用于恢复的版本确定备份的DDL的输出格式,
基本上不需要进行修改,即可在新版本集群进行DDL的并行恢复。例如:
$ gpddlbackup --database gpmagic -f gpmagic.ddl --target-version 6
3. 在新版本集群恢复DDL。例如:
$ gpddlrestore --database gpmagic -f gpmagic.ddl --object-bit 03FD
在目标数据库上恢复DDL,可以指定恢复的DDL的类型,比如此例中,暂时不恢复
索引信息,等数据完成同步之后,再恢复索引信息,以确保数据同步的性能。
在恢复DDL时,仍可能会有个别的错误信息,比如FILESPACE信息不会备份,所
以,对于6之前的版本,可能需要修改TABLESPACE定义的FILESPACE属性为已存在的
文件空间名称。
4. 执行跨集群的数据同步命令。例如:
$ gpdbtransfer --parameter-file parameter_file
其中parameter_file是一个参数文件,这样便于进行参数的维护,便于多次执
行命令。
5. 交换现有集群和新版本集群的端口。
注意:无论哪种大版本升级方案,都务必做好测试工作,确保所有业务和功能在新版本
上可以良好运行。在升级过程中再去临时解决突发问题,将会导致难以控制的时间成本。
注意:这里示例的命令是编者自己编写的命令,仅对编者服务的用户提供。类似的,可
以通过数据库自带的备份恢复命令完成DDL信息的备份和恢复,使用gpcopy命令实现
跨集群的数据同步。
版权所有:Esena(陈淼 ) 编写:陈淼 - 372 -
Greenplum Database 管理员指南 V6.2.1
第十八章:最佳实践
最佳实践,不是从源码得到的结论,而是众多实施经验的总结,是通过长时间的积
累,经过多次的验证,最终得出的经验性结论。最佳实践更符合科学的方法论,是对实
践经验的总结和归纳,可以更好的预期不同执行方法的结果。同时,最佳实践,不仅仅
是对过去的现象和经验的总结归纳,而是经过无数次的检验和再总结的结论,综合多方
面的技术和知识,得到的系统性结论。
这部分内容,编者还是第一次开始编写,所以,主体框架会以官方文档为基础,但
是,可以预见到的是,这个章节,将是编者的见解与官方文档差异较多的章节。
本章节,不会像其他章节那样,介绍GP数据库的功能细节和如何操作,而是重点
在讲述,如何做才是最好的选择,也就是所谓的最佳实践。
掌握了更多的最佳实践的知识,对于GP数据库的运维管理、性能优化等工作,都
可以起到很好的指导作用,也可以帮助很多初学者解决一些概念上的困惑。
最佳实践概述
本节,将大概介绍一下最佳实践的多个方面的内容。
数据模型
GP是MPP数据库,主要专注在分析型场景,所以,与传统的单机交易型数据库在模
型设计上会有所不同。因此,GP更推荐如下的模型设计:
对于非范式模型,GP数据库将会表现出更好的性能。比如星型模型和雪花模型,
数据库中的数据将以大数据量的事实表和小数据量的维表来进行存储。
不同的表之间,有关联关系的字段,采用相同的字段类型。
版权所有:Esena(陈淼 ) 编写:陈淼 - 373 -
Greenplum Database 管理员指南 V6.2.1
Heap 表与 AO 表
对于有高频度单条INSERT、DELETE和UPDATE操作的表和分区来说,采用Heap
表会更适合,这与Heap表和AO表的底层存储结构有关。
对于有高并发单条INSERT、DELETE和UPDATE操作的表和分区来说,采用Heap
表会更适合。这是对于6版本来说的,需要配合GDD(全局死锁检测)的功能来支持,
在6之前的版本,所有表的UPDATE和DELETE操作都需要EXCLUSIVE锁,Heap表
也是一样,所以,6之前的版本,并发的单条UPDATE和DELETE操作是排队的。
对于只会进行大数据量的批量操作的表来说,采用AO表更适合。对于AO表,不适
合高频度的单条INSERT、DELETE和UPDATE操作,也不适合高并发的单条INSERT、
DELETE和UPDATE操作。AO表,在设计上允许最多128个并发INSERT,且DELETE
和UPDATE操作不能真正的并发执行,需要获取EXCLUSIVE锁,进行排队执行。
要避免在AO表上执行单条INSERT、DELETE和UPDATE操作。
要避免在AO表上执行并发DELETE和UPDATE操作。虽然支持并发INSERT操作,但
是,并发INSERT会导致AO表的数据文件分裂,从而导致文件数的膨胀,最多会膨
胀到128倍,一旦出现大规模的AO表文件数膨胀,会对IO性能造成极其严重的影
响,大量的AO表文件数膨胀,还会影响文件系统的性能。
行存与列存
对于有高频度单条INSERT、DELETE和UPDATE操作的表和分区来说,采用行存表
会更适合,可以表现出更好的性能。
对于需要查询很多字段的表来说,采用行存表会更适合。
对于用途较广或者有混合负载的表来说,采用行存表会更合适。
对于表中字段较多,而只对少数字段进行查询和聚合的场景,采用列存表会更有优
势。需要注意的是,编者建议,如果使用行存表能够满足需求,优先采用行存表。
对于只会定期修改个别字段的表来说,采用列存表会更有优势。需要注意的是,编
者建议,如果使用行存表能够满足需求,优先采用行存表。
注意:虽然在有些情况下,列存表会更有优势,但是不等于说只要符合这样的条件就要
用列存。至少目前的AO表技术,为了支持并发INSERT,底层的数据文件是会分裂的,
版权所有:Esena(陈淼 ) 编写:陈淼 - 374 -
Greenplum Database 管理员指南 V6.2.1
最多会分裂为128倍的文件个数,所以,如果再加上列存的因素,列存表,每个字段单
独存储一个数据文件,列存表的并发INSERT会导致数据文件的个数严重失控,会带来
近乎灾难性的后果。更多介绍参见"选择行存或列存"章节的介绍。
压缩
对于不适合使用Heap表的大型事实表或者分区表,应该采用压缩表(压缩表必须是
AO表)。压缩表,可以降低IO的压力,节省磁盘空间。
编者建议,不要试图为列存表的不同字段设置不同的压缩属性,因为毫无意义。
在压缩级别和性能之间需要寻找一个平衡,越高的压缩级别,一般来说,意味着更
好的压缩效果,同时,会消耗更多的CPU资源来完成压缩和解压计算。编者认为,
在6版本开始,1到6级的ZSTD压缩是最理想的可选范围,如果对于压缩效果不是
特别敏感,也许1级ZSTD压缩是最好的选择,在6之前的版本,选择3到6级的ZLIB
压缩是最好的选择。
分布键
对任何表,明确指定分布键,或者使用随机分布,而不是依赖缺省的行为。
只要有可能,应该只使用一个字段作为分布键,而不是使用组合字段作为分布键。
如果不是为了特定的目的设计,不要为分析型用途的表,选择WHERE条件包含的字
段作为分布键。比如,查询是主键查询,使用主键作为分布键,并不会有任何不妥,
反而是最合适的设计,这一条的主要表达的意思是,不要让个别实例来承担一个大
的查询任务。
应该尽可能的避免使用日期或者时间字段来作为分布键。因为,一般不会使用这种
字段来与其他的表进行关联查询。
不要用分区字段作为分布键。因为,一般不会使用这种字段来与其他的表进行关联
查询。
为了改善大表之间的关联性能,应该考虑将大表之间关联的字段作为分布键。注意,
这里说的是大表之间的关联,但凡涉及与小表关联的场景,完全不应该作为选择分
布键的考虑因素。
版权所有:Esena(陈淼 ) 编写:陈淼 - 375 -
Greenplum Database 管理员指南 V6.2.1
要定期或者不定期的检查数据分布的倾斜情况。可以参考"数据的分布与倾斜"章
节获得更多关于检查数据倾斜的信息。
注意:如何界定分布键的选择是否合理,以大型任务计算不倾斜为最高目标。
内存管理
GP数据库要求设置vm.overcommit_memory为2。对于overcommit的三种选择
0、1、2对应了不同的行为,0,允许适度的超限申请内存,1,允许无节制的超限
申请内存,2,禁止超限申请内存。为什么GP要求配置为2呢,因为,对于0和1两
种情况,都有可能会触发oom-killer,一旦触发该行为,将无法确保数据库主服
务进程一定不会被选中成为被kill的进程,那将是十分危险的。
要禁用hugepage特性。主机的内存分配的控制,应该由GP数据库来统一管理。
设置好GUC参数gp_vmem_protect_limit以控制,在启用资源队列的情况下,
每个Instance所能使用的内存的上限。这个GUC参数的设置,一定要遵循GP的要
求,不能想当然乱改。
gp_vmem_protect_limit的值可以这样来计算:
编者并不清楚官方文档中的公式是如何得来的,难以理解,所以,编者不会介绍搞
不清楚的公式,编者按照自己的理解和实践经验来介绍。
首先,将主机物理内存的90%作为GP的可用内存。
GP可用内存 = 物理内存 × 90%
这里不考虑SWAP的尺寸,原则上SWAP尺寸与Mirror策略有关,通用的方案是
SWAP尺寸与RAM尺寸相同,但是SWAP只是为了保障可能发生Mirror切换时内存
不足的情况,在集群健康的情况下,应该永远都不要用到SWAP。
对于每个Primary来说,可用内存的量,与主机上Primary的数量成反比。
gp_vmem_protect_limit = 物理内存 × 90% ÷ 主机上Primary数量
得到的结果换算为MB为单位的数字,就是gp_vmem_protect_limit参数的值。
至于为workfile预留的内存尺寸,编者认为可以选择忽略。
版权所有:Esena(陈淼 ) 编写:陈淼 - 376 -
Greenplum Database 管理员指南 V6.2.1
绝对不要将GUC参数gp_vmem_protect_limit的值设置过高,甚至主机上所有
Primary的gp_vmem_protect_limit的值的和超过物理内存。
编者建议vm.overcommit_ratio的值设置为95,对于SWAP,只是一个保障,所
以,前面在计算gp_vmem_protect_limit的时候,编者并未引入
vm.overcommit_ratio这个参数,目标很明确,在健康的情况下,确保GP绝对
不会用到SWAP,在异常情况下,算上SWAP的尺寸,确保绝对不会超出最大可用内
存尺寸。
对于内存分配尺寸受statement_mem控制的场景,可以使用statement_mem参
数来控制每个Instance的内存使用上限。
结合资源队列的活动语句数限制(ACTIVE_STATEMENTS)和内存限制
(MEMORY_LIMIT)来控制资源队列中语句的内存使用量。
将所有用户都配置合适的资源队列或者资源组,而不是使用缺省的配置,这样有利
于按照预期去控制每个用户的资源使用情况。
注意:编者认为,对于资源队列的内存限制,也许没有很大的必要,通过设置资源队列
的内存限制来控制查询的内存开销可能意义更是不大,因为这些内存并不是总有语句在
使用,合理的超限配置,与任务的交叉可能会更有利于内存的充分利用。
分区
只对特别大的表进行分区--这是所有条件中必须满足的条件,不满足该条件的任
何表,都不应该进行分区。永远不要对小表进行分区,哪怕它的表结构和应用场景
非常的具有周期性和规律性。
选择分区字段时,要确保该字段可以用于查询条件,从而可以进行分区消除,以降
低查询扫描的数据量。
如果可以选择范围(range)分区,最好不要选择列表(list)分区。列表分区,每
个分区对应的都是孤立的值,对于只有有限个DISTINCT值的字段,进行分区,往
往没有必要,因为不会带来显著的性能提升。
要选择常常会用于过滤条件的字段作为分区字段。
不要用分布键作为分区字段。
不要使用缺省分区。PostgreSQL优化器一定会扫描缺省分区,而且,有缺省分区
的情况下,添加分区必须通过split缺省分区来完成。
版权所有:Esena(陈淼 ) 编写:陈淼 - 377 -
Greenplum Database 管理员指南 V6.2.1
杜绝使用多级分区,多级分区很容易使得表的数量失控,从而导致文件数失控。
需要合理控制分区粒度,不要过度零碎的进行分区。每个叶子分区,在每个
Primary上的数据量应该控制在100MB以上,或者记录数在100万条以上。比如集
群有100个Primary,那么可以使用一个通用的简化标准:每个叶子分区的数据量
在1亿条以上。同时,单表,在单个Primary上的记录数低于500万条时,建议不
做分区,即,比如集群有100个Primary,单表记录数在5亿以下时,可以不分区。
应该检查执行计划,是否有分区裁剪,以确定分区是否对查询有帮助。
当需要对列存表进行分区时,每个分区的记录数应该更大,因为列存表是按照每个
字段作为一个单独的数据文件来存储的。整个分区表的数据文件数量为:
文件数量 = Primary数量 × 分区数量 × 字段数量
比如,100个Primary的集群,一张表有100个分区,有100个字段,那么数据文
件的数量就会达到100万个,如果再有多并发INSERT导致AO表文件分裂,最坏的
情况下,文件数将达到1.28亿个,每个Primary上的文件数,最坏的情况下,可
以达到128万个,这些数字都是极其糟糕的。
在对列存表进行分区时,应该控制每个叶子分区,在每个Primary的记录数在
1000万以上。
注意:编者认为,合理的分区对于大表的查询性能提升和数据周期管理都有很大帮助,
所以,应该合理的使用分区表,但是绝对不要过度分区,也不要完全不用分区。
索引
通常来说,GP数据库不依赖索引。也就是说,索引,通常不是一种优化手段,一
些类似交易型场景,索引的确会有帮助,而分析型场景,索引不会带来任何好处。
对于高选择性的查询,可以在相关的字段上创建索引,以提升查询的性能。如果这
种查询很少发生,则创建索引的代价可能会远远超过带来的收益,所以,应该只为
高选择性,且会多次使用的查询场景,考虑使用索引来提升高性能。
避免为高频更新的字段创建索引。索引字段的更新一定会导致索引的更新,从而导
致索引的膨胀,严重的甚至导致索引失效。
对于加载数据量较大的场景,应该考虑删除索引后再加载数据,在完成数据加载后
重建索引。这个比较难找到一个确切的界限,当需要加载的数据量不是很大,也不
版权所有:Esena(陈淼 ) 编写:陈淼 - 378 -
Greenplum Database 管理员指南 V6.2.1
是很小时,重建索引未必会比直接带索引加载更快,所以,这需要根据经验来衡量。
应该为高选择性字段创建B-tree索引,而不是Bitmap索引。
对于需要被更新的字段,不应该使用Bitmap索引。编者认为,实际上Bitmap索
引,在GP数据库中,几乎没有存在的价值,因为GP数据库中,数据是分散的,单
看一个Primary上的数据,选择性会比从整个集群角度看到的选择性高很多。
对于分区表,尽量不使用索引,如果必须使用索引,一定要与分区字段不同。
更多关于使用索引的说明,可以参见"在GP中使用索引"章节。
资源队列
资源队列的最大作用是控制活跃语句数量,从而控制资源的争抢程度。编者想要解
释一下,为什么要控制活跃语句数量,这与资源有关,一定的硬件环境,计算能力
是有限的,太多的任务同时在执行,会使得系统资源出现严重的争抢,从而导致计
算效率严重下降。无论什么批处理系统,追求的最高目标永远是,任务量一定的情
况下,用最短的时间执行完所有的任务,而不是同时有更多个任务在执行。
所有的角色都应该设置合适的资源队列。
通过资源队列的ACTIVE_STATEMENTS属性来限制活跃语句的数量。
还可以通过资源队列的MEMORY_LIMIT属性来限制内存的使用量。不过编者建议,
一般不太需要这样做,除非内存资源过于紧张,经常出现内存不足的报错。
根据批处理的情况,适当的对资源队列的属性做出调整。
注意:应该考虑逐步使用资源组来代替资源队列,资源组对资源的控制粒度更细致。
监控与维护
要对系统表和数据库日志有日常的监控和维护。比如,系统表的定期VACUUM,或
者VACUUM FULL,系统表索引的定期REINDEX(在6之前的版本,pg_class的
REINDEX操作会导致pg_class表本身的索引的位置被更新到表的最后的page中,
这是需要注意的问题,所以一般来说,在6之前的版本,不对pg_class进行
版权所有:Esena(陈淼 ) 编写:陈淼 - 379 -
Greenplum Database 管理员指南 V6.2.1
REINDEX操作,万一做了并导致了性能问题,请联系专业技术支持)。
定期使用gpcheckperf命令对集群进行性能检查,并记录结果,以便于进行纵向
对比,提前发现严重的性能下降趋势,和可能存在的性能故障。
运用各种监控工具来记录系统的负载情况,包括且不限于CPU资源、内存资源、IO
资源和网络资源的使用情况。
对任何异常和故障,进行根本原因分析。这将有助于找到问题的根本原因,提前发
现可能出现的问题和风险,避免一些可能有问题的相关操作。
对系统中运行性能较差或者耗时超过预期的查询,检查其执行计划,寻找可能的优
化方法,提升系统的运行效率,降低系统运行压力。很多系统一直在可接受程度的
边缘苦苦支撑,不求深度优化,这是错误的,系统的高压运行,不仅仅是影响应用
的效率,还会为硬件增加严重的压力,降低整个系统的稳定性。
检查执行计划,确保是否正确的进行了分区裁剪或者索引扫描。这不是说建议使用
分区和索引,而是要确保,已经进行了分区的表,已经建立了索引的表,这些措施
和代价,是否真正带来了性能的提升,否则,分区和索引的代价就是徒劳的。
弄清楚各种日志的位置和内容,并进行必要的监控。比如pg_log日志中,及时发
现PANIC报错信息,及时的排查原因。
注意:并不是每个早期用户都善于进行监控与维护工作,对于商业用户来说,专业技术
支持的定期巡检工作中,会对GP集群进行必要的检查和维护,并会根据巡检的结果,
给出专业的监控与维护的建议,甚至会提供专业的命令和脚本用于日常的监控与维护工
作。不断的改进监控与维护措施,可以保障GP数据库长期高效而稳定的运行。
收集统计信息
将GUC参数gp_autostats_mode设置为on_no_stats(这也是缺省设置)并不
能避免需要ANALYZE。如果将GUC参数gp_autostats_mode设置为on_change
并且,将GUC参数gp_autostats_on_change_threshold设置为一个较小的值
(比如几百万),可以减少手动ANALYZE,但是,这样做会带来很大的资源开销,
同时,没有一个合适的阈值(不存在最佳设置)可以永远避免手动ANALYZE。
在有些时候,可以考虑使用analyzedb命令来收集数据库的统计信息。这个命令
的优势是,可以进行一定的增量识别,距离上次analyze之后,没有发生过变化
的表,不会再次被analyze。不过analyzedb和其他的很多数据库命令一样,无
法识别Heap是否发生了变化,只能识别AO表是否发生了变化。
版权所有:Esena(陈淼 ) 编写:陈淼 - 380 -
Greenplum Database 管理员指南 V6.2.1
在需要的时候,针对特定的表,执行ANALYZE操作。
在大规模数据量发生变化的INSERT、DELETE和UPDATE操作之后,有必要执行
ANALYZE操作。
有必要在CREATE INDEX之后,针对索引字段进行ANALYZE以收集统计信息。
如果全字段执行ANALYZE收集统计信息的性能较差,可以只针对JOIN条件字段、
WHERE条件字段、排序字段、GROUP BY字段和HAVING字段进行统计信息的收集,
对于只在结果中出现的字段,永远没有收集统计信息的必要。
在对大量的表进行数据修改后,可以执行analyzedb命令来更新统计信息,比如
扩容,升级等操作之后,通过analyzedb命令,可以并行快速的收集统计信息。
回收空间
在进行大量数据DELETE和UPDATE操作之后,应该对表进行VACUUM操作。不过,
编者建议,有时候REORGANIZE也许会是更好的选择,尤其是Heap表,因为Heap
表,VACUUM并不会真正的将空间返给操作系统,只是把垃圾空间记录下来以便重
新利用。而对于AO表,VACUUM和VACUUM FULL无法降低因为并发INSERT导致的
文件数膨胀问题,只有REORGANIZE可以解决该问题(编者实测所有版本如此)。
对于业务中使用的Heap表,不要进行VACUUM FULL操作,性能不好,应该使用
REORGANIZE来完成空间的彻底回收。而对于AO表,如果不需要解决并发INSERT
导致的文件数膨胀问题,则直接执行VACUUM即可,AO表的VACUUM与Heap表不同,
AO表的VACUUM会将空间返回给操作系统。
对于系统表,需要定期进行VACUUM操作,如果长时间没有进行VACUUM操作,则
可能会需要执行VACUUM FULL来回收空间,这与业务Heap表不同,系统表不能进
行REORGANIZE操作,所以,在必要的时候,必须进行VACUUM FULL。
对于系统表的VACUUM,官方文档建议不要kill,是的,任何数据库进程都不要
kill,但是可以cancel--至少在必要的时候,可以这样做,编者建议也应该尽
量避免cancel,最好在一个空闲时间来做系统表的VACUUM。
数据加载
版权所有:Esena(陈淼 ) 编写:陈淼 - 381 -
Greenplum Database 管理员指南 V6.2.1
Primary的数量越多,并行数据加载的能力就越强,这一点毋庸置疑,不过,实
际的性能还与其他因素有关,比如文件服务器的CPU性能,磁盘性能和网络带宽等。
如果集群规模特别大,需要加载的数据量特别大,单个文件服务器的性能无法满足
数据加载的要求,可以配置多个文件服务器,使得数据文件尽量均衡的分布在多个
文件服务器上。
将数据量特别大的文件均分到多个文件服务器上,可以充分利用多个文件系
统的性能。这是因为,单个文件系统的性能是有限的。
在一个文件系统上运行多个gpfdist服务。这是因为,单个gpfdist服务的
性能是有限的,实际上,gpfdist缺省按照32KB一个block来切分文件,性
能表现并不好,如果采用128KB到512KB的block来切分文件,会有极大的
性能提升,而且,gpfdist是单进程服务,一边切分数据文件,一边给request
发送数据,如果把数据发送改成异步,单个切分文件的进程,性能完全可以
达到3GB/S甚至4GB/S,而一边切分数据文件,一边发送数据的方式,最高
可以达到大约1.5GB/S的性能。
官方文档说,尽可能在多个网络端口上运行gpfdist,编者想说,gpfdist
一般都是直接监听IPV4的0.0.0.0地址和IPV6的::地址,gpfdist服务本
身并不区分网络端口,真正利用多个网络端口的方法,是在外部表中使用不
同的子网端口来访问gpfdist服务。还有就是,gpfdist和外部表之间没有
使用压缩传输,如果使用压缩传输,可能就不会有网络问题了。
通过GUC参数gp_external_max_segs来控制通过gpfdist外部表,访问
gpfdist服务的Primary数量。尤其是网络环境比较差的时候,可能需要降
低该参数的值以缓解网络压力过大导致的异常。
官方文件建议,保持gp_external_max_segs数量是外部表中location
数量的倍数。这可能是出于压力均衡的考虑,这个需要基于一个前提假设,
那就是,每个location指向的资源是均衡的,这个前提假设,在生产中其实
很难保证。
编者认为,如果能把gpfdist协议做到并发压缩传输,这些问题都将不是问
题,一个gpfdist利用多个CPU线程的资源,就可以使得切分发送文件的性
能达到3GB/S甚至4GB/S,市面上的主流服务器的IO性能也不过如此。
在装载较大尺寸的数据之前,应该考虑先删除索引,等数据装载完成之后,再重新
创建索引。需要提醒的是,这句话说起来很轻松,但实际操作却困难重重,比如一
个几十亿条记录的表,重建索引的代价也很大,重建索引期间,将没有索引可用。
因此,在条件允许的情况下,通过表交换的方式可以大幅减轻对现有业务的影响,
比如有规律的分区表,通过交换分区的模式来新增数据,非分区表,通过交换表名
的方式来新增数据,不过,这种操作一般只适合批处理操作,对于持续的交易型操
作,没有特别好的办法。
版权所有:Esena(陈淼 ) 编写:陈淼 - 382 -
Greenplum Database 管理员指南 V6.2.1
账户安全
保护gpadmin账户,不允许普通用户使用该账户,只有核心管理人员可以使用。
只在特殊情况下使用gpadmin账户,比如,系统维护、升级、扩容、故障处理等。
必须严格控制SUPERUSER权限的分配,因为,SUPERUSER可以跳过所有的权限限
制和资源队列的限制,甚至,不应该将任何普通角色加入具有SUPERUSER权限的
用户组--这样做也是有很大风险的,因为SET ROLE命令可以获得GROUP的权限。
批处理应用,业务应用,ETL应用,都不应该使用gpadmin用户。要把SUPERUSER
权限关在笼子里,否则会有很多麻烦。
为不同的用户,分配不同的数据库角色。
使用用户组来来管理对象的访问权限,尽量不直接对可登录的数据库账户赋权,这
样便于数据库账户的维护和权限管控。
保护好GP数据库集群中操作系统的root用户和gpadmin用户密码,并设置复杂且
不容易被猜测的密码。
保护好操作系统的重要文件的访问权限,不能被普通用户随意修改。
高可用
机械磁盘要做Raid,单个Raid 5的磁盘数量不宜过多,目前主流的2GB Cache
的双通道Avago(以前叫LSI,后来被Avago收购了)Raid卡,采用Raid 5时,一
个Raid组的磁盘数不宜过多,一般建议最多12块为佳,2U的X86主机,24块SAS
机械盘满配时,建议划分为2个Raid组,连续读写性能可以达到2.5GB/S到4GB/S
的范围。
如果有条件,建议采用Raid 1、Raid 5或者Raid 6的Raid策略,以满足磁盘
故障时,可以继续提供服务的目标。不过,Raid 1要损失50%的磁盘容量,Raid
6会大幅增加Raid卡的压力,所以,一般还是建议采用Raid 5的方案。
对于更换磁盘比较复杂的环境,建议设置HotSpare热备盘,这样可以避免,单盘
版权所有:Esena(陈淼 ) 编写:陈淼 - 383 -
Greenplum Database 管理员指南 V6.2.1
故障后长时间不进行更换导致的灾难性后果。编者建议,对于可以随时更换故障磁
盘的环境,热备盘未必是一个更好的选择,热备盘的Rebuild动作是自动的,并
不会因为任务多压力大而暂停,所以,在Rebuild期间,Raid的性能比坏一块盘
的情况还要糟糕,如果更换磁盘的周期很短,建议不配置Hotspare,而是在发生
单盘故障之后,选择一个任务空闲时段更换磁盘并进行Rebuild操作。
定期监控Raid的状态和磁盘的健康状况,及时发现Raid和磁盘的异常状态,并能
够及时采取措施进行修复。
定期监控磁盘使用率,在必要时,提前规划扩容。GP数据库要求,磁盘使用率不
能超过70%,这是一条永远都不应该触碰的红线,GP数据库长期运行在磁盘利用率
高于70%的状态,可能会导致多种难以控制的问题,比如,磁盘碎片率突增,磁盘
性能陡降,最终体现在数据库上的是,性能下降严重,数据库效率低下。
定期检查主机之间的磁盘容量是否发生倾斜。
为Master配置Standby。如果没有Standby,当Master出现灾难性故障,会导
致集群不可用,更严重的可能会导致数据难以恢复的灾难性后果。在配置了
Standby的情况下,应该密集的监控Master和Standby的同步状况,并及时处理
同步丢失的问题,确保Standby总是与Master保持同步状态。
设计好Master切换到Standby的后续工作,确保客户端的访问可以顺利过渡,比
如,为Master和Standby设置共用的虚拟IP地址,在激活Standby之后,将虚
拟IP漂移到Standby所在主机。当然,采用动态DNS也是一种选择,只是编者觉
得,这可能比采用虚拟IP要复杂的多。
为系统配置消息通知,在发生Instance故障时,及时通知运维和管理人员。
为Primary配置Mirror。这很重要,如果没有Mirror,任何一个Primary发生
故障,整个GP数据库集群就会进入不可用状态。
Mirror总是位于与Primary不同的主机上。关于Mirror策略,有多种模式,此
处不再展开说,详情可以参见"Instance镜像"章节。
当出现了Instance故障,应该尽快恢复集群的高可用状态,在执行
gprecoverseg命令之前,最好找到Instance故障的原因并解决,否则,集群恢
复之后,未解决的故障仍可能成为潜在的风险,或者影响集群的运行性能。
可以通过部署冗余集群的方式,实现灾备,同时可以获取更高的查询能力。截止目
前的6版本,GP还没有实现原生的容灾功能或者双活集群,所以,目前还是通过变
通的方案来实现灾备,目前编者的增量异地同步方案是已知最先进的方案。
如果GP集群部署了备份方案,绝对不应该在计算主机的本地磁盘上,保存备份数
据文件,应该采取离线存储的方式,否则,一旦计算主机出现灾难性故障,备份数
版权所有:Esena(陈淼 ) 编写:陈淼 - 384 -
Greenplum Database 管理员指南 V6.2.1
据文件也会随之丢失,就失去了备份的意义。
建议将数据保存到NFS目录,从而实现备份文件的离线保存,NFS文件服务器的性
能要有保障,避免因IO瓶颈影响备份的性能,每个计算主机,生成备份压缩文件
的速度,可以按照250GB/小时到500GB/小时进行评估。
系统配置
对于安装配置GP数据库主机,初始化GP数据库集群的管理员来说,应该按照最佳
实践的要求来修改和配置操作系统参数和GP数据库参数。
本节介绍的最佳实践的配置,如果使用编者的自动化安装部署初始化命令来进行一
键式GP数据库集群的安装部署,会自动完成这些最佳实践的配置,并不需要关心每一
项的细节,目前已经做到,执行一条命令,自动完成全部最优化设置的目标,编者自称
其为最先进的GP数据库自动化安装部署命令,不过,目前只服务商业付费用户。
文件系统
GP数据库要求工作目录必须运行在XFS文件系统上,因为XFS文件系统在处理大尺
寸文件时的性能更具优势,在RHEL和CentOS系统,使用如下的XFS挂载参数:
rw,nodev,noatime,nobarrier,inode64
由于Ubuntu操作系统不支持nobarrier挂载参数,所以,使用如下的XFS挂载参数:
rw,nodev,noatime,inode64
早些年的版本中,会提到一个挂载参数:
allocsize=16M
注意:这个挂载参数已经被证明,是一个不应该使用的挂载参数,这个参数除了会带来
麻烦,并不会带来任何的好处,因为针对所有的空间请求,XFS第一次都分配16MB是
极其浪费的,在一些极端场景,甚至会导致磁盘空间突增直至空间不足。
版权所有:Esena(陈淼 ) 编写:陈淼 - 385 -
Greenplum Database 管理员指南 V6.2.1
端口范围配置
在6版本的安装文档中,已经使用了新的端口范围配置规范,新的规范是,直接将
GP的服务端口范围从ip_local_port_range中扣除。官方文档的建议配置为:
在/etc/sysctl.conf文件中设置:
net.ipv4.ip_local_port_range = 10000 65535
基于上述配置,GP的Instance的服务端口选择小于10000的端口。例如:
PORT_BASE = 6000
MIRROR_PORT_BASE = 7000
编者不喜欢这种过于粗陋的方式,还是更喜欢如下的配置方式:
在/etc/sysctl.conf 文件中设置:
net.ipv4.ip_local_port_range = 1025 65535
net.ipv4.ip_local_reserved_ports = 5432,40000-40005,50000-50005
将GP的Instance的服务端口进行保留,而不是扣除更多无关的端口。
IO 参数配置
设置GP数据库运行目录所在的磁盘设备的blockdev的read-ahead尺寸为
16384,这个设置的单位是扇区(Sector),一般,一个扇区是512字节,所以,16384
对应的是16384 × 512字节 = 8M字节。例如,设置/dev/sdb设备:
# /sbin/blockdev --setra 16384 /dev/sdb
通过如下命令来获取/dev/sdb设备的read-ahead值:
# /sbin/blockdev --getra /dev/sdb
16384
设置IO调度方式为deadline。例如:
# for i in /sys/block/sd*/queue/scheduler;do echo deadline > $i;done
版权所有:Esena(陈淼 ) 编写:陈淼 - 386 -
Greenplum Database 管理员指南 V6.2.1
修改操作系统的最大打开文件数和最大进程数。例如:
# sed -e s/^ulimit/#ulimit/ -i /etc/profile
# sed -e /^[^#]/d -e /^[[:space:]]*$/d -i /etc/security/limits.conf
# echo '' >> /etc/security/limits.conf
# echo '* soft nofile 1048576' >> /etc/security/limits.conf
# echo '* hard nofile 1048576' >> /etc/security/limits.conf
# echo '* soft nproc
1048576' >> /etc/security/limits.conf
# echo '* hard nproc
1048576' >> /etc/security/limits.conf
# nprocname="/etc/security/limits.d/90-nproc.conf"
# if [ -f "/etc/security/limits.d/20-nproc.conf" ];then
#
nprocname="/etc/security/limits.d/20-nproc.conf"
# fi
# if [ -f $nprocname ];then
#
sed -e /^[^#]/d -e /^[[:space:]]*$/d -i $nprocname
#
echo '' >> $nprocname
#
echo '*
soft nproc
1048576' >> $nprocname
#
echo 'root soft nproc
1048576' >> $nprocname
# fi
注意:这里的修改方法是编者一直在使用的方法,与官方文档不一致,如果希望完全使
用官方文档的设置,请参考官方文档的相关内容。
开启core文件并设置到特定的目录位置。例如:
# grep core_pattern /etc/sysctl.conf
kernel.core_pattern = /var/core/core.%h.%u.%e.%p.%t
# grep core /etc/security/limits.conf
* soft core unlimited
操作系统内存参数配置
Linux的两个sysctl参数vm.overcommit_memory和
vm.overcommit_ratio控制着内存的分配方案。
GP数据库要求设置vm.overcommit_memory为2。对于overcommit的三种选择
0、1、2对应了不同的行为,0,允许适度的超限申请内存,1,允许无节制的超限申请
内存,2,禁止超限申请内存。为什么GP要求配置为2呢,因为,对于0和1两种情况,
都有可能会触发oom-killer,一旦触发该行为,将无法确保数据库主服务进程一定不
版权所有:Esena(陈淼 ) 编写:陈淼 - 387 -
Greenplum Database 管理员指南 V6.2.1
会被选中成为被kill的进程,那将是十分危险的。
vm.overcommit_ratio影响的是操作系统对于可用内存的计算,编者一般将这
个值设置为95,意思是说,操作系统的可用内存是SWAP + RAM × 95%。这么做并不
已定不安全,真正严格控制GP数据库使用内存的参数应该依靠GP数据库的GUC参数
gp_vmem_protect_limit(在开启资源队列时)或者
gp_resource_group_memory_limit(在开启资源组时)来控制,将操作系统可用
内存设置的很大,主要是为了保障发生Instance切换时的内存可用量,避免操作系统
出现OOM报错。例如:
# grep overcommit /etc/sysctl.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 95
要禁用hugepage特性。主机的内存分配的控制,应该由GP数据库来统一管理。例如:
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
共享内存设置
GP数据库需要使用共享内存来满足同一PostgreSQL实例的不同postgres进程
之间的通信。在sysctl.conf文件中,编者一直使用如下的设置:
kernel.shmmax = 5000000000000
kernel.shmmni = 32768
kernel.shmall = 40000000000
注意:与官方建议的值相比,编者已经把这些参数做了放大,目的是为了支持同一台物
理机上可以部署更多的Primary,以满足不同的需求场景。
每个主机上的 Primary 数量
每个主机上运行多少个Primary,这的确没有一个通用的公式可以使用,虽然没
有一个通用的计算公式,但是有一点是明确的,不同数量的Primary对数据库集群的
运行性能有很大的影响。每个主机上运行的Primary数量,不宜过多,也不宜过少,
这需要通过主机的资源情况来综合判断,很少有文章明确的涉及这个问题的细节,编者
版权所有:Esena(陈淼 ) 编写:陈淼 - 388 -
Greenplum Database 管理员指南 V6.2.1
在此尝试多说一些。
影响每个主机上适合运行多少个Primary的因素包括:
CPU Core的数量。这是一个关键因素。一般来说,对于生产环境,一个Primary
至少要有4到8个Core,否则,数据库集群的并发批处理能力将会很差。
主机上的可用物理内存的尺寸。早在十年前,内存还比较小的时候,GP的一体机
基本上是按照一个Primary 8GB的物理内存来配置,这从GUC参数
gp_vmem_protect_limit的缺省值(8192)就可以了解到,然而,十年过去了,
不仅单条内存的容量和单机支持的最大内存容量在快速增长,数据量也在快速增长,
所以,目前的情况来看,编者建议,每个Primary至少要有32GB左右的可用内存,
所以,目前,推荐的单台主机的内存配置最少是256GB。
内部互联网络的带宽。官方文档说的是网络端口的数量,编者认为这样说不准确,
比如单台主机上配置一个40Gb的网络端口,换做1Gb的网络端口,需要40个才能
得到理论上等价的网络带宽。编者建议,每个计算主机,至少配置2个10Gb的网络
端口,并使用mode 4的bound,确保有20Gb的内部互联网络的带宽,对于集群规
模超过100台的集群,编者建议可以为Master配置4个10Gb的网络端口,以提升
Master与Primary之间的交互能力。编者认为,网络带宽并不直接影响Primary
的数量,而是影响磁盘的IO能力是否会被网络拖累。
是否会在GP的计算主机上运行其他应用。编者建议,GP的设备要专用,一定要避
免与其他应用的混用,如果确有必要,请联系专业技术支持人员进行具体的评估,
以确定如何混合安装GP数据库集群。
基于这些因素,就目前主流的2U X86服务器来说,假如配置为,1块2GB Cache
支持Raid 5的Raid卡,24块10K SAS机械盘做成2个Raid 5,2个10Gb网络端口使
用mode 4的bound,64个CPU Core(开启超线程),256GB到512GB的内存,建议在
生产环境,配置4到16个Primary。配置4个Primary将拥有更好的并发能力,配置16
个Primary将拥有更好的单任务处理能力,但并发能力相对较差。当然,也可以配置
更多的Primary,只是,不太适合用于生产环境。
Instance 的内存配置
对于开启资源队列的情况,通过GUC参数gp_vmem_protect_limit来限制每个
Instance可以使用的内存总量的最大值。如果某个SQL导致了Instance的总内存使
用量超过了限制,会导致该查询失败,这种情况下,没有什么特别好的办法,要么降低
并发,要么降低每个查询的内存配额,如果GUC参数gp_vmem_protect_limit设置
已经与主机的物理内存相匹配,绝对不能随意增加该参数的值,那样会导致操作系统报
出OOM的错误,GUC参数gp_vmem_protect_limit并不是一个需要经常被调整的参
版权所有:Esena(陈淼 ) 编写:陈淼 - 389 -
Greenplum Database 管理员指南 V6.2.1
数,只要第一次进行了正确的设置,之后,只要集群的规模和物理内存配置没有发生调
整,原则上不需要进行修改。
编者建议,GUC参数gp_vmem_protect_limit的值,按照如下公式计算即可:
gp_vmem_protect_limit = 物理内存 × 90% ÷ 主机上Primary数量
编者不喜欢解释不清的花里胡哨的公式,按照编者的体系方案,可以确保数据库良
好高效的运行。
在开启资源组的情况下,由GUC参数gp_resource_group_memory_limit来控
制每个Instance可以使用的内存总量的最大值。
语句的内存配置
语句的内存使用量,一般通过statement_mem来限制。或者在开启资源组的情况
下(通过gpconfig配置gp_resource_manager为group来开启),如果GUC参数(或
者资源组的属性)memory_spill_ratio的值不为0的情况下,语句的分配内存由资源
组根据内存配额,最大活动事务数和memory_spill_ratio参数的值来决定,详情可
以参见"算子内存配额"章节。或者通过资源队列的MEMORY_LIMIT属性和
ACTIVE_STATEMENTS属性来控制语句的内存使用量。
一般可以通过如下的公式来计算statement_mem的值:
(gp_vmem_protect_limit × 0.9) ÷ 最大并发查询的数量
例如,最大的并发查询的数量为40,gp_vmem_protect_limit的值为8192(8GB):
(8192 MB × 0.9) ÷ 40 ≈ 184 MB
语句的内存使用量限制,是由statement_mem限制,还是由资源组限制,或者由
资源队列限制,这取决于资源管理方案的设置,不过,当对内存的需求超过了可分配的
限制,就需要将数据溢出到文件系统中,如果溢出到文件不能满足要求(通过溢出到文
件的方式不能满足内存不足的需求),查询就会失败。
当语句的内存使用限制受到statement_mem限制时,原则上,语句的内存使用上
限不能超过statement_mem的限制,当然,Orca优化器在有些场景会根据需要自动
突破这个参数的限制。
当语句的内存使用限制受到资源队列的限制时,语句的内存使用上限一般为:
版权所有:Esena(陈淼 ) 编写:陈淼 - 390 -
Greenplum Database 管理员指南 V6.2.1
MEMORY_LIMIT ÷ ACTIVE_STATEMENTS
注意:一般不建议将MEMORY_LIMIT属性和MAX_COST属性结合使用,因为执行计划对
于Cost的评估误差很大,会导致内存的分配完全失去基本的合理性。
要安全的增加statement_mem的值,需要确保gp_vmem_protect_limit的值
足够大,或者适当的降低并发查询的数量。不过,这句话的意思,并不是建议盲目的增
加gp_vmem_protect_limit参数的值,前面已经介绍过,这个参数的值不能随意增
大。
注意:编者认为,statement_mem与gp_vmem_protect_limit参数和最大并发查
询的数量这两个参数之间,并没有严格的等式关系,并不是说statement_mem的值一
定不能超过[(gp_vmem_protect_limit × 0.9) ÷ 最大并发查询的数量]计算的
结果,因为,很多时候,内存的真实使用量并不大。根据编者的经验,可以通过持续多
日的对系统资源进行统计,确定系统的最高活跃内存百分比,比如,当statement_mem
使用的是缺省的125MB的情况下,统计发现,系统的最高活跃内存百分比为30%,那么,
将statement_mem设置为125MB的3倍是安全的,用真实的数据来推导出一个合理的
值,总是比通过公式计算出的结果更实用。
溢出文件的配置
如果分配给语句的内存,不足以保证其完全在内存中完成计算,则需要将数据文件
溢出到文件系统以缓存中间计算结果。缺省情况下,一个查询在一个Primary上的溢
出文件的个数,不能超过100000个,这对于绝大部分的查询来说都是足够的,或者说,
如果超出了这个限制,那应该是查询本身的问题,而不是参数设置的问题。
可以通过控制GUC参数gp_workfile_limit_files_per_query的值来控制
一个查询在一个Primary上的溢出文件的个数,如果设置为0,就意味着对溢出文件的
数量不做任何的限制,不过,限制溢出文件的数量,可以防止劣质的查询对系统造成破
坏性影响。编者建议,不要修改这个参数,或者,如果要改,就改小一些,以阻止更多
的劣质查询对系统的影响。
如果内存严重不足,或者语句的计算出现严重的倾斜,则查询可能会导致溢出文件
的数量超出限制,此时,数据库会返回一个报错信息:
ERROR: number of workfiles per query limit exceeded
注意:最好不要尝试增加gp_workfile_limit_files_per_query参数的值。如果
遇到了溢出文件数量超过限制的报错,首先应该考虑如何优化SQL,检查倾斜。可能修
改内存参数也有助于缓解,然而,100000个文件数都超过了的话,可能需要非常大的
内存尺寸才能满足要求。
版权所有:Esena(陈淼 ) 编写:陈淼 - 391 -
Greenplum Database 管理员指南 V6.2.1
在gp_toolkit模式中,包含了一些和溢出文件信息相关的视图,通过这些视图,
可以查看当前系统中正在执行的SQL使用到的溢出文件的情况。这些信息将有助于排查
可能的问题:
gp_workfile_entries视图,每行记录,展示了查询的每个操作在每个
Primary上的溢出文件的使用情况。
gp_workfile_usage_per_query视图,每行记录,展示了每个查询在每个
Primary上的溢出文件的使用情况。
gp_workfile_usage_per_segment视图,每行记录,展示了每个Primary上
的总的溢出文件的使用情况。
这些视图的信息,对于排查当前系统的运行是否良好很有帮助。
GUC参数gp_workfile_compression用于控制溢出文件是否进行压缩存储,在
6之前的版本,类似的参数为gp_workfile_compress_algorithm,一般配置为
zlib,在6版本中,gp_workfile_compression是一个布尔型的参数,一般建议配
置为on。缺省情况下,溢出文件是不压缩的,编者建议压缩。
模式设计
GP数据库是一个MPP数据库,与共享的单机数据库相比,有很大的不同。对于非
范式模型,GP数据库将会表现出更好的性能。比如星型模型和雪花模型,数据库中的
数据将以大数据量的事实表和小数据量的维表来进行存储。
数据类型
使用一致的数据类型
不同的表之间,有关联关系的字段,采用相同的字段类型。如果关联的字段之间,
字段的数据类型是不同的,数据库在进行关联计算时,必须将数据进行动态的类型转换,
以适配不同类型的关联计算,所以,对于需要关联的字段来说,可能需要适当的调整数
据类型,比如增加数据类型的尺寸,以适配其他表中需要关联的字段的数据类型,对于
变长数据类型来说,数据类型定义上的尺寸增加并不会导致数据存储空间的上升。
版权所有:Esena(陈淼 ) 编写:陈淼 - 392 -
Greenplum Database 管理员指南 V6.2.1
使用合适的数据类型
对于定长数据类型来说,选择合适的数据类型,避免数据类型过大,可以节省存储
空间和提升计算性能。比如,通常建议使用变长类型VARCHAR和TEXT,而不是使用定
长类型CHAR,虽然这三种数据类型,对于相同的数据集合来说,并不会有性能差异,
但TEXT和CHAR可能会带来存储尺寸的增加,编者认为,对于AO表来说,不会带来存储
空间的增加。
通常会建议适合使用SMALLINT和INT类型时,不要使用BIGINT类型,这样会节
省存储空间,的确如此,不过在6版本之前,三种整数类型之间的关联查询可能会导致
NESTLOOP或者类型转换的开销,所以,如果不能确保关联字段之间采用相同的数据类
型,也许只使用BIGINT,比混合使用SMALLINT、INT和BIGINT更能带来实际的益处,
至少可以避免难以预料的类型转换问题。
存储模式
GP数据库,为建表语句,提供了多种存储选项,包括,Heap表与AO表,行存储与
列存储。在使用GP时,如何正确的选择存储选项,极其重要,毫不夸张的说,这是用
好GP的一项基本功,如果没理解不同存储选项的优劣,随意乱用的话,会带来很多的
麻烦,这个问题在之前的章节也有多次提到。如何正确的选择Heap表还是AO表,行存
表还是列存表,对于大型的事实表尤为重要,对于普通的维表也不能忽视。
关于存储模式的选择的最佳实践,包括如下内容:
1. 对于需要高并发单条INSERT、DELETE和UPDATE的场景,应该使用Heap表。
2. 对于频繁单条INSERT、DELETE和UPDATE的场景,应该使用Heap表。
3. 对于大型分析型事实表,应该采用AO表。
4. 对于大型分区表,应该根据分区的适用场景,不同的分区采取不同的存储模式。
5. 尽量减少使用列存表。只在特定的场景使用,例如,事实表的规模很大,表中有很
多字段,而查询只涉及少数字段,行存表无法满足性能要求,而列存可以有很大的
性能提升时,可以考虑使用列存表。
6. 对于大型事实表,应该尽可能的采用压缩存储,以节省磁盘空间和提升IO效率。
编者建议,Heap表只在类交易型场景使用,列存表,只在特定的超大表场景使用,
一般情况下,选择行存压缩AO表作为通用存储模式。
版权所有:Esena(陈淼 ) 编写:陈淼 - 393 -
Greenplum Database 管理员指南 V6.2.1
Heap表与AO表
缺省不指定任何存储模式的情况下(设置了gp_default_storage_options的
情况下,按照设置的属性作为缺省属性),创建的将是Heap表,Heap表与所有的
PostgreSQL的表的存储模式相同。对于有交易型并发单条INSERT、DELETE和
UPDATE的场景,以及,频繁的单条INSERT、DELETE和UPDATE的场景,应该使用Heap
表。
对于不会频繁修改数据的场景,应该使用AO表。对于AO表,必须避免频繁的单条
INSERT、DELETE和UPDATE,虽然AO表支持并发INSERT,但是,并发INSERT会导
致AO表的数据文件分裂,文件数最多会膨胀到128倍,所以,不要并发INSERT AO表,
问题很严重。另外,要避免并发DELETE和UPDATE AO表,因为AO表的DELETE和
UPDATE操作是EXCLUSIVE锁,并发操作必须排队。
AO表不适合用作频繁修改数据的场景,和Heap表一样,AO表的数据修改(DELETE
和UPDATE)只是将数据进行标记,并不会真正的被清理掉,而且,与Heap表不同的是,
Heap表的无效空间可以通过VACUUM进行重新利用,而AO表不能重新利用,只能进行
数据重新整理,类似重建表的操作。所以,AO表更适合一次加载很大的数据量,且很
少进行修改操作的分析型场景。
行存与列存
行存是传统的存储模式,一行记录的所有字段都紧凑的存储在连续的磁盘空间上,
这样,便于一次读写一整行的记录,这是最常见的数据库存储数据记录的方式。
列存是相对于行存而言的,在GP数据库中,列存是将每个字段的数据存储在一个
独立的数据文件中,当对列存表进行查询时,只需要扫描相关的字段的文件,这样,可
以大大降低IO的消耗。
对于偏交易型的场景,建议使用行存表,或者更准确的说,建议使用Heap表,以
更好的支持频繁的数据更新和插入操作。
对于查询中需要用到很多个字段的场景,应该使用行存表,对于用于多种工作负载
的表,也应该使用行存表,因为列存表的适用场景较少,主要用于只对少数字段进行分
析查询的场景。
列存表,对于查询来说,当只查询少数字段时,因为只扫描相关字段的数据文件,
会带来性能的提升,但是,对于INSERT和UPDATE操作,并不会带来性能的提升,因
为所有字段的数据文件都必须进行读写。所以,仅当业务场景的特点满足一定条件时才
适合使用列存表,首先是,数据量要很大,其次,数据很少发生变化,或者,数据的变
化都是批量操作,表的字段较多,但是分析查询时,只涉及少数字段。
列存,因为同一个字段的数据连续存储在一个独立的文件中,所以,数据具有更强
的相似性,与行存相比,当采用相同压缩选项时,列存的压缩效果会更好,从而可以节
版权所有:Esena(陈淼 ) 编写:陈淼 - 394 -
Greenplum Database 管理员指南 V6.2.1
省磁盘存储空间。但是,这不应该成为选择列存的主要理由,不该使用列存的场景,不
能因为可以更节省磁盘存储空间而强行使用列存。
对于列存,和行存相比,如果都读取全部的字段,并进行全表扫描,列存会消耗更
多的计算资源。
注意:编者提醒,如果使用行存,可以满足业务的性能需求,建议不要使用列存。
注意:编者反复强调不要随意使用列存的主要原因是,列存的一个最大的问题,就是文
件数量容易失控,这与目前GP使用的列存实现方式有关,编者认为,如果使用类似
Parquet格式的方式来实现列存,就不用过于担心文件数量失控的问题。
压缩
GP为AO表提供了多种压缩选项,使用压缩选项,可以节省磁盘存储空间,改善系
统的IO效率,可以根据适用场景,在不同的分区选择不同的压缩属性。
注意:添加分区表时,新增的分区的压缩属性不会自动继承上层的压缩属性(虽然曾经
有些版本是继承的),必须在增加分区时明确指定压缩属性,所以,养成新增分区时写
好WITH子句的习惯很重要,或者设置好gp_default_storage_options参数。
编者建议,在6版本之前,选择3到6级的ZLIB压缩作为通用压缩属性,在6版本开
始,选择1到6级的ZSTD压缩作为通用压缩属性,其他压缩算法和压缩级别,可以作为
扩展知识进行学习和了解,但是,编者认为没有实用性。比如1级ZSTD压缩,性能极好,
甚至有些时候,压缩效率未必比其他级别有显著的差距。虽然编者介绍了压缩算法和级
别的最佳选择范围,在实际使用中,如有必要,仍然可以通过测试来找到最适合项目场
景的压缩属性。
注意:永远不要在压缩文件系统上,使用压缩表。
分布键
在使用GP数据库时,正确的选择分布键,非常重要,分布键要确保数据分布的均
衡,因为,在MPP数据库中,查询的总时间由执行最慢的Instance决定,所以,整个
集群的速度等于最慢的Instance的速度。当数据分布存在倾斜的情况下,存储数据量
更大的Instance将需要花费更多的时间来完成计算,因此,所有的Instance应该存
储均衡的数据量,并且执行均衡的计算量。如果个别Instance存储的数据量远远超过
版权所有:Esena(陈淼 ) 编写:陈淼 - 395 -
Greenplum Database 管理员指南 V6.2.1
其他Instance,不仅会导致计算性能差,还可能会导致OOM类的报错。不过,OOM并
不一定是数据倾斜导致的,数据倾斜只是一种可能。
在选择分布键时,需要考虑以下因素:
对任何表,明确指定分布键,或者使用随机分布,而不是依赖缺省的行为。
只要有可能,应该只使用一个字段作为分布键,而不是使用组合字段作为分布键。
如果不是为了特定的目的设计,不要为分析型用途的表,选择WHERE条件包含的字
段作为分布键。比如,查询是主键查询,使用主键作为分布键,并不会有任何不妥,
反而是最合适的设计,这一条主要表达的意思是,不要让个别Instance来承担一
个大的查询任务。
应该尽可能的避免使用日期或者时间字段来作为分布键。因为,一般不会使用这种
字段来与其他的表进行关联查询。
不要用分区字段作为分布键。因为,一般不会使用这种字段来与其他的表进行关联
查询。
为了改善大表之间的关联性能,应该考虑将大表之间关联的字段作为分布键。注意,
这里说的是大表之间的关联,但凡涉及与小表关联的场景,完全不应该作为选择分
布键的考虑因素。
分布键字段应该使用唯一性较高的字段。虽然,主键往往是唯一性最好的字段,但
是,不建议为了选择一个分布键而去增加一个主键,这是一种逻辑颠倒的做法,通
常,应该选择一个常用于大表之间关联的某个唯一性较高的字段作为分布键,一般
这个字段可能在其他某个表中具有主键特征,例如,客户ID,例如会员卡号,例
如手机号码,例如身份证号码,等等。
如果没有某个字段适合单独作为分布键,就需要考虑组合分布键是否对关联查询有
帮助,如果有帮助,应该选择字段数量最少的可能性,一般建议永远不要超过两个
字段。
只有当关联条件包含全部的分布键字段时,分布键才能对关联有帮助,否则,必须
进行数据的重分布,所以,如果实在没有合适的单个字段或者两个字段用作分布键,
也许RANDOMLY分布会是一个不错的选择。过多的字段用作分布键,除了带来计算
分布键HASH值时更多的资源消耗,一般并不会带来其他好处。
要定期或者不定期的检查数据分布的倾斜情况。可以参考"数据的分布与倾斜"章
节获得更多关于数据倾斜的信息。
随机分布并不能绝对的保证每个Instance上的数据数量完全相同,或者误差在数
条以内,但可以绝对的保证数据的相对均衡。官方文档说,差异会小于10%,编者不清
版权所有:Esena(陈淼 ) 编写:陈淼 - 396 -
Greenplum Database 管理员指南 V6.2.1
楚这个数字是怎么来的,根据编者的经验,对于数据量较大的表来说,RANDOMLY分布,
Instance之间的记录数差异极小,远小于10%,编者认为10%可能是最坏的情况。
优秀的分布策略,对于大表与大表的关联,至关重要,对于GP来说,要执行表与
表的关联,相关的记录必须在同一个Instance上,如果相关的记录不在同一个
Instance上,则,在执行查询的过程中,必须在Instance之间进行动态的数据重分
布,当然,有些时候还可能会是广播操作。重分布,是将所有的数据根据关联字段重新
计算HASH值并确定数据重新分发到其他Instance,而广播,是将表中的所有数据在
每个Instance上分发一份完整的拷贝。
选择重分布还是选择广播,这是优化器基于两张表的规模进行的Cost评估,对一
张表进行重分布的代价是:
单个Instance的记录数 × gp_segments_for_planner × 每行的字节数
对一张表进行广播的代价是:
单个Instance的记录数 × gp_segments_for_planner2 × 每行的字节数
优化器会评估哪种选择的代价更低,以决定选择重分布或者广播。
本地关联
使用合适的分布键,使得数据均衡的分布在所有Instance上,并使得表之间的关
联可以实现本地关联,可以显著的提升关联查询的性能。当关联查询涉及的记录都位于
相同的Instance上时,关联操作可以在Instance本地完成,而不需要在所有
Instance之间进行数据重分布操作,这样,大大节省了数据移动的代价,避免了进行
大量的网络数据传输。
当关联的表之间无法实现本地关联(关联的字段不能全部包含分布键字段)时,就
必须在执行计划中加入数据移动(motion)的步骤(Slice),例如(Redistribute
motion)和(Broadcast motion),这样,执行计划会变得更复杂,而且,从磁盘读
取的到内存的数据副本,需要通过网络层,在所有Primary之间进行数据重分布,需
要消耗大量的网络资源,虽然,从理论上来说,如果从磁盘读出的数据都能够及时的发
送出去,重分布的影响会很小,但是,实际上,网络带宽往往都是有限的,虽然使用了
万兆网络,但相比于磁盘的性能和压缩率来说,还是完全不占优势,而且,有些时候,
表中的数据还可能来自系统缓存,所以,如果可以避免或者减少数据移动,对关联查询
会带来非常显著的性能提升。
版权所有:Esena(陈淼 ) 编写:陈淼 - 397 -
Greenplum Database 管理员指南 V6.2.1
数据倾斜
数据倾斜,往往会导致极其严重的性能问题,甚至导致OOM类的报错。数据倾斜,
不仅仅影响数据扫描操作的性能,对于很多执行计划中的算子来说,也会导致性能问题。
这与执行计划有关,比如,很多时候,Table Scan的下一步操作是Motion算子,那
么,可能是一个合理的重分布,数据之后就变的均衡,就不会影响后续算子的计算性能,
而如果Table Scan的下一步是Hash算子,然后是Hash Agg算子,那么,这些算子
在严重倾斜的Primary上,都会因为需要计算的数据量远远多于其他Primary而严重
影响查询的整体性能。
在完成大量数据装载之后,对数据表进行倾斜检查显得尤为重要,在日常的运维和
管理工作中,也应该定期的对数据表进行倾斜检查。可以参考"数据的分布与倾斜"章
节获得更多关于数据倾斜的信息。
下面是官方文档中示例的检查一张表的记录数的最大值、最小值以及差异性的例子:
SELECT 'Example Table' AS "Table Name",
max(c) AS "Max Seg Rows", min(c) AS "Min Seg Rows",
(max(c)-min(c))*100.0/max(c) AS "Skew Ratio"
FROM (SELECT count(*) c, gp_segment_id FROM facts GROUP BY 2) AS a;
这个SQL有分母为0的风险,而且,编者并不喜欢这种方法,这种方法需要对被检
查的表进行全表扫描,这是一种简单而粗暴的方式,也是性能最差的方式,如果需要对
大量的表进行倾斜检查,性能和时效方面都是无法接受的。编者在"数据的分布与倾斜
"章节介绍了目前最先进的检查数据倾斜的方案。
编者已经介绍了最先进的检查数据倾斜的方案,所以,gp_toolkit模式中的关于
数据倾斜的视图,编者不再介绍,有兴趣的可以自行研究一下,无异于count(*)。
计算倾斜
倾斜可能会有多种表现,比如,从整体的磁盘使用量分布来看,从每张数据表的尺
寸分布来看,从计算过程来看。对于管理人员来说,应该定期对磁盘使用量的分布和数
据表尺寸的分布进行监控,及时发现数据倾斜现象,计算过程的倾斜,一般比较难以在
运行之外的时间被发现,往往需要实时的介入。
倾斜,往往是数据库的性能和稳定性问题的根源,这不是危言耸听,这是无数的血
淋淋的教训的总结。对于数据分布的倾斜,通过检查表中数据的分布情况就很容易发现,
版权所有:Esena(陈淼 ) 编写:陈淼 - 398 -
Greenplum Database 管理员指南 V6.2.1
也很容易处理,一般是因为,没有指定分布键,或者选择了错误的分布键,只需要重新
选择一个合适的分布键即可完美解决。
然而,当倾斜发生在关联、排序、聚合等各种算子的计算过程中时,事情就变的十
分复杂,这种情况我们称之为计算倾斜。而要处理计算倾斜,可以说十分困难,一般的
技术人员很难发现,更不用说解决这种问题,但这也是用好GP非常关键的一门武功,
此门绝技练到第十层,应该可以算得上初级宗师了吧,实际上,在社区中,很多知名的
人物未必能够在处理计算倾斜时做到驾轻就熟,信手拈来,可见此门武功门槛极高。
几乎很少有介绍计算倾斜的文档和文章,因为这很难讲解,下面举个简单的例子来
介绍一下计算倾斜,以及如何解决。先来创建一张测试表并填充示例数据:
CREATE TABLE skew
(
a integer
)
WITH (APPENDONLY=true, COMPRESSLEVEL=1, COMPRESSTYPE=zstd)
DISTRIBUTED RANDOMLY;;
INSERT INTO skew SELECT round(random()*3);
ANALYZE skew;
INSERT INTO skew SELECT round(random()*3) FROM generate_series(1,999999);
INSERT INTO skew SELECT round(random()*3) FROM skew,generate_series(1,99);
测试版本为6.9.0版本,集群规模为72个Primary,通过上述的SQL,可以得知,
统计信息是失真的(为了演示,故意为之,当然实际生产中也极有可能会出现这种情况,
或者有时候,也无法绝对避免这种情况),因为分布策略是RANDOMLY,数据分布是均
衡的,但是,字段a的DISTINCT数量分别是3,这个数量相对于Primary的数量太小
了。先来看一下缺省情况下,下面这个SQL的执行计划:
select count(*) from (
select a,count(*) from skew group by 1
) x;
文字版的执行计划为:
图形化的执行计划为:
版权所有:Esena(陈淼 ) 编写:陈淼 - 399 -
|
||
|
|
|