当前位置:   article > 正文

一天学会PostgreSQL应用开发与管理 - 8 PostgreSQL 管理

postgresql 开发his

本章大纲

一、权限体系

1 逻辑结构
2 权限体系
3 schema使用 , 特别注意
4 用户
5 public
6 如何查看和解读一个对象的当前权限状态

二、索引介绍

1 索引有什么用?
2 索引的类型
3 索引合并扫描
4 表膨胀检查
5 检查膨胀
6 索引维护

三、系统配置

1 存储、文件系统规划
2 网络规划
3 CPU评估
4 内核配置
5 资源限制
6 防火墙配置

四、数据库初始化

1 initdb 介绍
2 postgresql.conf参数配置
3 pg_hba.conf数据库防火墙配置

五、PostgreSQL控制

1 环境变量配置
2 停库
3 重启
4 启动
5 Linux自启动服务

六、数据库备份和还原

1 逻辑备份
2 逻辑还原
3 配置归档、流复制
4 创建流复制用户
5 配置流复制防火墙
6 远程物理基础备份
7 物理增量备份
8 PITR(时间点恢复)
PITR 时间点恢复 例子

七、数据库性能

1 参数优化
2 性能视图 pg_stat*
3 TOP SQL
4 AWR
5 auto_explain
6 explain解读

八、数据库压测

1 pg_bench介绍
2 tpc-b测试
3 自定义测试

九、日常维护

第六章:PostgreSQL 管理

1. 权限体系

逻辑结构

最上层是实例,实例中允许创建多个数据库,每个数据库中可以创建多个schema,每个schema下面可以创建多个对象。

对象包括表、物化视图、操作符、索引、视图、序列、函数、... 等等。

pic1

在数据库中所有的权限都和角色(用户)挂钩,public是一个特殊角色,代表所有人。

超级用户是有允许任意操作对象的,普通用户只能操作自己创建的对象。

另外有一些对象是有赋予给public角色默认权限的,所以建好之后,所以人都有这些默认权限。

权限体系

pic2

实例级别的权限由pg_hba.conf来控制,例如 :

  1. # TYPE DATABASE USER ADDRESS METHOD
  2. # "local" is for Unix domain socket connections only
  3. local all all trust
  4. # IPv4 local connections:
  5. host all all 127.0.0.1/32 trust
  6. host all postgres 0.0.0.0/0 reject
  7. host all all 0.0.0.0/0 md5

配置解释

  1. 允许任何本地用户无密码连接任何数据库
  2. 不允许postgres用户从任何外部地址连接任何数据库
  3. 允许其他任何用户从外部地址通过密码连接任何数据库

数据库级别的权限,包括允许连接数据库,允许在数据库中创建schema。

默认情况下,数据库在创建后,允许public角色连接,即允许任何人连接。

默认情况下,数据库在创建后,不允许除了超级用户和owner之外的任何人在数据库中创建schema。

默认情况下,数据库在创建后,会自动创建名为public 的schema,这个schema的all权限已经赋予给public角色,即允许任何人在里面创建对象。

schema级别的权限,包括允许查看schema中的对象,允许在schema中创建对象。

默认情况下新建的schema的权限不会赋予给public角色,因此除了超级用户和owner,任何人都没有权限查看schema中的对象或者在schema中新建对象。

schema使用 , 特别注意
  1. According to the SQL standard, the owner of a schema always owns all objects within it.
  2. PostgreSQL allows schemas to contain objects owned by users other than the schema owner.
  3. This can happen only if the schema owner grants the CREATE privilege on his schema to someone else,
  4. or a superuser chooses to create objects in it.
  5. schema的owner默认是该schema下的所有对象的owner,但是PostgreSQL又允许用户在别人的schema下创建对象,所以一个对象可能属于两个owner,而且schema 的owner有 drop对象的权限。
  6. 对于两个owner都有drop的权限,这个我个人认为是一个BUG。
  7. 所以千万不要把自己的对象创建到别人的schema下面,那很危险。

对象级别的权限,每种类型的对象权限属性都不一样,具体请参考

http://www.postgresql.org/docs/9.5/static/sql-grant.html

以表为例,可以有SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER这些权限。

  1. GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
  2. [, ...] | ALL [ PRIVILEGES ] }
  3. ON { [ TABLE ] table_name [, ...]
  4. | ALL TABLES IN SCHEMA schema_name [, ...] }
  5. TO role_specification [, ...] [ WITH GRANT OPTION ]
  6. GRANT { { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] )
  7. [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) }
  8. ON [ TABLE ] table_name [, ...]
  9. TO role_specification [, ...] [ WITH GRANT OPTION ]
  10. GRANT { { USAGE | SELECT | UPDATE }
  11. [, ...] | ALL [ PRIVILEGES ] }
  12. ON { SEQUENCE sequence_name [, ...]
  13. | ALL SEQUENCES IN SCHEMA schema_name [, ...] }
  14. TO role_specification [, ...] [ WITH GRANT OPTION ]
  15. GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
  16. ON DATABASE database_name [, ...]
  17. TO role_specification [, ...] [ WITH GRANT OPTION ]
  18. GRANT { USAGE | ALL [ PRIVILEGES ] }
  19. ON DOMAIN domain_name [, ...]
  20. TO role_specification [, ...] [ WITH GRANT OPTION ]
  21. GRANT { USAGE | ALL [ PRIVILEGES ] }
  22. ON FOREIGN DATA WRAPPER fdw_name [, ...]
  23. TO role_specification [, ...] [ WITH GRANT OPTION ]
  24. GRANT { USAGE | ALL [ PRIVILEGES ] }
  25. ON FOREIGN SERVER server_name [, ...]
  26. TO role_specification [, ...] [ WITH GRANT OPTION ]
  27. GRANT { EXECUTE | ALL [ PRIVILEGES ] }
  28. ON { FUNCTION function_name ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) [, ...]
  29. | ALL FUNCTIONS IN SCHEMA schema_name [, ...] }
  30. TO role_specification [, ...] [ WITH GRANT OPTION ]
  31. GRANT { USAGE | ALL [ PRIVILEGES ] }
  32. ON LANGUAGE lang_name [, ...]
  33. TO role_specification [, ...] [ WITH GRANT OPTION ]
  34. GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
  35. ON LARGE OBJECT loid [, ...]
  36. TO role_specification [, ...] [ WITH GRANT OPTION ]
  37. GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
  38. ON SCHEMA schema_name [, ...]
  39. TO role_specification [, ...] [ WITH GRANT OPTION ]
  40. GRANT { CREATE | ALL [ PRIVILEGES ] }
  41. ON TABLESPACE tablespace_name [, ...]
  42. TO role_specification [, ...] [ WITH GRANT OPTION ]
  43. GRANT { USAGE | ALL [ PRIVILEGES ] }
  44. ON TYPE type_name [, ...]
  45. TO role_specification [, ...] [ WITH GRANT OPTION ]
  46. where role_specification can be:
  47. [ GROUP ] role_name
  48. | PUBLIC
  49. | CURRENT_USER
  50. | SESSION_USER
  51. GRANT role_name [, ...] TO role_name [, ...] [ WITH ADMIN OPTION ]

简单介绍一下grant的一些通用选项

WITH ADMIN OPTION表示被赋予权限的用户,拿到对应的权限后,还能将对应的权限赋予给其他人,否则只能自己有这个权限,但是不能再赋予给其他人。

用户

用户,角色在PostgreSQL是一个概念。

public

public角色,代表所有人的意思。

如何查看和解读一个对象的当前权限状态

以表为例 :

select relname,relacl from pg_class where relkind='r';    

或者执行

  1. SELECT n.nspname as "Schema",
  2. c.relname as "Name",
  3. 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",
  4. pg_catalog.array_to_string(c.relacl, E'\n') AS "Access privileges",
  5. pg_catalog.array_to_string(ARRAY(
  6. SELECT attname || E':\n ' || pg_catalog.array_to_string(attacl, E'\n ')
  7. FROM pg_catalog.pg_attribute a
  8. WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL
  9. ), E'\n') AS "Column privileges",
  10. pg_catalog.array_to_string(ARRAY(
  11. SELECT polname
  12. || CASE WHEN polcmd != '*' THEN
  13. E' (' || polcmd || E'):'
  14. ELSE E':'
  15. END
  16. || CASE WHEN polqual IS NOT NULL THEN
  17. E'\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)
  18. ELSE E''
  19. END
  20. || CASE WHEN polwithcheck IS NOT NULL THEN
  21. E'\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)
  22. ELSE E''
  23. END || CASE WHEN polroles <> '{0}' THEN
  24. E'\n to: ' || pg_catalog.array_to_string(
  25. ARRAY(
  26. SELECT rolname
  27. FROM pg_catalog.pg_roles
  28. WHERE oid = ANY (polroles)
  29. ORDER BY 1
  30. ), E', ')
  31. ELSE E''
  32. END
  33. FROM pg_catalog.pg_policy pol
  34. WHERE polrelid = c.oid), E'\n')
  35. AS "Policies"
  36. FROM pg_catalog.pg_class c
  37. LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
  38. WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f')
  39. AND n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)
  40. ORDER BY 1, 2;

得到权限说明如下

  1. Schema | Name | Type | Access privileges | Column privileges | Policies
  2. --------+-----------------+----------+--------------------------------+-------------------+----------
  3. public | sbtest1 | table | postgres=arwdDxt/postgres +| |
  4. | | | digoal=a*r*w*d*D*x*t*/postgres | |
  5. public | sbtest10 | table | postgres=arwdDxt/postgres | |
  6. public | sbtest10_id_seq | sequence | | |
  7. public | sbtest11 | table | postgres=arwdDxt/postgres | |
  8. public | sbtest11_id_seq | sequence | | |
  9. public | sbtest12 | table | postgres=arwdDxt/postgres | |
  10. public | sbtest12_id_seq | sequence | | |

解释一下 Access privileges

rolename=xxx 其中rolename就是被赋予权限的用户名,即权限被赋予给谁了?

=xxx 表示这个权限赋予给了public角色,即所有人

/yyyy 表示是谁赋予的这个权限?

权限的含义如下

  1. rolename=xxxx -- privileges granted to a role
  2. =xxxx -- privileges granted to PUBLIC
  3. r -- SELECT ("read")
  4. w -- UPDATE ("write")
  5. a -- INSERT ("append")
  6. d -- DELETE
  7. D -- TRUNCATE
  8. x -- REFERENCES
  9. t -- TRIGGER
  10. X -- EXECUTE
  11. U -- USAGE
  12. C -- CREATE
  13. c -- CONNECT
  14. T -- TEMPORARY
  15. arwdDxt -- ALL PRIVILEGES (for tables, varies for other objects)
  16. * -- grant option for preceding privilege
  17. /yyyy -- role that granted this privilege

例子

赋予权限的人是postgres用户, sbtest2表的select权限被赋予给了digoal用户。

  1. postgres=# grant select on sbtest2 to digoal;
  2. GRANT
  3. postgres=# \dp+ sbtest2
  4. Access privileges
  5. Schema | Name | Type | Access privileges | Column privileges | Policies
  6. --------+---------+-------+---------------------------+-------------------+----------
  7. public | sbtest2 | table | postgres=arwdDxt/postgres+| |
  8. | | | digoal=r/postgres | |
  9. (1 row)

回收权限一定要针对已有的权限来,如果你发现这里的权限还在,那照着权限回收即可。

例如

revoke select on sbtest2 from digoal;      

2. 索引介绍

索引有什么用?
  1. 加速TUPLE定位
  2. 主键, 唯一约束
  3. 排序
索引的类型

B-Tree:支持排序、范围查询、精确查询;适合所有数据类型,单个索引条目不能超过索引页的1/3。

hash:支持等值查询;适合超长字段。

gin:倒排索引,支持等值、包含、相交、等查询;适合多值类型(数组、全文检索等),任意字段组合查询。

gist:R-Tree索引,支持包含,相交,距离,点面判断等查询;适合几何类型、范围类型、全文检索、异构类型等。

sp-gist:空间分区(平衡)r-tree,支持包含,相交,距离,点面判断等查询;适合几何类型、范围类型、全文检索、异构类型等。

brin:块级索引,适合物理存储与列值存在较好相关性的字段。比如时序数据、物联网传感数据、FEED数据等。支持范围查询、等值查询。

rum:扩展索引接口,支持全文检索,支持附加标量类型的全文检索,支持带位置关系的全文检索。

索引合并扫描

多个索引,PostgreSQL会使用bitmapAnd或bitmapOr合并扫描。

pic

表膨胀检查
  1. SELECT
  2. current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
  3. ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat,
  4. CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
  5. CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
  6. CASE WHEN relpages < otta THEN $$0 bytes$$::text ELSE (bs*(relpages-otta))::bigint || $$ bytes$$ END AS wastedsize,
  7. iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
  8. ROUND(CASE WHEN iotta=0 OR ipages=0 OR ipages=iotta THEN 0.0 ELSE ipages/iotta::numeric END,1) AS ibloat,
  9. CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
  10. CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
  11. CASE WHEN ipages < iotta THEN $$0 bytes$$ ELSE (bs*(ipages-iotta))::bigint || $$ bytes$$ END AS wastedisize,
  12. CASE WHEN relpages < otta THEN
  13. CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
  14. ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
  15. ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
  16. END AS totalwastedbytes
  17. FROM (
  18. SELECT
  19. nn.nspname AS schemaname,
  20. cc.relname AS tablename,
  21. COALESCE(cc.reltuples,0) AS reltuples,
  22. COALESCE(cc.relpages,0) AS relpages,
  23. COALESCE(bs,0) AS bs,
  24. COALESCE(CEIL((cc.reltuples*((datahdr+ma-
  25. (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
  26. COALESCE(c2.relname,$$?$$) AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
  27. COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
  28. FROM
  29. pg_class cc
  30. JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> $$information_schema$$
  31. LEFT JOIN
  32. (
  33. SELECT
  34. ma,bs,foo.nspname,foo.relname,
  35. (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
  36. (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
  37. FROM (
  38. SELECT
  39. ns.nspname, tbl.relname, hdr, ma, bs,
  40. SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
  41. MAX(coalesce(null_frac,0)) AS maxfracsum,
  42. hdr+(
  43. SELECT 1+count(*)/8
  44. FROM pg_stats s2
  45. WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
  46. ) AS nullhdr
  47. FROM pg_attribute att
  48. JOIN pg_class tbl ON att.attrelid = tbl.oid
  49. JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
  50. LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
  51. AND s.tablename = tbl.relname
  52. AND s.inherited=false
  53. AND s.attname=att.attname,
  54. (
  55. SELECT
  56. (SELECT current_setting($$block_size$$)::numeric) AS bs,
  57. CASE WHEN SUBSTRING(SPLIT_PART(v, $$ $$, 2) FROM $$#"[0-9]+.[0-9]+#"%$$ for $$#$$)
  58. IN ($$8.0$$,$$8.1$$,$$8.2$$) THEN 27 ELSE 23 END AS hdr,
  59. CASE WHEN v ~ $$mingw32$$ OR v ~ $$64-bit$$ THEN 8 ELSE 4 END AS ma
  60. FROM (SELECT version() AS v) AS foo
  61. ) AS constants
  62. WHERE att.attnum > 0 AND tbl.relkind=$$r$$
  63. GROUP BY 1,2,3,4,5
  64. ) AS foo
  65. ) AS rs
  66. ON cc.relname = rs.relname AND nn.nspname = rs.nspname
  67. LEFT JOIN pg_index i ON indrelid = cc.oid
  68. LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
  69. ) AS sml order by wastedbytes desc limit 5
检查膨胀
  1. SELECT
  2. current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
  3. ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat,
  4. CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
  5. CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
  6. CASE WHEN relpages < otta THEN $$0 bytes$$::text ELSE (bs*(relpages-otta))::bigint || $$ bytes$$ END AS wastedsize,
  7. iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
  8. ROUND(CASE WHEN iotta=0 OR ipages=0 OR ipages=iotta THEN 0.0 ELSE ipages/iotta::numeric END,1) AS ibloat,
  9. CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
  10. CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
  11. CASE WHEN ipages < iotta THEN $$0 bytes$$ ELSE (bs*(ipages-iotta))::bigint || $$ bytes$$ END AS wastedisize,
  12. CASE WHEN relpages < otta THEN
  13. CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
  14. ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
  15. ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
  16. END AS totalwastedbytes
  17. FROM (
  18. SELECT
  19. nn.nspname AS schemaname,
  20. cc.relname AS tablename,
  21. COALESCE(cc.reltuples,0) AS reltuples,
  22. COALESCE(cc.relpages,0) AS relpages,
  23. COALESCE(bs,0) AS bs,
  24. COALESCE(CEIL((cc.reltuples*((datahdr+ma-
  25. (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
  26. COALESCE(c2.relname,$$?$$) AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
  27. COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
  28. FROM
  29. pg_class cc
  30. JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> $$information_schema$$
  31. LEFT JOIN
  32. (
  33. SELECT
  34. ma,bs,foo.nspname,foo.relname,
  35. (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
  36. (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
  37. FROM (
  38. SELECT
  39. ns.nspname, tbl.relname, hdr, ma, bs,
  40. SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
  41. MAX(coalesce(null_frac,0)) AS maxfracsum,
  42. hdr+(
  43. SELECT 1+count(*)/8
  44. FROM pg_stats s2
  45. WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
  46. ) AS nullhdr
  47. FROM pg_attribute att
  48. JOIN pg_class tbl ON att.attrelid = tbl.oid
  49. JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
  50. LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
  51. AND s.tablename = tbl.relname
  52. AND s.inherited=false
  53. AND s.attname=att.attname,
  54. (
  55. SELECT
  56. (SELECT current_setting($$block_size$$)::numeric) AS bs,
  57. CASE WHEN SUBSTRING(SPLIT_PART(v, $$ $$, 2) FROM $$#"[0-9]+.[0-9]+#"%$$ for $$#$$)
  58. IN ($$8.0$$,$$8.1$$,$$8.2$$) THEN 27 ELSE 23 END AS hdr,
  59. CASE WHEN v ~ $$mingw32$$ OR v ~ $$64-bit$$ THEN 8 ELSE 4 END AS ma
  60. FROM (SELECT version() AS v) AS foo
  61. ) AS constants
  62. WHERE att.attnum > 0 AND tbl.relkind=$$r$$
  63. GROUP BY 1,2,3,4,5
  64. ) AS foo
  65. ) AS rs
  66. ON cc.relname = rs.relname AND nn.nspname = rs.nspname
  67. LEFT JOIN pg_index i ON indrelid = cc.oid
  68. LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
  69. ) AS sml order by wastedibytes desc limit 5
索引维护

1、新建索引

  1. set maintenance_work_mem ='4GB'; -- 越大,创建索引越快
  2. set lock_timeout = '1s'; -- 避免长时间锁等待
  3. create index [CONCURRENTLY] xxx on xxx using xxx (colxxx); -- 根据实际情况,是否使用 CONCURRENTLY(不堵塞读写)。

2、删除旧索引

  1. set lock_timeout = '1s'; -- 避免长时间锁等待
  2. drop index oldindex;

3、PK\UK的维护,与之类似,增加一步骤。

  1. ALTER TABLE tbl ADD
  2. [ CONSTRAINT constraint_name ]
  3. { UNIQUE | PRIMARY KEY } USING INDEX index_name
  4. [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

3. 系统配置

1、存储、文件系统规划

索引盘:对应索引表空间。

空间评估、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,可以开启文件系统压缩功能。

2、网络规划

带宽评估,网段规划,防火墙规划。

不建议使用公网。

3、CPU评估

根据业务需求,评估CPU主频,核数。建议实测性能指标。

4、内核配置

/etc/sysctl.conf

  1. # add by digoal.zhou
  2. fs.aio-max-nr = 1048576
  3. fs.file-max = 76724600
  4. kernel.core_pattern= /data01/corefiles/core_%e_%u_%t_%s.%p
  5. # /data01/corefiles事先建好,权限777,如果是软链接,对应的目录修改为777
  6. kernel.sem = 4096 2147483647 2147483646 512000
  7. # 信号量, ipcs -l 或 -u 查看,每16个进程一组,每组信号量需要17个信号量。
  8. kernel.shmall = 107374182
  9. # 所有共享内存段相加大小限制(建议内存的80%)
  10. kernel.shmmax = 274877906944
  11. # 最大单个共享内存段大小(建议为内存一半), >9.2的版本已大幅降低共享内存的使用
  12. kernel.shmmni = 819200
  13. # 一共能生成多少共享内存段,每个PG数据库集群至少2个共享内存段
  14. net.core.netdev_max_backlog = 10000
  15. net.core.rmem_default = 262144
  16. # The default setting of the socket receive buffer in bytes.
  17. net.core.rmem_max = 4194304
  18. # The maximum receive socket buffer size in bytes
  19. net.core.wmem_default = 262144
  20. # The default setting (in bytes) of the socket send buffer.
  21. net.core.wmem_max = 4194304
  22. # The maximum send socket buffer size in bytes.
  23. net.core.somaxconn = 4096
  24. net.ipv4.tcp_max_syn_backlog = 4096
  25. net.ipv4.tcp_keepalive_intvl = 20
  26. net.ipv4.tcp_keepalive_probes = 3
  27. net.ipv4.tcp_keepalive_time = 60
  28. net.ipv4.tcp_mem = 8388608 12582912 16777216
  29. net.ipv4.tcp_fin_timeout = 5
  30. net.ipv4.tcp_synack_retries = 2
  31. net.ipv4.tcp_syncookies = 1
  32. # 开启SYN Cookies。当出现SYN等待队列溢出时,启用cookie来处理,可防范少量的SYN攻击
  33. net.ipv4.tcp_timestamps = 1
  34. # 减少time_wait
  35. net.ipv4.tcp_tw_recycle = 0
  36. # 如果=1则开启TCP连接中TIME-WAIT套接字的快速回收,但是NAT环境可能导致连接失败,建议服务端关闭它
  37. net.ipv4.tcp_tw_reuse = 1
  38. # 开启重用。允许将TIME-WAIT套接字重新用于新的TCP连接
  39. net.ipv4.tcp_max_tw_buckets = 262144
  40. net.ipv4.tcp_rmem = 8192 87380 16777216
  41. net.ipv4.tcp_wmem = 8192 65536 16777216
  42. net.nf_conntrack_max = 1200000
  43. net.netfilter.nf_conntrack_max = 1200000
  44. vm.dirty_background_bytes = 409600000
  45. # 系统脏页到达这个值,系统后台刷脏页调度进程 pdflush(或其他) 自动将(dirty_expire_centisecs/100)秒前的脏页刷到磁盘
  46. vm.dirty_expire_centisecs = 3000
  47. # 比这个值老的脏页,将被刷到磁盘。3000表示30秒。
  48. vm.dirty_ratio = 95
  49. # 如果系统进程刷脏页太慢,使得系统脏页超过内存 95 % 时,则用户进程如果有写磁盘的操作(如fsync, fdatasync等调用),则需要主动把系统脏页刷出。
  50. # 有效防止用户进程刷脏页,在单机多实例,并且使用CGROUP限制单实例IOPS的情况下非常有效。
  51. vm.dirty_writeback_centisecs = 100
  52. # pdflush(或其他)后台刷脏页进程的唤醒间隔, 100表示1秒。
  53. vm.mmap_min_addr = 65536
  54. vm.overcommit_memory = 0
  55. # 在分配内存时,允许少量over malloc, 如果设置为 1, 则认为总是有足够的内存,内存较少的测试环境可以使用 1 .
  56. vm.overcommit_ratio = 90
  57. # 当overcommit_memory = 2 时,用于参与计算允许指派的内存大小。
  58. vm.swappiness = 0
  59. # 关闭交换分区
  60. vm.zone_reclaim_mode = 0
  61. # 禁用 numa, 或者在vmlinux中禁止.
  62. net.ipv4.ip_local_port_range = 40000 65535
  63. # 本地自动分配的TCP, UDP端口号范围
  64. fs.nr_open=20480000
  65. # 单个进程允许打开的文件句柄上限
  66. # 以下参数请注意
  67. # vm.extra_free_kbytes = 4096000
  68. # vm.min_free_kbytes = 2097152
  69. # 如果是小内存机器,以上两个值不建议设置
  70. # vm.nr_hugepages = 66536
  71. # 建议shared buffer设置超过64GB时 使用大页,页大小 /proc/meminfo Hugepagesize
  72. # vm.lowmem_reserve_ratio = 1 1 1
  73. # 对于内存大于64G时,建议设置,否则建议默认值 256 256 32

sysctl -p

5、资源限制

/etc/security/limits.conf

  1. * soft nofile 1024000
  2. * hard nofile 1024000
  3. * soft nproc unlimited
  4. * hard nproc unlimited
  5. * soft core unlimited
  6. * hard core unlimited
  7. * soft memlock unlimited
  8. * hard memlock unlimited
6、防火墙配置

例子

  1. # 私有网段
  2. -A INPUT -s 192.168.0.0/16 -j ACCEPT
  3. -A INPUT -s 10.0.0.0/8 -j ACCEPT
  4. -A INPUT -s 172.16.0.0/16 -j ACCEPT

4. 数据库初始化

1、initdb 介绍
  1. initdb initializes a PostgreSQL database cluster.
  2. Usage:
  3. initdb [OPTION]... [DATADIR]
  4. Options:
  5. -A, --auth=METHOD default authentication method for local connections
  6. --auth-host=METHOD default authentication method for local TCP/IP connections
  7. --auth-local=METHOD default authentication method for local-socket connections
  8. [-D, --pgdata=]DATADIR location for this database cluster
  9. -E, --encoding=ENCODING set default encoding for new databases
  10. --locale=LOCALE set default locale for new databases
  11. --lc-collate=, --lc-ctype=, --lc-messages=LOCALE
  12. --lc-monetary=, --lc-numeric=, --lc-time=LOCALE
  13. set default locale in the respective category for
  14. new databases (default taken from environment)
  15. --no-locale equivalent to --locale=C
  16. --pwfile=FILE read password for the new superuser from file
  17. -T, --text-search-config=CFG
  18. default text search configuration
  19. -U, --username=NAME database superuser name
  20. -W, --pwprompt prompt for a password for the new superuser
  21. -X, --xlogdir=XLOGDIR location for the transaction log directory
  22. Less commonly used options:
  23. -d, --debug generate lots of debugging output
  24. -k, --data-checksums use data page checksums
  25. -L DIRECTORY where to find the input files
  26. -n, --noclean do not clean up after errors
  27. -N, --nosync do not wait for changes to be written safely to disk
  28. -s, --show show internal settings
  29. -S, --sync-only only sync data directory
  30. Other options:
  31. -V, --version output version information, then exit
  32. -?, --help show this help, then exit
  33. If the data directory is not specified, the environment variable PGDATA
  34. is used.

例子

initdb -D $PGDATA -E UTF8 --locale=C -U postgres -X $PG_XLOG -W    
2、postgresql.conf参数配置

例子

  1. listen_addresses = '0.0.0.0'
  2. port = 1921
  3. max_connections = 200
  4. tcp_keepalives_idle = 60
  5. tcp_keepalives_interval = 10
  6. tcp_keepalives_count = 6
  7. shared_buffers = 512MB
  8. maintenance_work_mem = 64MB
  9. dynamic_shared_memory_type = windows
  10. vacuum_cost_delay = 0
  11. bgwriter_delay = 10ms
  12. bgwriter_lru_maxpages = 1000
  13. bgwriter_lru_multiplier = 5.0
  14. bgwriter_flush_after = 0
  15. old_snapshot_threshold = -1
  16. wal_level = minimal
  17. synchronous_commit = off
  18. full_page_writes = on
  19. wal_buffers = 64MB
  20. wal_writer_delay = 10ms
  21. wal_writer_flush_after = 4MB
  22. checkpoint_timeout = 35min
  23. max_wal_size = 2GB
  24. min_wal_size = 80MB
  25. checkpoint_completion_target = 0.1
  26. checkpoint_flush_after = 0
  27. random_page_cost = 1.5
  28. log_destination = 'csvlog'
  29. logging_collector = on
  30. log_directory = 'pg_log'
  31. log_truncate_on_rotation = on
  32. log_checkpoints = on
  33. log_connections = on
  34. log_disconnections = on
  35. log_error_verbosity = verbose
  36. log_temp_files = 8192
  37. log_timezone = 'Asia/Hong_Kong'
  38. autovacuum = on
  39. log_autovacuum_min_duration = 0
  40. autovacuum_naptime = 20s
  41. autovacuum_vacuum_scale_factor = 0.05
  42. autovacuum_freeze_max_age = 1500000000
  43. autovacuum_multixact_freeze_max_age = 1600000000
  44. autovacuum_vacuum_cost_delay = 0
  45. vacuum_freeze_table_age = 1400000000
  46. vacuum_multixact_freeze_table_age = 1500000000
  47. datestyle = 'iso, mdy'
  48. timezone = 'Asia/Hong_Kong'
  49. lc_messages = 'C'
  50. lc_monetary = 'C'
  51. lc_numeric = 'C'
  52. lc_time = 'C'
  53. default_text_search_config = 'pg_catalog.english'
3、pg_hba.conf数据库防火墙配置

例子

host all all 0.0.0.0/0 md5      

5. PostgreSQL控制

1、环境变量配置

/home/digoal/.bash_profile

  1. export PGPORT=1921
  2. export PGDATA=/home/digoal/pgdata
  3. export LANG=en_US.utf8
  4. export PGHOME=/home/digoal/pgsql9.6
  5. export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH
  6. export PATH=$PGHOME/bin:$PATH:.
  7. export MANPATH=$PGHOME/share/man:$MANPATH
  8. export PGHOST=$PGDATA
  9. export PGUSER=postgres
  10. export PGDATABASE=postgres
2、停库
pg_ctl stop -m fast -D $PGDATA    
3、重启
pg_ctl restart -m fast -D $PGDATA    
4、启动
pg_ctl start -D $PGDATA    
5、Linux自启动服务
  1. vi /etc/rc.local
  2. su - digoal -c "pg_ctl start -D $PGDATA"

6. 数据库备份和还原

1、逻辑备份
  1. pg_dump --help
  2. pg_dump dumps a database as a text file or to other formats.
  3. Usage:
  4. pg_dump [OPTION]... [DBNAME]
  5. General options:
  6. -f, --file=FILENAME output file or directory name
  7. -F, --format=c|d|t|p output file format (custom, directory, tar,
  8. plain text (default))
  9. -j, --jobs=NUM use this many parallel jobs to dump
  10. -v, --verbose verbose mode
  11. -V, --version output version information, then exit
  12. -Z, --compress=0-9 compression level for compressed formats
  13. --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock
  14. -?, --help show this help, then exit
  15. Options controlling the output content:
  16. -a, --data-only dump only the data, not the schema
  17. -b, --blobs include large objects in dump
  18. -c, --clean clean (drop) database objects before recreating
  19. -C, --create include commands to create database in dump
  20. -E, --encoding=ENCODING dump the data in encoding ENCODING
  21. -n, --schema=SCHEMA dump the named schema(s) only
  22. -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)
  23. -o, --oids include OIDs in dump
  24. -O, --no-owner skip restoration of object ownership in
  25. plain-text format
  26. -s, --schema-only dump only the schema, no data
  27. -S, --superuser=NAME superuser user name to use in plain-text format
  28. -t, --table=TABLE dump the named table(s) only
  29. -T, --exclude-table=TABLE do NOT dump the named table(s)
  30. -x, --no-privileges do not dump privileges (grant/revoke)
  31. --binary-upgrade for use by upgrade utilities only
  32. --column-inserts dump data as INSERT commands with column names
  33. --disable-dollar-quoting disable dollar quoting, use SQL standard quoting
  34. --disable-triggers disable triggers during data-only restore
  35. --enable-row-security enable row security (dump only content user has
  36. access to)
  37. --exclude-table-data=TABLE do NOT dump data for the named table(s)
  38. --if-exists use IF EXISTS when dropping objects
  39. --inserts dump data as INSERT commands, rather than COPY
  40. --no-security-labels do not dump security label assignments
  41. --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs
  42. --no-tablespaces do not dump tablespace assignments
  43. --no-unlogged-table-data do not dump unlogged table data
  44. --quote-all-identifiers quote all identifiers, even if not key words
  45. --section=SECTION dump named section (pre-data, data, or post-data)
  46. --serializable-deferrable wait until the dump can run without anomalies
  47. --snapshot=SNAPSHOT use given snapshot for the dump
  48. --strict-names require table and/or schema include patterns to
  49. match at least one entity each
  50. --use-set-session-authorization
  51. use SET SESSION AUTHORIZATION commands instead of
  52. ALTER OWNER commands to set ownership
  53. Connection options:
  54. -d, --dbname=DBNAME database to dump
  55. -h, --host=HOSTNAME database server host or socket directory
  56. -p, --port=PORT database server port number
  57. -U, --username=NAME connect as specified database user
  58. -w, --no-password never prompt for password
  59. -W, --password force password prompt (should happen automatically)
  60. --role=ROLENAME do SET ROLE before dump
  61. If no database name is supplied, then the PGDATABASE environment
  62. variable value is used.

《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        
2、逻辑还原
  1. pg_restore --help
  2. pg_restore restores a PostgreSQL database from an archive created by pg_dump.
  3. Usage:
  4. pg_restore [OPTION]... [FILE]
  5. General options:
  6. -d, --dbname=NAME connect to database name
  7. -f, --file=FILENAME output file name
  8. -F, --format=c|d|t backup file format (should be automatic)
  9. -l, --list print summarized TOC of the archive
  10. -v, --verbose verbose mode
  11. -V, --version output version information, then exit
  12. -?, --help show this help, then exit
  13. Options controlling the restore:
  14. -a, --data-only restore only the data, no schema
  15. -c, --clean clean (drop) database objects before recreating
  16. -C, --create create the target database
  17. -e, --exit-on-error exit on error, default is to continue
  18. -I, --index=NAME restore named index
  19. -j, --jobs=NUM use this many parallel jobs to restore
  20. -L, --use-list=FILENAME use table of contents from this file for
  21. selecting/ordering output
  22. -n, --schema=NAME restore only objects in this schema
  23. -O, --no-owner skip restoration of object ownership
  24. -P, --function=NAME(args) restore named function
  25. -s, --schema-only restore only the schema, no data
  26. -S, --superuser=NAME superuser user name to use for disabling triggers
  27. -t, --table=NAME restore named relation (table, view, etc.)
  28. -T, --trigger=NAME restore named trigger
  29. -x, --no-privileges skip restoration of access privileges (grant/revoke)
  30. -1, --single-transaction restore as a single transaction
  31. --disable-triggers disable triggers during data-only restore
  32. --enable-row-security enable row security
  33. --if-exists use IF EXISTS when dropping objects
  34. --no-data-for-failed-tables do not restore data of tables that could not be
  35. created
  36. --no-security-labels do not restore security labels
  37. --no-tablespaces do not restore tablespace assignments
  38. --section=SECTION restore named section (pre-data, data, or post-data)
  39. --strict-names require table and/or schema include patterns to
  40. match at least one entity each
  41. --use-set-session-authorization
  42. use SET SESSION AUTHORIZATION commands instead of
  43. ALTER OWNER commands to set ownership
  44. Connection options:
  45. -h, --host=HOSTNAME database server host or socket directory
  46. -p, --port=PORT database server port number
  47. -U, --username=NAME connect as specified database user
  48. -w, --no-password never prompt for password
  49. -W, --password force password prompt (should happen automatically)
  50. --role=ROLENAME do SET ROLE before restore
  51. The options -I, -n, -P, -t, -T, and --section can be combined and specified
  52. multiple times to select multiple objects.
  53. If no input file name is supplied, then standard input is used.

如果备份为-F p格式,备份输出为文本,直接运行即可。

psql postgres postgres -f ./digoal.dmp      
3、配置归档、流复制

要支持物理备份,务必打开归档,同时建议打开流复制。

配置归档目录

  1. # mkdir -p /disk1/digoal/arch
  2. # chown digoal:digoal /disk1/digoal/arch

配置流复制和归档

vi postgresql.conf

  1. max_worker_processes = 16
  2. max_wal_senders = 8
  3. archive_command = 'test ! -f /disk1/digoal/arch/%f && cp %p /disk1/digoal/arch/%f'

重启数据库

pg_ctl restart -m fast -D $PGDATA    
4、创建流复制用户
  1. postgres=# create role rep replication login encrypted password 'rep123';
  2. CREATE ROLE
5、配置流复制防火墙

vi $PGDATA/pg_hba.conf

host replication rep 0.0.0.0/0 md5    

pg_ctl reload -D $PGDATA

6、远程物理基础备份
  1. pg_basebackup --help
  2. pg_basebackup takes a base backup of a running PostgreSQL server.
  3. Usage:
  4. pg_basebackup [OPTION]...
  5. Options controlling the output:
  6. -D, --pgdata=DIRECTORY receive base backup into directory
  7. -F, --format=p|t output format (plain (default), tar)
  8. -r, --max-rate=RATE maximum transfer rate to transfer data directory
  9. (in kB/s, or use suffix "k" or "M")
  10. -R, --write-recovery-conf
  11. write recovery.conf after backup
  12. -S, --slot=SLOTNAME replication slot to use
  13. -T, --tablespace-mapping=OLDDIR=NEWDIR
  14. relocate tablespace in OLDDIR to NEWDIR
  15. -x, --xlog include required WAL files in backup (fetch mode)
  16. -X, --xlog-method=fetch|stream
  17. include required WAL files with specified method
  18. --xlogdir=XLOGDIR location for the transaction log directory
  19. -z, --gzip compress tar output
  20. -Z, --compress=0-9 compress tar output with given compression level
  21. General options:
  22. -c, --checkpoint=fast|spread
  23. set fast or spread checkpointing
  24. -l, --label=LABEL set backup label
  25. -P, --progress show progress information
  26. -v, --verbose output verbose messages
  27. -V, --version output version information, then exit
  28. -?, --help show this help, then exit
  29. Connection options:
  30. -d, --dbname=CONNSTR connection string
  31. -h, --host=HOSTNAME database server host or socket directory
  32. -p, --port=PORT database server port number
  33. -s, --status-interval=INTERVAL
  34. time between status packets sent to server (in seconds)
  35. -U, --username=NAME connect as specified database user
  36. -w, --no-password never prompt for password
  37. -W, --password force password prompt (should happen automatically)

创建备份目录,备份可以通过流复制协议,备份到远程。

  1. # mkdir -p /disk1/digoal/backup
  2. # chown digoal:digoal /disk1/digoal/backup

例子 1,通过流复制用户,以及流复制备份

  1. export PGPASSWORD=rep123
  2. pg_basebackup -D /disk1/digoal/backup -F t -z -h 数据库IP -p 数据库端口 -U rep

例子 2,使用cp备份

步骤如下

  1. select pg_start_backup('test');
  2. copy 数据文件,表空间等目录
  3. select pg_stop_backup();
7、物理增量备份

物理增量备份分为两种,

一种是数据文件的增量备份,需要等10.0或者使用pg_rman, pg_probackup

https://github.com/postgrespro/pg_probackup

https://github.com/ossc-db/pg_rman

另一种是归档增量备份。

将归档文件拷贝到备份存储即可。

8、PITR(时间点恢复)

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')

  1. #recovery_target_name = '' # e.g. 'daily backup 2011-01-26'
  2. #
  3. #recovery_target_time = '' # e.g. '2004-07-14 22:39:00 EST'
  4. #
  5. #recovery_target_xid = ''
  6. #
  7. #recovery_target_inclusive = true

6. 启动恢复库

pg_ctl start -D 恢复库$PGDATA    
PITR 时间点恢复 例子

数据变更操作(主库)

  1. postgres=# select pg_create_restore_point('digoal');
  2. pg_create_restore_point
  3. -------------------------
  4. 1D6/FB17EC08
  5. (1 row)

首先要创建一个记录还原点XID的表。记录XID,时间,以及描述信息。(来代替pg_create_restore_point 系统函数的功能)

  1. postgres=> create table restore_point(id serial primary key, xid int8, crt_time timestamp default now(), point text);
  2. CREATE TABLE

创建一个函数,代替pg_create_restore_point的功能,插入还原点。

  1. postgres=> create or replace function create_restore_point(i_point text) returns void as $$
  2. declare
  3. begin
  4. insert into restore_point(xid,point) values (txid_current(),i_point);
  5. end;
  6. $$ language plpgsql strict;
  7. CREATE FUNCTION

插入一个还原点

  1. postgres=> select create_restore_point('digoal');
  2. create_restore_point
  3. ----------------------
  4. (1 row)

查询这个表的信息:

  1. postgres=> select * from restore_point;
  2. id | xid | crt_time | point
  3. ----+--------+----------------------------+--------
  4. 1 | 561426 | 2015-06-19 09:18:57.525475 | digoal
  5. (1 row)
  6. postgres=> select * from restore_point where point='digoal';
  7. id | xid | crt_time | point
  8. ----+--------+----------------------------+--------
  9. 1 | 561426 | 2015-06-19 09:18:57.525475 | digoal
  10. (1 row)

接下来要模拟一下还原:

  1. postgres=> create table test(id int,info text);
  2. CREATE TABLE
  3. postgres=> insert into test select generate_series(1,1000),md5(random()::text);
  4. INSERT 0 1000

记录当前哈希值。用于恢复后的比对。

  1. postgres=> select sum(hashtext(t.*::text)) from test t;
  2. sum
  3. --------------
  4. -69739904784
  5. (1 row)

接下来我要做一笔删除操作,在删除前,我先创建一条还原点信息。

  1. postgres=> select create_restore_point('before delete test');
  2. create_restore_point
  3. ----------------------
  4. (1 row)
  5. postgres=> delete from test;
  6. DELETE 1000
  7. postgres=> select * from restore_point where point='before delete test';
  8. id | xid | crt_time | point
  9. ----+--------+----------------------------+--------------------
  10. 2 | 561574 | 2015-06-19 09:45:28.030295 | before delete test
  11. (1 row)

我只需要恢复到561574 即可。接下来就是模拟恢复了。

主动产生一些XLOG,触发归档。

  1. postgres=> select pg_xlogfile_name(pg_current_xlog_location());
  2. pg_xlogfile_name
  3. --------------------------
  4. 000000010000000200000041
  5. (1 row)
  6. postgres=> insert into test select generate_series(1,100000);
  7. INSERT 0 100000
  8. postgres=> insert into test select generate_series(1,100000);
  9. INSERT 0 100000
  10. postgres=> select pg_xlogfile_name(pg_current_xlog_location());
  11. pg_xlogfile_name
  12. --------------------------
  13. 000000010000000200000042
  14. (1 row)

下载阿里云RDS的备份和归档到本地。

在本地需要安装一个postgresql, 与阿里云RDS的编译配置参数一致(例如数据块的大小),最好使用的模块也一致,这里没有用到其他模块,所以无所谓。

通过pg_settings来看一下RDS的配置信息,版本信息,方便我们在本地进行恢复。

  1. postgres=> select name,setting,unit from pg_settings where category='Preset Options';
  2. name | setting | unit
  3. -----------------------+---------+------
  4. block_size | 8192 |
  5. data_checksums | on |
  6. integer_datetimes | on |
  7. max_function_args | 100 |
  8. max_identifier_length | 63 |
  9. max_index_keys | 32 |
  10. segment_size | 131072 | 8kB
  11. server_version | 9.4.1 |
  12. server_version_num | 90401 |
  13. wal_block_size | 8192 |
  14. wal_segment_size | 2048 | 8kB
  15. (11 rows)
  16. postgres=> select version();
  17. version
  18. --------------------------------------------------------------------------------------------------------------
  19. 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
  20. (1 row)

本地编译安装PostgreSQL 9.4.1,编译参数与RDS一致。阿里云RDS这几个参数都是默认的。

  1. --with-blocksize=BLOCKSIZE
  2. set table block size in kB [8]
  3. --with-segsize=SEGSIZE set table segment size in GB [1]
  4. --with-wal-blocksize=BLOCKSIZE
  5. set WAL block size in kB [8]
  6. --with-wal-segsize=SEGSIZE
  7. set WAL segment size in MB [16]
  8. # useradd digoal
  9. # su - digoal
  10. $ vi .bash_profile
  11. # add by digoal
  12. export PS1="$USER@`/bin/hostname -s`-> "
  13. export PGPORT=1931
  14. export PGDATA=/home/digoal/pg_root
  15. export LANG=en_US.utf8
  16. export PGHOME=/home/digoal/pgsql9.4.1
  17. export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH
  18. export DATE=`date +"%Y%m%d%H%M"`
  19. export PATH=$PGHOME/bin:$PATH:.
  20. export MANPATH=$PGHOME/share/man:$MANPATH
  21. export PGHOST=$PGDATA
  22. export PGDATABASE=postgres
  23. alias rm='rm -i'
  24. alias ll='ls -lh'
  25. unalias vi
  26. # wget https://ftp.postgresql.org/pub/source/v9.4.1/postgresql-9.4.1.tar.bz2
  27. # tar -jxvf postgresql-9.4.1.tar.bz2
  28. # cd postgresql-9.4.1
  29. # ./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
  30. # gmake world && gmake install-world

下载备份和归档文件,解压:

基础备份选择需要恢复的时间点之前的一个备份,归档则选择在此之后的所有归档文件。

  1. total 453M
  2. -rw-r--r-- 1 root root 17M Jun 19 10:23 000000010000000200000040.tar.gz
  3. -rw-r--r-- 1 root root 17M Jun 19 10:23 000000010000000200000041.tar.gz
  4. -rw-r--r-- 1 root root 404M Jun 19 10:23 hins668881_xtra_20150618232331.tar.gz
  5. # mkdir /home/digoal/pg_root
  6. # mv hins668881_xtra_20150618232331.tar.gz /home/digoal/pg_root
  7. # tar -zxvf hins668881_xtra_20150618232331.tar.gz
  8. [root@db-172-16-3-150 ~]# tar -xvf 000000010000000200000040.tar.gz
  9. 000000010000000200000040
  10. [root@db-172-16-3-150 ~]# tar -xvf 000000010000000200000041.tar.gz
  11. 000000010000000200000041
  12. [root@db-172-16-3-150 ~]# mv 000000010000000200000040 /home/digoal/
  13. [root@db-172-16-3-150 ~]# mv 000000010000000200000041 /home/digoal/
  14. [root@db-172-16-3-150 ~]# chown -R digoal:digoal /home/digoal
  15. [root@db-172-16-3-150 ~]# chmod -R 700 /home/digoal/pg_root

修改配置文件,注释掉阿里云RDS PG的一些定制参数。

  1. $ vi postgresql.conf
  2. port=1931
  3. 注释RDS自定义的GUC参数
  4. #rds_enable_proxy=on
  5. #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"'
  6. #rds_enable_admin_user_as_super=on

配置recovery.conf

打开hot_standby,恢复到目标点后暂停,如果确认已经到达,使用resume激活。

  1. $ vi recovery.conf
  2. standby_mode = 'on'
  3. restore_command = 'cp /home/digoal/%f %p'
  4. recovery_target_xid='561574' # 使用我们自建的恢复点的XID
  5. recovery_target_inclusive=true
  6. pause_at_recovery_target=true

启动数据库

$ pg_ctl start      

检查是否恢复到指定XID

  1. digoal@db-172-16-3-150-> psql -h 127.0.0.1 -p 1931
  2. psql (9.4.1)
  3. Type "help" for help.
  4. postgres=> \dt
  5. List of relations
  6. Schema | Name | Type | Owner
  7. --------+-----------------+-------+--------
  8. public | ha_health_check | table | aurora
  9. public | login_log | table | digoal
  10. public | restore_point | table | digoal
  11. public | session | table | digoal
  12. public | tbl_small | table | digoal
  13. public | test | table | digoal
  14. public | userinfo | table | digoal
  15. (7 rows)

检查,已经恢复到DELETE test表的数据之前了。

  1. postgres=> select count(*) from test;
  2. count
  3. -------
  4. 1000
  5. (1 row)
  6. postgres=> select sum(hashtext(t.*::text)) from test t;
  7. sum
  8. --------------
  9. -69739904784
  10. (1 row)

7. 数据库性能

1、参数优化

假设 512GB 内存, SSD.

  1. listen_addresses = '0.0.0.0'
  2. port = 1921
  3. max_connections = 5000
  4. unix_socket_directories = '.' # 确保unix socket处于安全目录
  5. tcp_keepalives_idle = 60 # 避免网络层设备主动断开空闲连接的问题
  6. tcp_keepalives_interval = 10 # 避免网络层设备主动断开空闲连接的问题
  7. tcp_keepalives_count = 10 # 避免网络层设备主动断开空闲连接的问题
  8. shared_buffers = 128GB # 1/4 物理内存
  9. maintenance_work_mem = 4GB # 加速创建索引,VACUUM垃圾回收,平时最多消耗 maintenance_work_mem * autovacuum_max_workers 内存
  10. dynamic_shared_memory_type = posix
  11. vacuum_cost_delay = 0 # SSD, 建议设置为0, 不打断vacuum
  12. bgwriter_delay = 10ms # 快速刷shared buffer脏页
  13. bgwriter_lru_maxpages = 1000
  14. bgwriter_lru_multiplier = 10.0
  15. bgwriter_flush_after = 0 # IO很好的机器,不需要考虑平滑调度。否则建议设置为大于0
  16. max_worker_processes = 128
  17. max_parallel_workers_per_gather = 0
  18. old_snapshot_threshold = -1
  19. backend_flush_after = 0 # IO很好的机器,不需要考虑平滑调度
  20. wal_level = replica
  21. synchronous_commit = off # 异步提交
  22. full_page_writes = on # COW文件系统,或者对齐并支持BLOCK_SIZE大小原子写的SSD,可以关闭,提高性能,减少WAL的写入量。
  23. wal_buffers = 1GB
  24. wal_writer_delay = 10ms
  25. wal_writer_flush_after = 0 # IO很好的机器,不需要考虑平滑调度
  26. checkpoint_timeout = 30min # 不建议频繁做检查点,否则XLOG会产生很多的FULL PAGE WRITE
  27. max_wal_size = 256GB # 建议设置为SHARED BUFFER的2
  28. min_wal_size = 32GB
  29. checkpoint_completion_target = 0.05 # 硬盘好的情况下,可以让检查点快速结束,恢复时也可以快速达到一致状态。
  30. checkpoint_flush_after = 0 # IO很好的机器,不需要考虑平滑调度
  31. archive_mode = on
  32. archive_command = '/bin/date' # 后期再修改,如 'test ! -f /disk1/digoal/arch/%f && cp %p /disk1/digoal/arch/%f'
  33. max_wal_senders = 8
  34. random_page_cost = 1.3 # IO很好的机器,不需要考虑离散和顺序扫描的成本差异
  35. parallel_tuple_cost = 0
  36. parallel_setup_cost = 0
  37. min_parallel_relation_size = 0
  38. effective_cache_size = 300GB # 看着办,减掉数据库shared buffer, maintenance work mem, work mem, wal shared buffer,剩下的都是OS可用的CACHE。
  39. force_parallel_mode = off
  40. log_destination = 'csvlog'
  41. logging_collector = on
  42. log_truncate_on_rotation = on
  43. log_checkpoints = on
  44. log_connections = on
  45. log_disconnections = on
  46. log_error_verbosity = verbose
  47. log_timezone = 'PRC'
  48. autovacuum = on
  49. log_autovacuum_min_duration = 0
  50. autovacuum_max_workers = 16 # CPU核多,并且IO好的情况下,可多点,但是注意 16*autovacuum mem ,会消耗较多内存,所以内存也要有基础。
  51. autovacuum_naptime = 20s
  52. autovacuum_vacuum_scale_factor = 0.05 # 垃圾版本超过5%时,触发垃圾回收
  53. vacuum_freeze_min_age = 50000000 # 年龄超过5000万的记录,都设置为冻结年龄
  54. vacuum_multixact_freeze_min_age = 5000000
  55. autovacuum_freeze_max_age = 1600000000 # 表的年龄超过16亿时,强制触发vacuum freeze(即使没有开启autovacuum)
  56. vacuum_freeze_table_age = 1200000000 # 表的年龄超过12亿时,autovacuum 触发vacuum freeze
  57. vacuum_multixact_freeze_table_age = 1100000000
  58. datestyle = 'iso, mdy'
  59. timezone = 'PRC'
  60. lc_messages = 'C'
  61. lc_monetary = 'C'
  62. lc_numeric = 'C'
  63. lc_time = 'C'
  64. default_text_search_config = 'pg_catalog.english'
  65. shared_preload_libraries='pg_stat_statements'
2、性能视图 pg_stat*
  1. List of relations
  2. Schema | Name | Type | Owner
  3. ------------+-----------------------------+------+----------
  4. pg_catalog | pg_stat_activity | view | postgres
  5. pg_catalog | pg_stat_all_indexes | view | postgres
  6. pg_catalog | pg_stat_all_tables | view | postgres
  7. pg_catalog | pg_stat_archiver | view | postgres
  8. pg_catalog | pg_stat_bgwriter | view | postgres
  9. pg_catalog | pg_stat_database | view | postgres
  10. pg_catalog | pg_stat_database_conflicts | view | postgres
  11. pg_catalog | pg_stat_progress_vacuum | view | postgres
  12. pg_catalog | pg_stat_replication | view | postgres
  13. pg_catalog | pg_stat_ssl | view | postgres
  14. pg_catalog | pg_stat_sys_indexes | view | postgres
  15. pg_catalog | pg_stat_sys_tables | view | postgres
  16. pg_catalog | pg_stat_user_functions | view | postgres
  17. pg_catalog | pg_stat_user_indexes | view | postgres
  18. pg_catalog | pg_stat_user_tables | view | postgres
  19. pg_catalog | pg_stat_wal_receiver | view | postgres
  20. pg_catalog | pg_stat_xact_all_tables | view | postgres
  21. pg_catalog | pg_stat_xact_sys_tables | view | postgres
  22. pg_catalog | pg_stat_xact_user_functions | view | postgres
  23. pg_catalog | pg_stat_xact_user_tables | view | postgres
  24. pg_catalog | pg_statio_all_indexes | view | postgres
  25. pg_catalog | pg_statio_all_sequences | view | postgres
  26. pg_catalog | pg_statio_all_tables | view | postgres
  27. pg_catalog | pg_statio_sys_indexes | view | postgres
  28. pg_catalog | pg_statio_sys_sequences | view | postgres
  29. pg_catalog | pg_statio_sys_tables | view | postgres
  30. pg_catalog | pg_statio_user_indexes | view | postgres
  31. pg_catalog | pg_statio_user_sequences | view | postgres
  32. pg_catalog | pg_statio_user_tables | view | postgres
  33. pg_catalog | pg_stats | view | postgres
  34. (30 rows)
3、TOP SQL

pg_stat_statements插件,统计SQL调用的资源消耗。

  1. create extension pg_stat_statements;
  2. 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;    
4、AWR

《PostgreSQL AWR报告(for 阿里云ApsaraDB PgSQL)》

5、auto_explain

打印超时SQL当时的执行计划。

  1. shared_preload_libraries = 'auto_explain'
  2. 配置
  3. auto_explain.log_analyze = on
  4. auto_explain.log_nested_statements = on
  5. auto_explain.log_buffers = on
  6. auto_explain.log_min_duration = '1s'
  7. auto_explain.log_timing = on
  8. auto_explain.log_verbose = on
6、explain解读

explain 语法

pic

explain 例子

pic

explain 节点

pic

8. 数据库压测

pg_bench介绍
  1. pgbench --help
  2. pgbench is a benchmarking tool for PostgreSQL.
  3. Usage:
  4. pgbench [OPTION]... [DBNAME]
  5. Initialization options:
  6. -i, --initialize invokes initialization mode
  7. -F, --fillfactor=NUM set fill factor
  8. -n, --no-vacuum do not run VACUUM after initialization
  9. -q, --quiet quiet logging (one message each 5 seconds)
  10. -s, --scale=NUM scaling factor
  11. --foreign-keys create foreign key constraints between tables
  12. --index-tablespace=TABLESPACE
  13. create indexes in the specified tablespace
  14. --tablespace=TABLESPACE create tables in the specified tablespace
  15. --unlogged-tables create tables as unlogged tables
  16. Options to select what to run:
  17. -b, --builtin=NAME[@W] add builtin script NAME weighted at W (default: 1)
  18. (use "-b list" to list available scripts)
  19. -f, --file=FILENAME[@W] add script FILENAME weighted at W (default: 1)
  20. -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches
  21. (same as "-b simple-update")
  22. -S, --select-only perform SELECT-only transactions
  23. (same as "-b select-only")
  24. Benchmarking options:
  25. -c, --client=NUM number of concurrent database clients (default: 1)
  26. -C, --connect establish new connection for each transaction
  27. -D, --define=VARNAME=VALUE
  28. define variable for use by custom script
  29. -j, --jobs=NUM number of threads (default: 1)
  30. -l, --log write transaction times to log file
  31. -L, --latency-limit=NUM count transactions lasting more than NUM ms as late
  32. -M, --protocol=simple|extended|prepared
  33. protocol for submitting queries (default: simple)
  34. -n, --no-vacuum do not run VACUUM before tests
  35. -P, --progress=NUM show thread progress report every NUM seconds
  36. -r, --report-latencies report average latency per command
  37. -R, --rate=NUM target rate in transactions per second
  38. -s, --scale=NUM report this scale factor in output
  39. -t, --transactions=NUM number of transactions each client runs (default: 10)
  40. -T, --time=NUM duration of benchmark test in seconds
  41. -v, --vacuum-all vacuum all four standard tables before tests
  42. --aggregate-interval=NUM aggregate data over NUM seconds
  43. --progress-timestamp use Unix epoch timestamps for progress
  44. --sampling-rate=NUM fraction of transactions to log (e.g., 0.01 for 1%)
  45. Common options:
  46. -d, --debug print debugging output
  47. -h, --host=HOSTNAME database server host or socket directory
  48. -p, --port=PORT database server port number
  49. -U, --username=USERNAME connect as specified database user
  50. -V, --version output version information, then exit
  51. -?, --help show this help, then exit
tpc-b测试
  1. \set aid random(1, 100000 * :scale)
  2. \set bid random(1, 1 * :scale)
  3. \set tid random(1, 10 * :scale)
  4. \set delta random(-5000, 5000)
  5. BEGIN;
  6. UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
  7. SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
  8. UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
  9. UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
  10. INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
  11. END;

初始化数据, 1000万记录。

  1. export PGPASSWORD=密码
  2. pgbench -i -s 100

测试

  1. export PGPASSWORD=密码
  2. 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);    

创建脚本

  1. vi test.sql
  2. \set id random(1,100000000)
  3. 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;

压测

  1. pgbench -M prepared -n -r -P 1 -f ./test.sql -c 32 -j 32 -T 100
  2. progress: 1.0 s, 246533.1 tps, lat 0.128 ms stddev 0.536
  3. progress: 2.0 s, 254653.8 tps, lat 0.125 ms stddev 0.333
  4. progress: 3.0 s, 232433.6 tps, lat 0.137 ms stddev 0.812
  5. progress: 4.0 s, 258225.7 tps, lat 0.123 ms stddev 0.250

9. 日常维护

1、AWR健康报告

2、垃圾回收

3、膨胀索引重建

4、TOP SQL性能优化

5、错误日志分析

6、安全风险评估(SQL注入、暴力破解、密码周期修改)

7、备份可用性校验

8、历史备份和归档清理

9、历史数据清理

10、实时监控系统建设

11、HA建设、监控、演练

12、容灾建设、监控、演练

13、审计系统建设

14、业务逻辑优化

15、内核优化

16、版本升级、BUG FIX

17、社区交流

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/354805
推荐阅读
相关标签
  

闽ICP备14008679号