Chinaunix首页 | 论坛 | 博客
  • 博客访问: 12021
  • 博文数量: 3
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 40
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-20 16:18
文章分类
文章存档

2015年(3)

我的朋友

分类: 数据库开发技术

2015-04-24 16:05:40

greenplum数据库维护

维护1.日常清理
包括以下工作
1.1 恢复磁盘空间,
1.2 更新规划器统计,
1.3 避免事务 ID 重叠造成的问题,
1.5 auto-vacuum 守护进程

一件很明显的维护工作就是经常性地创建数据的备份拷贝。
如果没有最近的备份,那么你就没有从灾难中恢复的机会(磁盘坏、失火、误删表)。


维护1.1.恢复磁盘空间

====由于以下几个原因,必须周期性运行 VACUUM 命令:
a.恢复那些由已更新或已删除的行占据的磁盘空间。
b.更新greenplum查询规划器使用的数据统计信息。
c.避免因为事务ID重叠造成的老数据丢失。


VACUUM 的标准形式可以和普通的数据库操作并发进行,
但VACUUM 需要大量的 I/O 操作,可能导致其它活动中的会话性能严重降低。有一些配置参数可以用于缓解这个问题。

====VACUUM 命令有两个变种。
第一种形式,叫做"懒汉 vacuum"或者就是 VACUUM ,在表和索引中标记过期的数据为将来使用;
它并不试图立即恢复这些过期数据使用的空间(除非位于表末尾并且很容易锁定此表)。
因此,表文件不会缩小,并且任何文件中没有使用的空间都不会返回给操作系统。
这个变种的 VACUUM 可以和通常的数据库操作并发执行。

第二种形式是 VACUUM FULL 命令。
这个形式使用一种更加激进的算法来恢复过期的行版本占据的空间。
任何 VACUUM FULL 释放的空间都立即返回给操作系统。
但是,这个形式的 VACUUM 命令在进行 VACUUM FULL 操作的时候要求一个排他锁。
因此,经常使用 VACUUM FULL 会对并发数据库查询有非常糟糕的影响。


====排他锁和共享锁概念
排它锁(x锁):若事务T对数据D加X锁,则其它任何事务都不能再对D加任何类型的锁,直至T释放D上的X锁;
一般要求在修改数据前要向该数据加排它锁,所以排它锁又称为写锁。

共享锁(s锁):若事务T对数据D加S锁,则其它事务只能对D加S锁,而不能加X锁,直至T释放D上的S锁;
一般要求在读取数据前要向该数据加共享锁, 所以共享锁又称读锁.

====使用vacuum命令的策略和建议
a.标准形式的 VACUUM 最适合用于维护磁盘用量比较稳定的情况。
如果你需要把磁盘空间归还给操作系统,那么你可以使用 VACUUM FULL ,
不过如果释放的磁盘空间又会很快再次被分配就没什么意义了。
如果维护更新频繁的表,那么中等频率的多次标准 VACUUM 方法比很低频率的 VACUUM FULL 更好。

b.对于大多数节点而言,推荐的习惯是在一天中的低使用时段安排一次整个数据库的 VACUUM ,必要时外加对频繁更新的表的清理。
有些环境下,对那些更新非常频繁的表可能会每几分钟就清理一次。
如果你的集群中有多个数据库,别忘记对每个库进行清理;vacuumdb 脚本可能会帮上你的忙。

c.如果你知道自己刚删除掉一个表中大部分的行,那么建议使用 VACUUM FULL ,
这样该表的稳态尺寸可以因为 VACUUM FULL 更富侵略性的方法而显著减小。
日常的磁盘空间清理,请使用 VACUUM 而不是 VACUUM FULL 。

d.如果你有一个表,它的内容经常被完全删除,那么可以考虑用 TRUNCATE 而不是后面跟着 VACUUM 的 DELETE 。
TRUNCATE 立即删除整个表的内容,而不要求随后的 VACUUM 或 VACUUM FULL 来恢复现在未使用的磁盘空间。

 

维护1.2.更新规划器统计
greenplum数据库的查询规划器依赖一些有关表内容的统计信息用以为查询生成好的规划。
这些统计是通过 ANALYZE 命令获得的,你可以直接调用这条命令,也可以把它当做 VACUUM 里的一个可选步骤来调用。
拥有合理准确的统计是非常重要的,否则,选择了恶劣的规划很可能降低数据库的性能。

和为了回收空间做清理一样,经常更新统计信息也是对更新频繁的表更有用。
不过,即使是更新非常频繁的表,如果它的数据的统计分布并不经常改变,那么也不需要更新统计信息。
一条简单的拇指定律就是想想表中字段的最大跟最小值改变的幅度。
比如,一个包含行更新时间的 timestamp 字段将随着行的追加和更新稳定增长最大值;
这样的字段可能需要比那些包含访问网站的 URL 的字段更频繁一些更新统计信息。那些 URL 字段可能改变得一样频繁,
但是其数值的统计分布的改变相对要缓慢得多。

我们可以在特定的表,甚至是表中特定的字段上运行 ANALYZE ,
所以如果你的应用有需求的话,可以对某些信息更新得比其它信息更频繁。
不过,在实际中,这种做法的有用性是值得怀疑的。
因为 ANALYZE 使用了统计学上的随机采样的方法进行行采样,
而不是把每一行都读取进来,所以即使在大表上也是一项相当快的操作。

维护1.3.避免事务 ID 重叠造成的问题

greenplum的 MVCC 事务语意依赖于比较事务 ID(XID)的数值:
一条带有大于当前事务 XID 的插入 XID 的行版本是"属于未来的",并且不应为当前事务可见。
但是因为事务 ID 的大小有限(在我们写这些的时候是 32 位),如果集群一次运行的时间很长(大于 40 亿次事务),
那么它就要受到事务 ID 重叠的折磨:XID 计数器回到零位,然后突然间所有以前的事务就变成看上去是在将来的,
这意味着它们的输出将变得可见。简而言之,可怕的数据丢失。实际上数据仍然在那里,但是如果你无法获取数据,


维护1.4. auto-vacuum 守护进程   (auto-vacuum进程如何开启)

系统带有一个额外的可选服务进程,叫做 autovacuum 守护进程,它的目的是自动执行 VACUUM 和 ANALYZE 命令。
在打开这个选项之后,autovacuum 守护进程将周期性运行并且检查那些有大量插入、更新、删除行操作的表。
这些检查使用行级别的统计收集设施;
因此,除非把 stats_start_collector 和 stats_row_level 设置为 true ,否则无法使用 autovacuum 守护。
还有,在为 superuser_reserved_connections 选择数值的时候,不要忘记给 autovacuum 进程保留一个槽位。


如果打开了 autovacuum 守护,那么它会每隔 autovacuum_naptime 秒钟运行一次。
在每次运行时将选择一个数据库进行处理,并且检查其中的每个表,看看是否需要运行 VACUUM 或 ANALYZE 命令。
那些 relfrozenxid 大于 autovacuum_freeze_max_age 的表将总是被清理。否则将使用两个条件来决定使用哪个操作。
如果上次 VACUUM 之后的过期行的数量超过了"清理阈值",那么就清理该表。清理阈值定义为:

清理阈值 = 清理基本阈值 + 清理缩放系数*行数
(vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuples)
这里的  清理基本阈值是 autovacuum_vacuum_threshold ,
        清理缩放系数是 autovacuum_vacuum_scale_factor ,
        行数是 pg_class.reltuples ,
过期行的数量是从统计收集器里面获取的,这是一个半精确的计数,
由每次 UPDATE 和 DELETE 操作更新。半精确的原因是在重负载时有些信息可能会丢失。


为了分析,使用了一个类似的条件:分析阈值,定义为:

分析阈值 = 分析基本阈值 + 分析缩放系数*行数
(analyze threshold = analyze base threshold + analyze scale factor * number of tuples)
它会和上次 ANALYZE 插入、更新、删除的总行数进行比较。缺省的阈值和伸缩系数是从 postgresql.conf 里面取得的,
不过,可以针对每个表独立设置,方法是在系统表 pg_autovacuum 里输入记录。
如果 pg_autovacuum 里面存在针对特定表的行,那么就使用该特定的设置;否则使用全局设置。


除了基本阈值和缩放系数之外,在 pg_autovacuum 里还有 5 个参数可以为每个表进行设置。
首先,pg_autovacuum.enabled 可以设置为 false 让 autovacuum 守护进程完全忽略某个表。
这种情况下,autovacuum 只有在为了避免事务 ID 重叠必须清理整个数据库的时候才会动那个表。
接下来两个参数,清理开销延迟(pg_autovacuum.vac_cost_delay)和清理开销限制(pg_autovacuum.vac_cost_limit),
用于针对特定的表为基于开销的清理延迟特性设置数值。
最后两个参数(pg_autovacuum.freeze_min_age)和(pg_autovacuum.freeze_max_age),
用于针对特定的表为 vacuum_freeze_min_age 和 autovacuum_freeze_max_age 设置数值。

如果在 pg_autovacuum 里某个数值为负数,或者在 pg_autovacuum 里就根本没有出现特定表的数据行,那么使用 postgresql.conf 里面对应的数值。
目前只能手工向 pg_autovacuum 表中 INSERT 记录。这个特性将在以后的版本中改进,并且这个系统表的定义也很有可能会改变。

维护2.经常重建索引


重建索引语法:
REINDEX { INDEX | TABLE | DATABASE | SYSTEM } name [ FORCE ]

====重建一个单独的索引:
REINDEX INDEX my_index;
====重建表 my_table 上的所有索引:
REINDEX TABLE my_table;

====重建一个数据库上的所有系统索引,不管系统索引是否仍然有效:
$ export PGOPTIONS="-P"
$ psql broken_db
...
broken_db=> REINDEX DATABASE broken_db;
broken_db=> \q
====实例
$ export PGOPTIONS="-P"
$ psql sjjs
...
broken_db=> REINDEX DATABASE sjjs;
broken_db=> \q

====索引膨胀的概念
我们经常有必要避免"索引膨胀",因为缺乏在 B-tree 索引内部的空间恢复机制。
一个情况就是索引健字的范围随着时间而变化。
比如,一个在时间戳上的索引随着时间的推移,旧的记录会最终被删除,
因为那些用于不再使用的键字范围的索引页面不能得到重复使用,就会导致膨胀。
随着时间的推移,索引的尺寸可能会变得比里面有用的数据大得多。

那些已经完全清空的索引页会得到重复使用。
不过这样仍然会有不充分使用空间的可能:
如果一个页面中大多数索引键字被删除,只留下很少的部分,那么该页仍然将被分配。
所以,如果使用模式是这样的:每个范围里除了少数键字之外,其它大部分键字最终都被删除;那么这样也会导致空间的低效使用。
膨胀的可能性不是无穷的,最差的情况是每个页面至少还有一个键字,但是对这样的使用模式,我们可能仍然值得安排周期性的重建索引。


维护 3.日志文件维护
把数据库服务器的日志输出保存在一个地方而不是仅仅把它们放到 /dev/null 里是个好主意。
在碰到危险的时候,日志输出是非常宝贵的。不过,日志输出可能很庞大(特别是在比较高的调试级别上),
而且你不会无休止地保存它们。你需要"滚动"日志文件,这样生成新的日志文件并且经常抛弃老的。

如果你简单地把 postgres 的 stderr 重定向到一个文件中,你会有日志输出,但是截断日志文件的唯一的方法是停止并重启主服务器。
这样做对于开发环境中是可以的,但是你肯定不想在生产环境中也这么干。
一个更好的办法是把主服务器的 stderr 输出发送到某种日志滚动程序里。
我们有一个内置的日志滚动程序,你可以通过在 postgresql.conf 里设置配置参数 redirect_stderr 为 true 的办法打开它。
另外,如果你想使用一个外部日志滚动程序(比如 Apache 附带的 rotatelogs 工具),你可以将 stderr 的输出重定向到这个外部工具。
如果你用 pg_ctl 启动服务器,那么 stderr 已经重定向到 stdout ,因此你只需要一个管道命令,比如:
pg_ctl start | rotatelogs /var/log/pgsql_log 86400
另外一种生产级的管理日志输出的方法就是把它们发送给 syslog 处理滚动。
要利用这个工具,我们需要设置 postgresql.conf 里的 log_destination 为 syslog(记录 syslog 日志)。
然后在你想强迫 syslog 守护进程开始写入一个新日志文件的时候,就可以发送一个 SIGHUP 信号给它。
如果你想自动滚动日志文件,那么我们可以配置 logrotate 程序处理 syslog 的日志文件。

阅读(4705) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~