最上层是实例,实例中允许创建多个数据库,每个数据库中可以创建多个schema,每个schema下面可以创建多个对象。
对象包括表、物化视图、操作符、索引、视图、序列、函数、... 等等。
在数据库中所有的权限都和角色(用户)挂钩,public是一个特殊角色,代表所有人。
超级用户是有允许任意操作对象的,普通用户只能操作自己创建的对象。
另外有一些对象是有赋予给public角色默认权限的,所以建好之后,所以人都有这些默认权限。
实例级别的权限由pg_hba.conf来控制,例如 :
# TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 trust host all postgres 0.0.0.0/0 reject host all all 0.0.0.0/0 md5配置解释
允许任何本地用户无密码连接任何数据库 不允许postgres用户从任何外部地址连接任何数据库 允许其他任何用户从外部地址通过密码连接任何数据库数据库级别的权限,包括允许连接数据库,允许在数据库中创建schema。
默认情况下,数据库在创建后,允许public角色连接,即允许任何人连接。
默认情况下,数据库在创建后,不允许除了超级用户和owner之外的任何人在数据库中创建schema。
默认情况下,数据库在创建后,会自动创建名为public 的schema,这个schema的all权限已经赋予给public角色,即允许任何人在里面创建对象。
schema级别的权限,包括允许查看schema中的对象,允许在schema中创建对象。
默认情况下新建的schema的权限不会赋予给public角色,因此除了超级用户和owner,任何人都没有权限查看schema中的对象或者在schema中新建对象。
对象级别的权限,每种类型的对象权限属性都不一样,具体请参考
http://www.postgresql.org/docs/9.5/static/sql-grant.html
以表为例,可以有SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER这些权限。
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [, ...] | ALL [ PRIVILEGES ] } ON { [ TABLE ] table_name [, ...] | ALL TABLES IN SCHEMA schema_name [, ...] } TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] ) [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) } ON [ TABLE ] table_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { USAGE | SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON { SEQUENCE sequence_name [, ...] | ALL SEQUENCES IN SCHEMA schema_name [, ...] } TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } ON DATABASE database_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON DOMAIN domain_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN DATA WRAPPER fdw_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN SERVER server_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { EXECUTE | ALL [ PRIVILEGES ] } ON { FUNCTION function_name ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) [, ...] | ALL FUNCTIONS IN SCHEMA schema_name [, ...] } TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON LANGUAGE lang_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON LARGE OBJECT loid [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] } ON SCHEMA schema_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { CREATE | ALL [ PRIVILEGES ] } ON TABLESPACE tablespace_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON TYPE type_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] where role_specification can be: [ GROUP ] role_name | PUBLIC | CURRENT_USER | SESSION_USER GRANT role_name [, ...] TO role_name [, ...] [ WITH ADMIN OPTION ]简单介绍一下grant的一些通用选项
WITH ADMIN OPTION表示被赋予权限的用户,拿到对应的权限后,还能将对应的权限赋予给其他人,否则只能自己有这个权限,但是不能再赋予给其他人。
用户,角色在PostgreSQL是一个概念。
public角色,代表所有人的意思。
以表为例 :
select relname,relacl from pg_class where relkind='r';或者执行
SELECT n.nspname as "Schema", c.relname as "Name", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'S' THEN 'sequence' WHEN 'f' THEN 'foreign table' END as "Type", pg_catalog.array_to_string(c.relacl, E'\n') AS "Access privileges", pg_catalog.array_to_string(ARRAY( SELECT attname || E':\n ' || pg_catalog.array_to_string(attacl, E'\n ') FROM pg_catalog.pg_attribute a WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL ), E'\n') AS "Column privileges", pg_catalog.array_to_string(ARRAY( SELECT polname || CASE WHEN polcmd != '*' THEN E' (' || polcmd || E'):' ELSE E':' END || CASE WHEN polqual IS NOT NULL THEN E'\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid) ELSE E'' END || CASE WHEN polwithcheck IS NOT NULL THEN E'\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid) ELSE E'' END || CASE WHEN polroles <> '{0}' THEN E'\n to: ' || pg_catalog.array_to_string( ARRAY( SELECT rolname FROM pg_catalog.pg_roles WHERE oid = ANY (polroles) ORDER BY 1 ), E', ') ELSE E'' END FROM pg_catalog.pg_policy pol WHERE polrelid = c.oid), E'\n') AS "Policies" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f') AND n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid) ORDER BY 1, 2;得到权限说明如下
Schema | Name | Type | Access privileges | Column privileges | Policies --------+-----------------+----------+--------------------------------+-------------------+---------- public | sbtest1 | table | postgres=arwdDxt/postgres +| | | | | digoal=a*r*w*d*D*x*t*/postgres | | public | sbtest10 | table | postgres=arwdDxt/postgres | | public | sbtest10_id_seq | sequence | | | public | sbtest11 | table | postgres=arwdDxt/postgres | | public | sbtest11_id_seq | sequence | | | public | sbtest12 | table | postgres=arwdDxt/postgres | | public | sbtest12_id_seq | sequence | | |解释一下 Access privileges
rolename=xxx 其中rolename就是被赋予权限的用户名,即权限被赋予给谁了?
=xxx 表示这个权限赋予给了public角色,即所有人
/yyyy 表示是谁赋予的这个权限?
权限的含义如下
rolename=xxxx -- privileges granted to a role =xxxx -- privileges granted to PUBLIC r -- SELECT ("read") w -- UPDATE ("write") a -- INSERT ("append") d -- DELETE D -- TRUNCATE x -- REFERENCES t -- TRIGGER X -- EXECUTE U -- USAGE C -- CREATE c -- CONNECT T -- TEMPORARY arwdDxt -- ALL PRIVILEGES (for tables, varies for other objects) * -- grant option for preceding privilege /yyyy -- role that granted this privilege例子
赋予权限的人是postgres用户, sbtest2表的select权限被赋予给了digoal用户。
postgres=# grant select on sbtest2 to digoal; GRANT postgres=# \dp+ sbtest2 Access privileges Schema | Name | Type | Access privileges | Column privileges | Policies --------+---------+-------+---------------------------+-------------------+---------- public | sbtest2 | table | postgres=arwdDxt/postgres+| | | | | digoal=r/postgres | | (1 row)回收权限一定要针对已有的权限来,如果你发现这里的权限还在,那照着权限回收即可。
例如
revoke select on sbtest2 from digoal;B-Tree:支持排序、范围查询、精确查询;适合所有数据类型,单个索引条目不能超过索引页的1/3。
hash:支持等值查询;适合超长字段。
gin:倒排索引,支持等值、包含、相交、等查询;适合多值类型(数组、全文检索等),任意字段组合查询。
gist:R-Tree索引,支持包含,相交,距离,点面判断等查询;适合几何类型、范围类型、全文检索、异构类型等。
sp-gist:空间分区(平衡)r-tree,支持包含,相交,距离,点面判断等查询;适合几何类型、范围类型、全文检索、异构类型等。
brin:块级索引,适合物理存储与列值存在较好相关性的字段。比如时序数据、物联网传感数据、FEED数据等。支持范围查询、等值查询。
rum:扩展索引接口,支持全文检索,支持附加标量类型的全文检索,支持带位置关系的全文检索。
多个索引,PostgreSQL会使用bitmapAnd或bitmapOr合并扫描。
1、新建索引
set maintenance_work_mem ='4GB'; -- 越大,创建索引越快 set lock_timeout = '1s'; -- 避免长时间锁等待 create index [CONCURRENTLY] xxx on xxx using xxx (colxxx); -- 根据实际情况,是否使用 CONCURRENTLY(不堵塞读写)。2、删除旧索引
set lock_timeout = '1s'; -- 避免长时间锁等待 drop index oldindex;3、PK\UK的维护,与之类似,增加一步骤。
ALTER TABLE tbl ADD [ CONSTRAINT constraint_name ] { UNIQUE | PRIMARY KEY } USING INDEX index_name [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]索引盘:对应索引表空间。
空间评估、IOPS评估、带宽评估。建议采用SSD,文件系统采用ext4或xfs。
数据盘:对应数据文件表空间。
空间评估、IOPS评估、带宽评估。建议采用SSD,文件系统采用ext4或xfs。
重做日志盘:对应WAL目录。
空间评估、IOPS评估、带宽评估。建议采用SSD,文件系统采用ext4或xfs。
归档盘:对应WAL归档目录。
空间评估、IOPS评估、带宽评估。可以采用机械盘,文件系统采用ext4或xfs或ZFS,可以开启文件系统压缩功能。
备份盘:对应数据库备份目录。
空间评估、IOPS评估、带宽评估。可以采用机械盘,文件系统采用ext4或xfs或ZFS,可以开启文件系统压缩功能。
日志盘(pg_log):对应数据库审计、错误日志目录。
空间评估、IOPS评估、带宽评估。可以采用机械盘,文件系统采用ext4或xfs或ZFS,可以开启文件系统压缩功能。
带宽评估,网段规划,防火墙规划。
不建议使用公网。
根据业务需求,评估CPU主频,核数。建议实测性能指标。
/etc/sysctl.conf
# add by digoal.zhou fs.aio-max-nr = 1048576 fs.file-max = 76724600 kernel.core_pattern= /data01/corefiles/core_%e_%u_%t_%s.%p # /data01/corefiles事先建好,权限777,如果是软链接,对应的目录修改为777 kernel.sem = 4096 2147483647 2147483646 512000 # 信号量, ipcs -l 或 -u 查看,每16个进程一组,每组信号量需要17个信号量。 kernel.shmall = 107374182 # 所有共享内存段相加大小限制(建议内存的80%) kernel.shmmax = 274877906944 # 最大单个共享内存段大小(建议为内存一半), >9.2的版本已大幅降低共享内存的使用 kernel.shmmni = 819200 # 一共能生成多少共享内存段,每个PG数据库集群至少2个共享内存段 net.core.netdev_max_backlog = 10000 net.core.rmem_default = 262144 # The default setting of the socket receive buffer in bytes. net.core.rmem_max = 4194304 # The maximum receive socket buffer size in bytes net.core.wmem_default = 262144 # The default setting (in bytes) of the socket send buffer. net.core.wmem_max = 4194304 # The maximum send socket buffer size in bytes. net.core.somaxconn = 4096 net.ipv4.tcp_max_syn_backlog = 4096 net.ipv4.tcp_keepalive_intvl = 20 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_keepalive_time = 60 net.ipv4.tcp_mem = 8388608 12582912 16777216 net.ipv4.tcp_fin_timeout = 5 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_syncookies = 1 # 开启SYN Cookies。当出现SYN等待队列溢出时,启用cookie来处理,可防范少量的SYN攻击 net.ipv4.tcp_timestamps = 1 # 减少time_wait net.ipv4.tcp_tw_recycle = 0 # 如果=1则开启TCP连接中TIME-WAIT套接字的快速回收,但是NAT环境可能导致连接失败,建议服务端关闭它 net.ipv4.tcp_tw_reuse = 1 # 开启重用。允许将TIME-WAIT套接字重新用于新的TCP连接 net.ipv4.tcp_max_tw_buckets = 262144 net.ipv4.tcp_rmem = 8192 87380 16777216 net.ipv4.tcp_wmem = 8192 65536 16777216 net.nf_conntrack_max = 1200000 net.netfilter.nf_conntrack_max = 1200000 vm.dirty_background_bytes = 409600000 # 系统脏页到达这个值,系统后台刷脏页调度进程 pdflush(或其他) 自动将(dirty_expire_centisecs/100)秒前的脏页刷到磁盘 vm.dirty_expire_centisecs = 3000 # 比这个值老的脏页,将被刷到磁盘。3000表示30秒。 vm.dirty_ratio = 95 # 如果系统进程刷脏页太慢,使得系统脏页超过内存 95 % 时,则用户进程如果有写磁盘的操作(如fsync, fdatasync等调用),则需要主动把系统脏页刷出。 # 有效防止用户进程刷脏页,在单机多实例,并且使用CGROUP限制单实例IOPS的情况下非常有效。 vm.dirty_writeback_centisecs = 100 # pdflush(或其他)后台刷脏页进程的唤醒间隔, 100表示1秒。 vm.mmap_min_addr = 65536 vm.overcommit_memory = 0 # 在分配内存时,允许少量over malloc, 如果设置为 1, 则认为总是有足够的内存,内存较少的测试环境可以使用 1 . vm.overcommit_ratio = 90 # 当overcommit_memory = 2 时,用于参与计算允许指派的内存大小。 vm.swappiness = 0 # 关闭交换分区 vm.zone_reclaim_mode = 0 # 禁用 numa, 或者在vmlinux中禁止. net.ipv4.ip_local_port_range = 40000 65535 # 本地自动分配的TCP, UDP端口号范围 fs.nr_open=20480000 # 单个进程允许打开的文件句柄上限 # 以下参数请注意 # vm.extra_free_kbytes = 4096000 # vm.min_free_kbytes = 2097152 # 如果是小内存机器,以上两个值不建议设置 # vm.nr_hugepages = 66536 # 建议shared buffer设置超过64GB时 使用大页,页大小 /proc/meminfo Hugepagesize # vm.lowmem_reserve_ratio = 1 1 1 # 对于内存大于64G时,建议设置,否则建议默认值 256 256 32sysctl -p
/etc/security/limits.conf
* soft nofile 1024000 * hard nofile 1024000 * soft nproc unlimited * hard nproc unlimited * soft core unlimited * hard core unlimited * soft memlock unlimited * hard memlock unlimited例子
# 私有网段 -A INPUT -s 192.168.0.0/16 -j ACCEPT -A INPUT -s 10.0.0.0/8 -j ACCEPT -A INPUT -s 172.16.0.0/16 -j ACCEPT例子
initdb -D $PGDATA -E UTF8 --locale=C -U postgres -X $PG_XLOG -W例子
listen_addresses = '0.0.0.0' port = 1921 max_connections = 200 tcp_keepalives_idle = 60 tcp_keepalives_interval = 10 tcp_keepalives_count = 6 shared_buffers = 512MB maintenance_work_mem = 64MB dynamic_shared_memory_type = windows vacuum_cost_delay = 0 bgwriter_delay = 10ms bgwriter_lru_maxpages = 1000 bgwriter_lru_multiplier = 5.0 bgwriter_flush_after = 0 old_snapshot_threshold = -1 wal_level = minimal synchronous_commit = off full_page_writes = on wal_buffers = 64MB wal_writer_delay = 10ms wal_writer_flush_after = 4MB checkpoint_timeout = 35min max_wal_size = 2GB min_wal_size = 80MB checkpoint_completion_target = 0.1 checkpoint_flush_after = 0 random_page_cost = 1.5 log_destination = 'csvlog' logging_collector = on log_directory = 'pg_log' log_truncate_on_rotation = on log_checkpoints = on log_connections = on log_disconnections = on log_error_verbosity = verbose log_temp_files = 8192 log_timezone = 'Asia/Hong_Kong' autovacuum = on log_autovacuum_min_duration = 0 autovacuum_naptime = 20s autovacuum_vacuum_scale_factor = 0.05 autovacuum_freeze_max_age = 1500000000 autovacuum_multixact_freeze_max_age = 1600000000 autovacuum_vacuum_cost_delay = 0 vacuum_freeze_table_age = 1400000000 vacuum_multixact_freeze_table_age = 1500000000 datestyle = 'iso, mdy' timezone = 'Asia/Hong_Kong' lc_messages = 'C' lc_monetary = 'C' lc_numeric = 'C' lc_time = 'C' default_text_search_config = 'pg_catalog.english'例子
host all all 0.0.0.0/0 md5/home/digoal/.bash_profile
export PGPORT=1921 export PGDATA=/home/digoal/pgdata export LANG=en_US.utf8 export PGHOME=/home/digoal/pgsql9.6 export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH export PATH=$PGHOME/bin:$PATH:. export MANPATH=$PGHOME/share/man:$MANPATH export PGHOST=$PGDATA export PGUSER=postgres export PGDATABASE=postgres《PostgreSQL 最佳实践 - 在线逻辑备份与恢复介绍》
例子
备份digoal库, DDL中不包含表空间. 所以恢复时不需要提前创建对应的表空间.
pg_dump -f ./digoal.dmp -F p -C -E UTF8 --no-tablespaces -h 127.0.0.1 -p 1999 -U postgres digoal如果备份为-F p格式,备份输出为文本,直接运行即可。
psql postgres postgres -f ./digoal.dmp要支持物理备份,务必打开归档,同时建议打开流复制。
配置归档目录
# mkdir -p /disk1/digoal/arch # chown digoal:digoal /disk1/digoal/arch配置流复制和归档
vi postgresql.conf
max_worker_processes = 16 max_wal_senders = 8 archive_command = 'test ! -f /disk1/digoal/arch/%f && cp %p /disk1/digoal/arch/%f'重启数据库
pg_ctl restart -m fast -D $PGDATAvi $PGDATA/pg_hba.conf
host replication rep 0.0.0.0/0 md5pg_ctl reload -D $PGDATA
创建备份目录,备份可以通过流复制协议,备份到远程。
# mkdir -p /disk1/digoal/backup # chown digoal:digoal /disk1/digoal/backup例子 1,通过流复制用户,以及流复制备份
export PGPASSWORD=rep123 pg_basebackup -D /disk1/digoal/backup -F t -z -h 数据库IP -p 数据库端口 -U rep例子 2,使用cp备份
步骤如下
select pg_start_backup('test'); copy 数据文件,表空间等目录 select pg_stop_backup();物理增量备份分为两种,
一种是数据文件的增量备份,需要等10.0或者使用pg_rman, pg_probackup
https://github.com/postgrespro/pg_probackup
https://github.com/ossc-db/pg_rman
另一种是归档增量备份。
将归档文件拷贝到备份存储即可。
1. 如果是异机备份,首先要部署PostgreSQL软件环境,建议部署的PostgreSQL软件版本与备份的数据文件一致。编译参数一致。
如何查看编译参数?在源库执行如下命令
pg_config部署软件时,还需要部署源库所有的PostgreSQL插件,并且需要确保插件版本一致。
2. 构建恢复目录,需要有足够的空间。
3. 解压数据文件,归档到各自的目录。
如果有表空间,将表空间使用软链连接到$PGDATA/pg_tblspc,或者将表空间解压到$PGDATA/pg_tblspc。
4. 修改postgresql.conf
主要修改参数,包括监听端口,shared buffer, preload library 等,防止端口冲突导致启动失败。
5. 配置$PGDATA/recovery.conf,同时设置恢复目标
主要配置,restore_command。(如果是搭建流复制备库,则需要配置的是#primary_conninfo = '' # e.g. 'host=localhost port=5432'。)
#restore_command = '' # e.g. 'cp /mnt/server/archivedir/%f %p'设置恢复到哪个时间点、XID或者target name。(如果是搭建流复制备库,则需要配置recovery_target_timeline = 'latest')
#recovery_target_name = '' # e.g. 'daily backup 2011-01-26' # #recovery_target_time = '' # e.g. '2004-07-14 22:39:00 EST' # #recovery_target_xid = '' # #recovery_target_inclusive = true6. 启动恢复库
pg_ctl start -D 恢复库$PGDATA数据变更操作(主库)
postgres=# select pg_create_restore_point('digoal'); pg_create_restore_point ------------------------- 1D6/FB17EC08 (1 row)首先要创建一个记录还原点XID的表。记录XID,时间,以及描述信息。(来代替pg_create_restore_point 系统函数的功能)
postgres=> create table restore_point(id serial primary key, xid int8, crt_time timestamp default now(), point text); CREATE TABLE创建一个函数,代替pg_create_restore_point的功能,插入还原点。
postgres=> create or replace function create_restore_point(i_point text) returns void as $$ declare begin insert into restore_point(xid,point) values (txid_current(),i_point); end; $$ language plpgsql strict; CREATE FUNCTION插入一个还原点
postgres=> select create_restore_point('digoal'); create_restore_point ---------------------- (1 row)查询这个表的信息:
postgres=> select * from restore_point; id | xid | crt_time | point ----+--------+----------------------------+-------- 1 | 561426 | 2015-06-19 09:18:57.525475 | digoal (1 row) postgres=> select * from restore_point where point='digoal'; id | xid | crt_time | point ----+--------+----------------------------+-------- 1 | 561426 | 2015-06-19 09:18:57.525475 | digoal (1 row)接下来要模拟一下还原:
postgres=> create table test(id int,info text); CREATE TABLE postgres=> insert into test select generate_series(1,1000),md5(random()::text); INSERT 0 1000记录当前哈希值。用于恢复后的比对。
postgres=> select sum(hashtext(t.*::text)) from test t; sum -------------- -69739904784 (1 row)接下来我要做一笔删除操作,在删除前,我先创建一条还原点信息。
postgres=> select create_restore_point('before delete test'); create_restore_point ---------------------- (1 row) postgres=> delete from test; DELETE 1000 postgres=> select * from restore_point where point='before delete test'; id | xid | crt_time | point ----+--------+----------------------------+-------------------- 2 | 561574 | 2015-06-19 09:45:28.030295 | before delete test (1 row)我只需要恢复到561574 即可。接下来就是模拟恢复了。
主动产生一些XLOG,触发归档。
postgres=> select pg_xlogfile_name(pg_current_xlog_location()); pg_xlogfile_name -------------------------- 000000010000000200000041 (1 row) postgres=> insert into test select generate_series(1,100000); INSERT 0 100000 postgres=> insert into test select generate_series(1,100000); INSERT 0 100000 postgres=> select pg_xlogfile_name(pg_current_xlog_location()); pg_xlogfile_name -------------------------- 000000010000000200000042 (1 row)下载阿里云RDS的备份和归档到本地。
在本地需要安装一个postgresql, 与阿里云RDS的编译配置参数一致(例如数据块的大小),最好使用的模块也一致,这里没有用到其他模块,所以无所谓。
通过pg_settings来看一下RDS的配置信息,版本信息,方便我们在本地进行恢复。
postgres=> select name,setting,unit from pg_settings where category='Preset Options'; name | setting | unit -----------------------+---------+------ block_size | 8192 | data_checksums | on | integer_datetimes | on | max_function_args | 100 | max_identifier_length | 63 | max_index_keys | 32 | segment_size | 131072 | 8kB server_version | 9.4.1 | server_version_num | 90401 | wal_block_size | 8192 | wal_segment_size | 2048 | 8kB (11 rows) postgres=> select version(); version -------------------------------------------------------------------------------------------------------------- PostgreSQL 9.4.1 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3), 64-bit (1 row)本地编译安装PostgreSQL 9.4.1,编译参数与RDS一致。阿里云RDS这几个参数都是默认的。
--with-blocksize=BLOCKSIZE set table block size in kB [8] --with-segsize=SEGSIZE set table segment size in GB [1] --with-wal-blocksize=BLOCKSIZE set WAL block size in kB [8] --with-wal-segsize=SEGSIZE set WAL segment size in MB [16] # useradd digoal # su - digoal $ vi .bash_profile # add by digoal export PS1="$USER@`/bin/hostname -s`-> " export PGPORT=1931 export PGDATA=/home/digoal/pg_root export LANG=en_US.utf8 export PGHOME=/home/digoal/pgsql9.4.1 export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH export DATE=`date +"%Y%m%d%H%M"` export PATH=$PGHOME/bin:$PATH:. export MANPATH=$PGHOME/share/man:$MANPATH export PGHOST=$PGDATA export PGDATABASE=postgres alias rm='rm -i' alias ll='ls -lh' unalias vi # wget https://ftp.postgresql.org/pub/source/v9.4.1/postgresql-9.4.1.tar.bz2 # tar -jxvf postgresql-9.4.1.tar.bz2 # cd postgresql-9.4.1 # ./configure --prefix=/home/digoal/pgsql9.4.1 --with-pgport=1931 --with-perl --with-python --with-tcl --with-openssl --with-pam --with-ldap --with-libxml --with-libxslt --enable-thread-safety --enable-debug # gmake world && gmake install-world下载备份和归档文件,解压:
基础备份选择需要恢复的时间点之前的一个备份,归档则选择在此之后的所有归档文件。
total 453M -rw-r--r-- 1 root root 17M Jun 19 10:23 000000010000000200000040.tar.gz -rw-r--r-- 1 root root 17M Jun 19 10:23 000000010000000200000041.tar.gz -rw-r--r-- 1 root root 404M Jun 19 10:23 hins668881_xtra_20150618232331.tar.gz # mkdir /home/digoal/pg_root # mv hins668881_xtra_20150618232331.tar.gz /home/digoal/pg_root # tar -zxvf hins668881_xtra_20150618232331.tar.gz [root@db-172-16-3-150 ~]# tar -xvf 000000010000000200000040.tar.gz 000000010000000200000040 [root@db-172-16-3-150 ~]# tar -xvf 000000010000000200000041.tar.gz 000000010000000200000041 [root@db-172-16-3-150 ~]# mv 000000010000000200000040 /home/digoal/ [root@db-172-16-3-150 ~]# mv 000000010000000200000041 /home/digoal/ [root@db-172-16-3-150 ~]# chown -R digoal:digoal /home/digoal [root@db-172-16-3-150 ~]# chmod -R 700 /home/digoal/pg_root修改配置文件,注释掉阿里云RDS PG的一些定制参数。
$ vi postgresql.conf port=1931 注释RDS自定义的GUC参数 #rds_enable_proxy=on #rds_available_extensions='plpgsql,pg_stat_statements,btree_gin,btree_gist,chkpass,citext,cube,dblink,dict_int,earthdistance,hstore,intagg,intarray,isn,ltree,pgcrypto,pgrowlocks,pg_prewarm,pg_trgm,postgres_fdw,sslinfo,tablefunc,tsearch2,unaccent,postgis,postgis_topology,fuzzystrmatch,postgis_tiger_geocoder,plperl,pltcl,plv8,plls,plcoffee,"uuid-ossp"' #rds_enable_admin_user_as_super=on配置recovery.conf
打开hot_standby,恢复到目标点后暂停,如果确认已经到达,使用resume激活。
$ vi recovery.conf standby_mode = 'on' restore_command = 'cp /home/digoal/%f %p' recovery_target_xid='561574' # 使用我们自建的恢复点的XID recovery_target_inclusive=true pause_at_recovery_target=true启动数据库
$ pg_ctl start检查是否恢复到指定XID
digoal@db-172-16-3-150-> psql -h 127.0.0.1 -p 1931 psql (9.4.1) Type "help" for help. postgres=> \dt List of relations Schema | Name | Type | Owner --------+-----------------+-------+-------- public | ha_health_check | table | aurora public | login_log | table | digoal public | restore_point | table | digoal public | session | table | digoal public | tbl_small | table | digoal public | test | table | digoal public | userinfo | table | digoal (7 rows)检查,已经恢复到DELETE test表的数据之前了。
postgres=> select count(*) from test; count ------- 1000 (1 row) postgres=> select sum(hashtext(t.*::text)) from test t; sum -------------- -69739904784 (1 row)假设 512GB 内存, SSD.
listen_addresses = '0.0.0.0' port = 1921 max_connections = 5000 unix_socket_directories = '.' # 确保unix socket处于安全目录 tcp_keepalives_idle = 60 # 避免网络层设备主动断开空闲连接的问题 tcp_keepalives_interval = 10 # 避免网络层设备主动断开空闲连接的问题 tcp_keepalives_count = 10 # 避免网络层设备主动断开空闲连接的问题 shared_buffers = 128GB # 1/4 物理内存 maintenance_work_mem = 4GB # 加速创建索引,VACUUM垃圾回收,平时最多消耗 maintenance_work_mem * autovacuum_max_workers 内存 dynamic_shared_memory_type = posix vacuum_cost_delay = 0 # SSD, 建议设置为0, 不打断vacuum bgwriter_delay = 10ms # 快速刷shared buffer脏页 bgwriter_lru_maxpages = 1000 bgwriter_lru_multiplier = 10.0 bgwriter_flush_after = 0 # IO很好的机器,不需要考虑平滑调度。否则建议设置为大于0 max_worker_processes = 128 max_parallel_workers_per_gather = 0 old_snapshot_threshold = -1 backend_flush_after = 0 # IO很好的机器,不需要考虑平滑调度 wal_level = replica synchronous_commit = off # 异步提交 full_page_writes = on # COW文件系统,或者对齐并支持BLOCK_SIZE大小原子写的SSD,可以关闭,提高性能,减少WAL的写入量。 wal_buffers = 1GB wal_writer_delay = 10ms wal_writer_flush_after = 0 # IO很好的机器,不需要考虑平滑调度 checkpoint_timeout = 30min # 不建议频繁做检查点,否则XLOG会产生很多的FULL PAGE WRITE。 max_wal_size = 256GB # 建议设置为SHARED BUFFER的2倍 min_wal_size = 32GB checkpoint_completion_target = 0.05 # 硬盘好的情况下,可以让检查点快速结束,恢复时也可以快速达到一致状态。 checkpoint_flush_after = 0 # IO很好的机器,不需要考虑平滑调度 archive_mode = on archive_command = '/bin/date' # 后期再修改,如 'test ! -f /disk1/digoal/arch/%f && cp %p /disk1/digoal/arch/%f' max_wal_senders = 8 random_page_cost = 1.3 # IO很好的机器,不需要考虑离散和顺序扫描的成本差异 parallel_tuple_cost = 0 parallel_setup_cost = 0 min_parallel_relation_size = 0 effective_cache_size = 300GB # 看着办,减掉数据库shared buffer, maintenance work mem, work mem, wal shared buffer,剩下的都是OS可用的CACHE。 force_parallel_mode = off log_destination = 'csvlog' logging_collector = on log_truncate_on_rotation = on log_checkpoints = on log_connections = on log_disconnections = on log_error_verbosity = verbose log_timezone = 'PRC' autovacuum = on log_autovacuum_min_duration = 0 autovacuum_max_workers = 16 # CPU核多,并且IO好的情况下,可多点,但是注意 16*autovacuum mem ,会消耗较多内存,所以内存也要有基础。 autovacuum_naptime = 20s autovacuum_vacuum_scale_factor = 0.05 # 垃圾版本超过5%时,触发垃圾回收 vacuum_freeze_min_age = 50000000 # 年龄超过5000万的记录,都设置为冻结年龄 vacuum_multixact_freeze_min_age = 5000000 autovacuum_freeze_max_age = 1600000000 # 表的年龄超过16亿时,强制触发vacuum freeze(即使没有开启autovacuum) vacuum_freeze_table_age = 1200000000 # 表的年龄超过12亿时,autovacuum 触发vacuum freeze vacuum_multixact_freeze_table_age = 1100000000 datestyle = 'iso, mdy' timezone = 'PRC' lc_messages = 'C' lc_monetary = 'C' lc_numeric = 'C' lc_time = 'C' default_text_search_config = 'pg_catalog.english' shared_preload_libraries='pg_stat_statements'pg_stat_statements插件,统计SQL调用的资源消耗。
create extension pg_stat_statements; shared_preload_libraries = 'pg_stat_statements';TOP 5 CPU_TIME SQL
select c.rolname,b.datname,a.total_time/a.calls per_call_time,a.* from pg_stat_statements a, pg_database b, pg_authid c where a.userid=c.oid and a.dbid=b.oid order by a.total_time desc limit 5;《PostgreSQL AWR报告(for 阿里云ApsaraDB PgSQL)》
打印超时SQL当时的执行计划。
shared_preload_libraries = 'auto_explain' 配置 auto_explain.log_analyze = on auto_explain.log_nested_statements = on auto_explain.log_buffers = on auto_explain.log_min_duration = '1s' auto_explain.log_timing = on auto_explain.log_verbose = onexplain 语法
explain 例子
explain 节点
初始化数据, 1000万记录。
export PGPASSWORD=密码 pgbench -i -s 100测试
export PGPASSWORD=密码 pgbench -M prepared -n -r -P 1 -c 连接数 -j 线程数 -h 主机IP -p 端口 -U 用户 数据库名 -T 时间(秒)创建测试表
create table test(id int primary key, info text, crt_time timestamp);创建脚本
vi test.sql \set id random(1,100000000) insert into test (id,info,crt_time) values (:id, md5(random()::text), now()) on conflict (id) do update set info=excluded.info, crt_time=excluded.crt_time;压测
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 32 -j 32 -T 100 progress: 1.0 s, 246533.1 tps, lat 0.128 ms stddev 0.536 progress: 2.0 s, 254653.8 tps, lat 0.125 ms stddev 0.333 progress: 3.0 s, 232433.6 tps, lat 0.137 ms stddev 0.812 progress: 4.0 s, 258225.7 tps, lat 0.123 ms stddev 0.2501、AWR健康报告
2、垃圾回收
3、膨胀索引重建
4、TOP SQL性能优化
5、错误日志分析
6、安全风险评估(SQL注入、暴力破解、密码周期修改)
7、备份可用性校验
8、历史备份和归档清理
9、历史数据清理
10、实时监控系统建设
11、HA建设、监控、演练
12、容灾建设、监控、演练
13、审计系统建设
14、业务逻辑优化
15、内核优化
16、版本升级、BUG FIX
17、社区交流
相关资源:matlab开发-PhaseLockingValue