PostgreSQL 快速大版本升级多种方案 - 含重点介绍fast & safe upgrade to PostgreSQL 9.4 use pg_upgrade & zfs

16 minute read

背景

已使用pg_upgrade顺利将一个8TB的生产数据库(包含表, 索引, 类型, 函数, 外部对象等对象大概10万个)从9.3升级到9.4, 升级比较快(约2分钟), 因为数据库较大后期analyze的时间比较长, 不过你可以将常用的表优先analyze一下, 就可以放心大胆的提供服务了.

PostgreSQL 9.4于(2014-12-18)正式发布, 为了让大家可以快速的享受9.4带来的强大特性, 写一篇使用zfs和pg_upgrade升级9.4的快速可靠的文章. 希望对大家有帮助.

提醒:

在正式升级9.4前, 请做好功课, 至少release note要阅读一遍, 特别是兼容性. 例如有些应用可能用了某些9.4不兼容的语法或者插件的话, 需要解决了再上. (以前就有出现过版本升级带来的bytea的默认表述变更导致的程序异常)

pg_upgrade支持从8.3.x以及更新的版本的跨大版本升级, 使用LINK模式, 可以减少数据的拷贝工作, 大大提高版本升级的速度.

本文将演示一下使用pg_upgrade将数据库从9.3.5升级到最新的9.4.

使用zfs快照来保存老的数据文件和软件. 如果升级失败, 回滚非常简单, 回退到ZFS快照或者使用ZFS快照克隆都可以.

实际上,使用备库来进行升级演练,把流程都跑通,是很不错的选择。ZFS则是加一道保险,或者说方便多次(克隆ZFS进行演练)演练。

pic

升级步骤简介

1、假设主机已是基于ZFS

  停库  
  
  创建快照  
  
  使用upgrade升级  

2、假设主机不是基于ZFS

  创建ZFS主机  
  
  创建PostgreSQL物理standby  
  
  主备角色切换,把主库切到ZFS主机下。  
  
  以下基于新的主库操作:  
  
  停主  
  
  创建快照  
  
  使用upgrade升级  

3、如何把老版本的standby升级成为9.4 standby?

  pg start backup  
  
  rsync 数据文件  
  
  pg_stop_backup  
  
  创建recovery.conf 继续.  

使用ZFS和pg_upgrade升级9.4的详细步骤

以CentOS 7 x64为例,

测试环境部署

安装zfs

http://download.fedoraproject.org/pub/epel 找到最新的epel7 rpm包, 加入YUM仓库.

例如当下版本如下 :

[root@localhost ~]# yum localinstall --nogpgcheck http://ftp.cuhk.edu.hk/pub/linux/fedora-epel/7/x86_64/e/epel-release-7-5.noarch.rpm  
[root@localhost ~]# yum localinstall --nogpgcheck http://archive.zfsonlinux.org/epel/zfs-release.el7.noarch.rpm  
[root@localhost ~]# uname -r  
3.10.0-123.el7.x86_64  
[root@localhost ~]# yum install kernel-devel-3.10.0-123.el7 zfs   

安装好ZFS后, 创建ZPOOL, 我们使用5个文件来模拟5块磁盘.

[root@localhost disks]# dd if=/dev/zero of=./disk1 bs=8192k count=1024 oflag=direct  
[root@localhost disks]# dd if=/dev/zero of=./disk2 bs=8192k count=1024 oflag=direct  
[root@localhost disks]# dd if=/dev/zero of=./disk3 bs=8192k count=1024 oflag=direct  
[root@localhost disks]# dd if=/dev/zero of=./disk4 bs=8192k count=1024 oflag=direct  
[root@localhost disks]# dd if=/dev/zero of=./disk5 bs=8192k count=1024 oflag=direct  

创建zpool

[root@localhost disks]# zpool create -o ashift=12 zp1 raidz /data01/disks/disk1 /data01/disks/disk2 /data01/disks/disk3 /data01/disks/disk4 /data01/disks/disk5  
[root@localhost disks]# zpool status  
  pool: zp1  
 state: ONLINE  
  scan: none requested  
config:  
  
        NAME                     STATE     READ WRITE CKSUM  
        zp1                      ONLINE       0     0     0  
          raidz1-0               ONLINE       0     0     0  
            /data01/disks/disk1  ONLINE       0     0     0  
            /data01/disks/disk2  ONLINE       0     0     0  
            /data01/disks/disk3  ONLINE       0     0     0  
            /data01/disks/disk4  ONLINE       0     0     0  
            /data01/disks/disk5  ONLINE       0     0     0  

设置zfs默认参数 :

[root@localhost disks]# zfs set atime=off zp1  
[root@localhost disks]# zfs set compression=lz4 zp1  
[root@localhost disks]# zfs set canmount=off zp1  

接下来, 我们需要规划一下数据库的目录结构.

假设分开5个文件系统来存放.

$PGDATA  
pg_xlog  
pg_arch  
tbs1  
tbs2  

创建对应的zfs文件系统

[root@localhost disks]# zfs create -o mountpoint=/pgdata01 zp1/pg_root  
[root@localhost disks]# zfs create -o mountpoint=/pgdata02 zp1/pg_xlog  
[root@localhost disks]# zfs create -o mountpoint=/pgdata03 zp1/pg_arch  
[root@localhost disks]# zfs create -o mountpoint=/pgdata04 zp1/tbs1  
[root@localhost disks]# zfs create -o mountpoint=/pgdata05 zp1/tbs2  
[root@localhost disks]# df -h  
zp1/pg_root                 32G  256K   32G   1% /pgdata01  
zp1/pg_xlog                 32G  256K   32G   1% /pgdata02  
zp1/pg_arch                 32G  256K   32G   1% /pgdata03  
zp1/tbs1                    32G  256K   32G   1% /pgdata04  
zp1/tbs2                    32G  256K   32G   1% /pgdata05  

创建数据目录

[root@localhost ~]# mkdir /pgdata01/pg_root  
[root@localhost ~]# mkdir /pgdata02/pg_xlog  
[root@localhost ~]# mkdir /pgdata03/pg_arch  
[root@localhost ~]# mkdir /pgdata04/tbs1  
[root@localhost ~]# mkdir /pgdata05/tbs2  
[root@localhost ~]# chown -R postgres:postgres /pgdata0*/  

接下来安装PostgreSQL 9.3.5, 并初始化数据库, 生成测试数据.

[root@localhost soft_bak]# tar -jxvf postgresql-9.3.5.tar.bz2  
[root@localhost soft_bak]# cd postgresql-9.3.5  

注意在升级到9.4时, 软件的编译参数要一致, 例如我们这里使用了非默认的数据块, 所以在编译9.4时也需要一致.

[root@localhost soft_bak]# yum -y install glib2 lrzsz sysstat e4fsprogs xfsprogs ntp readline-devel zlib zlib-devel openssl openssl-devel pam-devel libxml2-devel libxslt-devel python-devel tcl-devel gcc make smartmontools flex bison perl perl-devel perl-ExtUtils* OpenIPMI-tools openldap openldap-devel  
[root@localhost postgresql-9.3.5]# ./configure --prefix=/opt/pgsql9.3.5 --with-pgport=1921 --with-perl --with-tcl --with-python --with-openssl --with-pam --without-ldap --with-libxml --with-libxslt --enable-thread-safety --with-blocksize=32 --with-wal-blocksize=32 && gmake world && gmake install-world  
[root@localhost postgresql-9.3.5]# ln -s /opt/pgsql9.3.5 /opt/pgsql  
[root@localhost postgresql-9.3.5]# vi /etc/ld.so.conf  
/opt/pgsql/lib  
[root@localhost postgresql-9.3.5]# ldconfig  
  
[root@localhost postgresql-9.3.5]# ldconfig -p|grep /opt/pgsql  
        libpqwalreceiver.so (libc6,x86-64) => /opt/pgsql/lib/libpqwalreceiver.so  
        libpq.so.5 (libc6,x86-64) => /opt/pgsql/lib/libpq.so.5  
        libpq.so (libc6,x86-64) => /opt/pgsql/lib/libpq.so  
        libpgtypes.so.3 (libc6,x86-64) => /opt/pgsql/lib/libpgtypes.so.3  
        libpgtypes.so (libc6,x86-64) => /opt/pgsql/lib/libpgtypes.so  
        libecpg_compat.so.3 (libc6,x86-64) => /opt/pgsql/lib/libecpg_compat.so.3  
        libecpg_compat.so (libc6,x86-64) => /opt/pgsql/lib/libecpg_compat.so  
        libecpg.so.6 (libc6,x86-64) => /opt/pgsql/lib/libecpg.so.6  
        libecpg.so (libc6,x86-64) => /opt/pgsql/lib/libecpg.so  
[root@localhost postgresql-9.3.5]# vi /etc/profile  
export PATH=/opt/pgsql/bin:$PATH  
[root@localhost postgresql-9.3.5]# . /etc/profile  
[root@localhost postgresql-9.3.5]# which psql  
/opt/pgsql/bin/psql  
[root@localhost postgresql-9.3.5]# which pg_config  
/opt/pgsql/bin/pg_config  

再安装一个外部插件, 提醒各位在使用pg_upgrade升级时, 也需要在新的版本中编译进去(请使用相同的版本).

如果外部插件不支持PostgreSQL 9.4的话, 那么请在9.3的数据库中先卸载对应的插件(包括里面创建的类型, 函数等有依赖的一切).

我这里以pldebug为例

http://git.postgresql.org/gitweb/?p=pldebugger.git;a=summary  
[root@localhost soft_bak]# tar -zxvf pldebugger-85d7b3b.tar.gz  
[root@localhost soft_bak]# mv pldebugger-85d7b3b postgresql-9.3.5/contrib/  
[root@localhost soft_bak]# cd postgresql-9.3.5/contrib/pldebugger-85d7b3b/  
[root@localhost pldebugger-85d7b3b]# which pg_config  
/opt/pgsql/bin/pg_config  
[root@localhost pldebugger-85d7b3b]# gmake clean  
[root@localhost pldebugger-85d7b3b]# gmake  
[root@localhost pldebugger-85d7b3b]# gmake install  

初始化数据库

[root@localhost pldebugger-85d7b3b]# useradd postgres  
# su - postgres  
$ vi .bash_profile  
export PS1="$USER@`/bin/hostname -s`-> "  
export PGPORT=1921  
export PGDATA=/pgdata01/pg_root  
export LANG=en_US.utf8  
export PGHOME=/opt/pgsql  
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 PGUSER=postgres  
export PGHOST=$PGDATA  
export PGDATABASE=postgres  
alias rm='rm -i'  
alias ll='ls -lh'  
$ . ~/.bash_profile  

修改权限

[root@localhost pldebugger-85d7b3b]# chown -R postgres:postgres /pgdata0*/*  
[root@localhost pldebugger-85d7b3b]# chmod -R 700 /pgdata0*/*  

初始化数据库

postgres@localhost-> initdb -D $PGDATA -U postgres -E UTF8 --locale=C -W -X /pgdata02/pg_xlog  

修改配置文件, 开启归档

vi pg_hba.conf  
host all all 0.0.0.0/0 md5  
  
vi postgresql.conf  
listen_addresses = '0.0.0.0'            # what IP address(es) to listen on;  
port = 1921                             # (change requires restart)  
max_connections = 100                   # (change requires restart)  
superuser_reserved_connections = 3      # (change requires restart)  
unix_socket_directories = '.'   # comma-separated list of directories  
unix_socket_permissions = 0700          # begin with 0 to use octal notation  
tcp_keepalives_idle = 60                # TCP_KEEPIDLE, in seconds;  
tcp_keepalives_interval = 10            # TCP_KEEPINTVL, in seconds;  
tcp_keepalives_count = 10               # TCP_KEEPCNT;  
shared_buffers = 512MB                  # min 128kB  
maintenance_work_mem = 512MB            # min 1MB  
vacuum_cost_delay = 10                  # 0-100 milliseconds  
vacuum_cost_limit = 10000               # 1-10000 credits  
bgwriter_delay = 10ms                   # 10-10000ms between rounds  
wal_level = hot_standby                 # minimal, archive, or hot_standby  
synchronous_commit = off                # synchronization level;  
wal_buffers = 16384kB                   # min 32kB, -1 sets based on shared_buffers  
wal_writer_delay = 10ms         # 1-10000 milliseconds  
checkpoint_segments = 32                # in logfile segments, min 1, 16MB each  
archive_mode = on               # allows archiving to be done  
archive_command = 'DIR="/pgdata03/pg_arch/`date +%F`";test -d $DIR || mkdir -p $DIR; cp %p $DIR/%f'               # command to use to archive a logfile segment  
archive_timeout = 600           # force a logfile segment switch after this  
effective_cache_size = 4096MB  
log_destination = 'csvlog'              # Valid values are combinations of  
logging_collector = on          # Enable capturing of stderr and csvlog  
log_directory = 'pg_log'                # directory where log files are written,  
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,  
log_file_mode = 0600                    # creation mode for log files,  
log_truncate_on_rotation = on           # If on, an existing log file with the  
log_checkpoints = on  
log_connections = on  
log_disconnections = on  
log_error_verbosity = verbose           # terse, default, or verbose messages  
log_lock_waits = on                     # log lock waits >= deadlock_timeout  
log_statement = 'ddl'                   # none, ddl, mod, all  
log_timezone = 'PRC'  
autovacuum = on                 # Enable autovacuum subprocess?  'on'  
log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and  
datestyle = 'iso, mdy'  
timezone = 'PRC'  
lc_messages = 'C'                       # locale for system error message  
lc_monetary = 'C'                       # locale for monetary formatting  
lc_numeric = 'C'                        # locale for number formatting  
lc_time = 'C'                           # locale for time formatting  
default_text_search_config = 'pg_catalog.english'  

启动数据库

postgres@localhost-> pg_ctl start  

创建测试用户

postgres=# create role digoal login encrypted password 'digoal';  
CREATE ROLE  

创建表空间, 数据库

postgres=# create tablespace tbs1 location '/pgdata04/tbs1';  
CREATE TABLESPACE  
postgres=# create tablespace tbs2 location '/pgdata05/tbs2';  
CREATE TABLESPACE  
postgres=# create database digoal template template0 encoding 'UTF8' tablespace tbs1;  
CREATE DATABASE  
postgres=# grant all on database digoal to digoal;  
GRANT  
postgres=# grant all on tablespace tbs1 to digoal;  
GRANT  
postgres=# grant all on tablespace tbs2 to digoal;  
GRANT  
postgres=# \c digoal digoal  
You are now connected to database "digoal" as user "digoal".  
digoal=> create schema digoal;  
CREATE SCHEMA  

创建extension, 用于后面模拟9.3升级到9.4的扩展模块.

postgres=# \c digoal postgres  
You are now connected to database "digoal" as user "postgres".  
digoal=# create extension pldbgapi;  
CREATE EXTENSION  

该扩展会创建一些复合类型和函数

digoal=# \dT  
        List of data types  
 Schema |    Name    | Description   
--------+------------+-------------  
 public | breakpoint |   
 public | frame      |   
 public | proxyinfo  |   
 public | targetinfo |   
 public | var        |   
(5 rows)  
  
digoal=# \df  
                                                          List of functions  
 Schema |            Name             | Result data type |                       Argument data types                        |  Type   
   
--------+-----------------------------+------------------+------------------------------------------------------------------+-------  
 public | pldbg_abort_target          | SETOF boolean    | session integer                                                  | normal  
 public | pldbg_attach_to_port        | integer          | portnumber integer                                               | normal  
 public | pldbg_continue              | breakpoint       | session integer                                                  | normal  
 public | pldbg_create_listener       | integer          |                                                                  | normal  
 public | pldbg_deposit_value         | boolean          | session integer, varname text, linenumber integer, value text    | normal  
 public | pldbg_drop_breakpoint       | boolean          | session integer, func oid, linenumber integer                    | normal  
 public | pldbg_get_breakpoints       | SETOF breakpoint | session integer                                                  | normal  
 public | pldbg_get_proxy_info        | proxyinfo        |                                                                  | normal  
 public | pldbg_get_source            | text             | session integer, func oid                                        | normal  
 public | pldbg_get_stack             | SETOF frame      | session integer                                                  | normal  
 public | pldbg_get_target_info       | targetinfo       | signature text, targettype "char"                                | normal  
 public | pldbg_get_variables         | SETOF var        | session integer                                                  | normal  
 public | pldbg_oid_debug             | integer          | functionoid oid                                                  | normal  
 public | pldbg_select_frame          | breakpoint       | session integer, frame integer                                   | normal  
 public | pldbg_set_breakpoint        | boolean          | session integer, func oid, linenumber integer                    | normal  
 public | pldbg_set_global_breakpoint | boolean          | session integer, func oid, linenumber integer, targetpid integer | normal  
 public | pldbg_step_into             | breakpoint       | session integer                                                  | normal  
 public | pldbg_step_over             | breakpoint       | session integer                                                  | normal  
 public | pldbg_wait_for_breakpoint   | breakpoint       | session integer                                                  | normal  
 public | pldbg_wait_for_target       | integer          | session integer                                                  | normal  
 public | plpgsql_oid_debug           | integer          | functionoid oid                                                  | normal  
(21 rows)  
  
digoal=# \d breakpoint  
Composite type "public.breakpoint"  
   Column   |  Type   | Modifiers   
------------+---------+-----------  
 func       | oid     |   
 linenumber | integer |   
 targetname | text    |   

创建测试数据表, 函数, 创建在tbs1和tbs2.

digoal=# \c digoal digoal  
You are now connected to database "digoal" as user "digoal".  
digoal=> create table userinfo (id int primary key, info text, crt_time timestamp);  
CREATE TABLE  
digoal=> \d userinfo  
              Table "digoal.userinfo"  
  Column  |            Type             | Modifiers   
----------+-----------------------------+-----------  
 id       | integer                     | not null  
 info     | text                        |   
 crt_time | timestamp without time zone |   
Indexes:  
    "userinfo_pkey" PRIMARY KEY, btree (id)  
  
digoal=> alter index userinfo_pkey set tablespace tbs2;  
ALTER INDEX  
  
digoal=> create or replace function f_digoal(i_id int) returns void as $$  
declare  
begin  
  update userinfo set info=$_$Hello,I'm digoal.$_$||md5(random()::text), crt_time=now() where id=i_id;  
  if not found then  
    insert into userinfo(id,info,crt_time) values(i_id, $_$Hello,I'm digoal.$_$||md5(random()::text), now());  
  end if;   
  return;  
exception when others then  
  return;  
end;  
$$ language plpgsql strict volatile;  
CREATE FUNCTION  
digoal=> select f_digoal(1);  
 f_digoal   
----------  
   
(1 row)  
  
digoal=> select * from userinfo ;  
 id |                       info                        |          crt_time            
----+---------------------------------------------------+----------------------------  
  1 | Hello,I'm digoal.607acd6f0bfe3c48eecde00f1b98ad85 | 2014-12-19 18:48:03.398352  
(1 row)  
digoal=> select f_digoal(1);  
 f_digoal   
----------  
   
(1 row)  
  
digoal=> select * from userinfo ;  
 id |                       info                        |          crt_time            
----+---------------------------------------------------+----------------------------  
  1 | Hello,I'm digoal.debe361485303d3bac72ea3d9a95aa42 | 2014-12-19 18:48:47.255641  
(1 row)  

生成测试数据

digoal=> insert into userinfo select generate_series(2,10000000),'test',clock_timestamp();  
INSERT 0 9999999  

安装PostgreSQL 9.4, 注意编译参数一致性, 以及内部和外部扩展模块(内部模块gmake world gmake install-world会全部安装).

[root@localhost soft_bak]# wget https://ftp.postgresql.org/pub/source/v9.4.0/postgresql-9.4.0.tar.bz2  
[root@localhost soft_bak]# tar -jxvf postgresql-9.4.0.tar.bz2  
[root@localhost soft_bak]# cd postgresql-9.4.0  
[root@localhost postgresql-9.4.0]# ./configure --prefix=/opt/pgsql9.4.0 --with-pgport=1921 --with-perl --with-tcl --with-python --with-openssl --with-pam --without-ldap --with-libxml --with-libxslt --enable-thread-safety --with-blocksize=32 --with-wal-blocksize=32 && gmake world && gmake install-world  

检查安装包含upgrade和upgrade库.

[root@localhost ~]# cd /opt/pgsql9.4.0/lib/  
[root@localhost lib]# ll|grep upgr  
-rwxr-xr-x 1 root root   14352 Dec 19 19:12 pg_upgrade_support.so  
[root@localhost lib]# ll /opt/pgsql9.4.0/bin/pg_upgrade   
-rwxr-xr-x 1 root root 116368 Dec 19 19:12 /opt/pgsql9.4.0/bin/pg_upgrade  

安装pldebug模块, 这个模块可以和9.4兼容.

[root@localhost postgresql-9.4.0]# cd ..  
[root@localhost soft_bak]# tar -zxvf pldebugger-85d7b3b.tar.gz  
[root@localhost soft_bak]# mv pldebugger-85d7b3b postgresql-9.4.0/contrib/  
[root@localhost soft_bak]# cd postgresql-9.4.0/contrib/pldebugger-85d7b3b/  
[root@localhost pldebugger-85d7b3b]# export PATH=/opt/pgsql9.4.0/bin:$PATH  
[root@localhost pldebugger-85d7b3b]# which pg_config  
/opt/pgsql9.4.0/bin/pg_config  
[root@localhost pldebugger-85d7b3b]# gmake clean  
[root@localhost pldebugger-85d7b3b]# gmake  
[root@localhost pldebugger-85d7b3b]# gmake install  

如果我们要使用硬链接$PGDATA来加快升级速度的话, 那么新的集群$PGDATA要和老集群的$PGDATA在一个文件系统下.

所以我们使用 /pgdata01/pg_root_9.4 :

[root@localhost lib]# mkdir /pgdata01/pg_root_9.4  
[root@localhost lib]# chown -R postgres:postgres /pgdata01/pg_root_9.4  
[root@localhost lib]# chmod 700 /pgdata01/pg_root_9.4  

初始化XLOG目录和arch目录(如果使用了定制的pg_log, 则还需初始化pg_log目录, 本例使用的是$PGDATA/pg_log, 所以无需创建pg_log)

[root@localhost lib]# mkdir /pgdata02/pg_xlog_9.4  
[root@localhost lib]# chown -R postgres:postgres /pgdata02/pg_xlog_9.4  
[root@localhost lib]# chmod 700 /pgdata02/pg_xlog_9.4  
[root@localhost lib]# mkdir /pgdata03/pg_arch_9.4  
[root@localhost lib]# chown -R postgres:postgres /pgdata03/pg_arch_9.4  
[root@localhost lib]# chmod 700 /pgdata03/pg_arch_9.4  

初始化9.4数据库, 注意除xlog,pgdata以为其他初始化参数和9.3一致(超级用户名也要一致) :

[root@localhost lib]# su - postgres  
Last login: Fri Dec 19 19:23:00 CST 2014 on pts/3  
postgres@localhost-> /opt/pgsql9.4.0/bin/initdb -D /pgdata01/pg_root_9.4 -X /pgdata02/pg_xlog_9.4 -E UTF8 --locale=C -U postgres -W  

配置9.4集群

将pg_hba.conf改为和老实例的9.3一致.

另外, 因为升级需要多次连接新老集群数据库实例, 所以修改为使用本地trust认证.

postgres@localhost-> vi /pgdata01/pg_root/pg_hba.conf  
postgres@localhost-> vi /pgdata01/pg_root_9.4/pg_hba.conf  

包含以下即可

# "local" is for Unix domain socket connections only  
local   all             all                                     trust  
# IPv4 local connections:  
host    all             all             127.0.0.1/32            trust  

修改9.4实例的postgresql.conf, 注意使用不同的监听端口. (PostgreSQL 9.4新增了很多功能和参数, 本例一并提供了 )

listen_addresses = '0.0.0.0'            # what IP address(es) to listen on;  
port = 1922                             # (change requires restart)  
max_connections = 100                   # (change requires restart)  
unix_socket_directories = '.'   # comma-separated list of directories  
unix_socket_permissions = 0700          # begin with 0 to use octal notation  
tcp_keepalives_idle = 60                # TCP_KEEPIDLE, in seconds;  
tcp_keepalives_interval = 10            # TCP_KEEPINTVL, in seconds;  
tcp_keepalives_count = 10               # TCP_KEEPCNT;  
shared_buffers = 512MB                  # min 128kB  
huge_pages = try                        # on, off, or try  
maintenance_work_mem = 512MB            # min 1MB  
autovacuum_work_mem = -1                # min 1MB, or -1 to use maintenance_work_mem  
dynamic_shared_memory_type = posix      # the default is the first option  
vacuum_cost_delay = 10                  # 0-100 milliseconds  
vacuum_cost_limit = 10000               # 1-10000 credits  
bgwriter_delay = 10ms                   # 10-10000ms between rounds  
wal_level = logical                     # minimal, archive, hot_standby, or logical  
synchronous_commit = off                # synchronization level;  
wal_buffers = 16384kB                   # min 32kB, -1 sets based on shared_buffers  
wal_writer_delay = 10ms         # 1-10000 milliseconds  
checkpoint_segments = 32                # in logfile segments, min 1, 16MB each  
archive_mode = on               # allows archiving to be done  
archive_command = 'DIR="/pgdata03/pg_arch_9.4/`date +%F`";test -d $DIR || mkdir -p $DIR; cp %p $DIR/%f'         # command to use to archive a logfile segment  
archive_timeout = 600           # force a logfile segment switch after this  
log_destination = 'csvlog'              # Valid values are combinations of  
logging_collector = on          # Enable capturing of stderr and csvlog  
log_directory = 'pg_log'                # directory where log files are written,  
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,  
log_file_mode = 0600                    # creation mode for log files,  
log_truncate_on_rotation = on           # If on, an existing log file with the  
log_checkpoints = on  
log_connections = on  
log_disconnections = on  
log_error_verbosity = verbose           # terse, default, or verbose messages  
log_lock_waits = on                     # log lock waits >= deadlock_timeout  
log_statement = 'ddl'                   # none, ddl, mod, all  
log_timezone = 'PRC'  
autovacuum = on                 # Enable autovacuum subprocess?  'on'  
log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and  
datestyle = 'iso, mdy'  
timezone = 'PRC'  
lc_messages = 'C'                       # locale for system error message  
lc_monetary = 'C'                       # locale for monetary formatting  
lc_numeric = 'C'                        # locale for number formatting  
lc_time = 'C'                           # locale for time formatting  
default_text_search_config = 'pg_catalog.english'  

停库

postgres@localhost-> /opt/pgsql9.3.5/bin/pg_ctl stop -m fast -D /pgdata01/pg_root  
postgres@localhost-> /opt/pgsql9.4.0/bin/pg_ctl stop -m fast -D /pgdata01/pg_root_9.4  

创建9.3数据库的文件系统快照

[root@localhost ~]# df -h  
zp1/pg_root                 30G   19M   30G   1% /pgdata01  
zp1/pg_xlog                 31G  428M   30G   2% /pgdata02  
zp1/pg_arch                 31G  636M   30G   3% /pgdata03  
zp1/tbs1                    31G  170M   30G   1% /pgdata04  
zp1/tbs2                    31G   97M   30G   1% /pgdata05  
[root@localhost ~]# zfs snapshot zp1/pg_root@pg9.3.5  
[root@localhost ~]# zfs snapshot zp1/pg_xlog@pg9.3.5  
[root@localhost ~]# zfs snapshot zp1/pg_arch@pg9.3.5  
[root@localhost ~]# zfs snapshot zp1/tbs1@pg9.3.5  
[root@localhost ~]# zfs snapshot zp1/tbs2@pg9.3.5  
[root@localhost ~]# zfs list -t snapshot  
NAME                  USED  AVAIL  REFER  MOUNTPOINT  
zp1/pg_arch@pg9.3.5      0      -   635M  -  
zp1/pg_root@pg9.3.5      0      -  18.4M  -  
zp1/pg_xlog@pg9.3.5      0      -   428M  -  
zp1/tbs1@pg9.3.5         0      -   169M  -  
zp1/tbs2@pg9.3.5         0      -  96.2M  -  

使用9.4的pg_upgrade检测兼容性

su - postgres  
postgres@localhost-> cd  
postgres@localhost-> mkdir upgrade_log  
postgres@localhost-> cd upgrade_log/  
postgres@localhost-> /opt/pgsql9.4.0/bin/pg_upgrade -b /opt/pgsql9.3.5/bin -B /opt/pgsql9.4.0/bin -d /pgdata01/pg_root -D /pgdata01/pg_root_9.4 -p 1921 -P 1922 -U postgres -j 8 -k -c  
Performing Consistency Checks  
-----------------------------  
Checking cluster versions                                   ok  
Checking database user is a superuser                       ok  
Checking for prepared transactions                          ok  
Checking for reg* system OID user data types                ok  
Checking for contrib/isn with bigint-passing mismatch       ok  
Checking for invalid "line" user columns                    ok  
Checking for presence of required libraries                 ok  
Checking database user is a superuser                       ok  
Checking for prepared transactions                          ok  
  
*Clusters are compatible*  

验证兼容性正常, 可以正式升级了.

postgres@localhost-> /opt/pgsql9.4.0/bin/pg_upgrade -b /opt/pgsql9.3.5/bin -B /opt/pgsql9.4.0/bin -d /pgdata01/pg_root -D /pgdata01/pg_root_9.4 -p 1921 -P 1922 -U postgres -j 8 -k -r -v  

最后输出如下 :

Upgrade Complete  
----------------  
Optimizer statistics are not transferred by pg_upgrade so,  
once you start the new server, consider running:  
    analyze_new_cluster.sh  
  
Running this script will delete the old cluster's data files:  
    delete_old_cluster.sh  

给了2个脚本, 用于收集统计信息和删除老集群.

postgres@localhost-> ll  
total 20K  
-rwx------ 1 postgres postgres 785 Dec 19 19:50 analyze_new_cluster.sh  
-rwx------ 1 postgres postgres 114 Dec 19 19:50 delete_old_cluster.sh  
-rw------- 1 postgres postgres 326 Dec 19 19:51 pg_upgrade_internal.log  
-rw------- 1 postgres postgres 179 Dec 19 19:51 pg_upgrade_server.log  
-rw------- 1 postgres postgres 179 Dec 19 19:51 pg_upgrade_utility.log  

接下来要做的是启动新的数据库集群.

postgres@localhost-> /opt/pgsql9.4.0/bin/pg_ctl start -D /pgdata01/pg_root_9.4  

执行统计信息收集脚本, 因为使用pg_upgrade升级的话, 统计信息不会迁移过来. 所以需要手工统计一下.

脚本内容如下

postgres@localhost-> cat analyze_new_cluster.sh   
#!/bin/sh  
  
echo 'This script will generate minimal optimizer statistics rapidly'  
echo 'so your system is usable, and then gather statistics twice more'  
echo 'with increasing accuracy.  When it is done, your system will'  
echo 'have the default level of optimizer statistics.'  
echo  
  
echo 'If you have used ALTER TABLE to modify the statistics target for'  
echo 'any tables, you might want to remove them and restore them after'  
echo 'running this script because they will delay fast statistics generation.'  
echo  
  
echo 'If you would like default statistics as quickly as possible, cancel'  
echo 'this script and run:'  
echo '    "/opt/pgsql9.4.0/bin/vacuumdb" -U "postgres" --all --analyze-only'  
echo  
  
"/opt/pgsql9.4.0/bin/vacuumdb" -U "postgres" --all --analyze-in-stages  
echo  
  
echo 'Done'  

脚本需要我们自行提供连接参数,当然我们也可以设置环境变量,避免修改脚本($PGHOST $PGDATABASE $PGPASSWORD $PGUSER $PGPORT等).

postgres@localhost-> "/opt/pgsql9.4.0/bin/vacuumdb" -U "postgres" --all --analyze-only -h /pgdata01/pg_root_9.4 -p 1922 -U postgres  
vacuumdb: vacuuming database "digoal"  
vacuumdb: vacuuming database "postgres"  
vacuumdb: vacuuming database "template1"  

升级完成.

----------------------------------------------------------------------------------------------------------------------------------------------  

查看数据

postgres@localhost-> /opt/pgsql9.4.0/bin/psql -h 127.0.0.1 -p 1922 -U digoal digoal  
psql (9.4.0)  
Type "help" for help.  
digoal=> \dt  
         List of relations  
 Schema |   Name   | Type  | Owner    
--------+----------+-------+--------  
 digoal | userinfo | table | digoal  
(1 row)  
  
digoal=> \dx  
                              List of installed extensions  
   Name   | Version |   Schema   |                     Description                        
----------+---------+------------+------------------------------------------------------  
 pldbgapi | 1.0     | public     | server-side support for debugging PL/pgSQL functions  
 plpgsql  | 1.0     | pg_catalog | PL/pgSQL procedural language  
(2 rows)  
digoal=> select count(*) from userinfo ;  
  count     
----------  
 10000000  
(1 row)  

最后, 确认升级成功后, 我们可以把老的集群删掉. 删之前也请确认清楚是否真的可以删除, 不要太相信pg_upgrade.

postgres@localhost-> cat delete_old_cluster.sh   
#!/bin/sh  
  
rm -rf /pgdata01/pg_root  
rm -rf /pgdata04/tbs1/PG_9.3_201306121  
rm -rf /pgdata05/tbs2/PG_9.3_201306121  

因为我们用了硬链接, 检查一下就可以删除了, 表空间, $PGDATA都使用了硬链接.

postgres@localhost-> stat PG_9.3_201306121  
  File: ‘PG_9.3_201306121’  
  Size: 3               Blocks: 27         IO Block: 131072 directory  
Device: 26h/38d Inode: 8           Links: 3  
Access: (0700/drwx------)  Uid: ( 1001/postgres)   Gid: ( 1001/postgres)  
Access: 2014-12-19 19:24:39.096630736 +0800  
Modify: 2014-12-19 19:24:47.718612433 +0800  
Change: 2014-12-19 19:24:47.718612433 +0800  
 Birth: -  
postgres@localhost-> du -sh *  
170M    PG_9.3_201306121  
3.0M    PG_9.4_201409291  

删除后, 文件统计信息正确

postgres@localhost-> du -sh *  
170M    PG_9.4_201409291  

如果要玩回退的话, 以下调整先不要做.

确认要完全使用9.4以后, 我们还需要调整一下/etc/profile, ~/.bash_profile, 方便我们的使用.

rm -f /opt/pgsql  
ln -s /opt/pgsql9.4.0 /opt/pgsql  
  
vi /etc/profile  
export PATH=/opt/pgsql/bin:$PATH  
  
vi /home/postgres/.bash_profile  
export PGPORT=1921  
export PGDATA=/pgdata01/pg_root_9.4  
  
--------------------------------------------------------------------------------------------------------------------------------------------------------------  

最后做一下ZFS回退测试 :

回退也很简单, 简单的描述一下 :

[root@localhost ~]# zfs clone -o mountpoint=/old_pgdata01 zp1/pg_root@pg9.3.5 zp1/old_pgdata01  
[root@localhost ~]# zfs clone -o mountpoint=/old_pgdata02 zp1/pg_xlog@pg9.3.5 zp1/old_pgdata02  
[root@localhost ~]# zfs clone -o mountpoint=/old_pgdata03 zp1/pg_arch@pg9.3.5 zp1/old_pgdata03  
[root@localhost ~]# zfs clone -o mountpoint=/old_pgdata04 zp1/tbs1@pg9.3.5 zp1/old_pgdata04  
[root@localhost ~]# zfs clone -o mountpoint=/old_pgdata05 zp1/tbs2@pg9.3.5 zp1/old_pgdata05  
df -h  
zp1/old_pgdata01            30G   19M   30G   1% /old_pgdata01  
zp1/old_pgdata02            31G  428M   30G   2% /old_pgdata02  
zp1/old_pgdata03            31G  636M   30G   3% /old_pgdata03  
zp1/old_pgdata04            31G  170M   30G   1% /old_pgdata04  
zp1/old_pgdata05            30G   97M   30G   1% /old_pgdata05  

调整pg_xlog,以及 表空间链接

[root@localhost ~]# su - postgres  
postgres@localhost-> cd /old_pgdata01  
postgres@localhost-> cd pg_root  
postgres@localhost-> ll  
total 225K  
lrwxrwxrwx 1 postgres postgres   17 Dec 19 19:23 pg_xlog -> /pgdata02/pg_xlog  
postgres@localhost-> rm -f pg_xlog  
postgres@localhost-> ln -s /old_pgdata02/pg_xlog ./  
postgres@localhost-> cd pg_tblspc/  
postgres@localhost-> ll  
total 1.0K  
lrwxrwxrwx 1 postgres postgres 14 Dec 19 19:24 16385 -> /pgdata04/tbs1  
lrwxrwxrwx 1 postgres postgres 14 Dec 19 19:24 16386 -> /pgdata05/tbs2  
postgres@localhost-> rm -f *  
postgres@localhost-> ln -s /old_pgdata04/tbs1 ./16385  
postgres@localhost-> ln -s /old_pgdata05/tbs2 ./16386  

修改参数(新老版本不冲突),

archive_command = 'DIR="/old_pgdata03/pg_arch/`date +%F`";test -d $DIR || mkdir -p $DIR; cp %p $DIR/%f'  
port = 1922|1921  

启动old数据库

postgres@localhost-> /opt/pgsql9.3.5/bin/pg_ctl start -D /old_pgdata01/pg_root  
server starting  

链接到old数据库测试正常.

postgres@localhost-> /opt/pgsql9.3.5/bin/psql -h 127.0.0.1 -p 1921 -U digoal digoal  
psql (9.3.5)  
Type "help" for help.  
  
digoal=> select count(*) from userinfo ;  
  count     
----------  
 10000000  
(1 row)  

参考

1. http://www.postgresql.org/docs/9.4/static/pgupgrade.html

2. 《PostgreSQL pg_upgrade 9.3 improve and example》

3. http://download.fedoraproject.org/pub/epel

4. http://zfsonlinux.org/epel.html

5. pg_upgrade –help

Usage:  
  pg_upgrade [OPTION]...  
  
Options:  
  -b, --old-bindir=BINDIR       old cluster executable directory  
  -B, --new-bindir=BINDIR       new cluster executable directory  
  -c, --check                   check clusters only, don't change any data  
  -d, --old-datadir=DATADIR     old cluster data directory  
  -D, --new-datadir=DATADIR     new cluster data directory  
  -j, --jobs                    number of simultaneous processes or threads to use  
  -k, --link                    link instead of copying files to new cluster  
  -o, --old-options=OPTIONS     old cluster options to pass to the server  
  -O, --new-options=OPTIONS     new cluster options to pass to the server  
  -p, --old-port=PORT           old cluster port number (default 50432)  
  -P, --new-port=PORT           new cluster port number (default 50432)  
  -r, --retain                  retain SQL and log files after success  
  -U, --username=NAME           cluster superuser (default "postgres")  
  -v, --verbose                 enable verbose internal logging  
  -V, --version                 display version information, then exit  
  -?, --help                    show this help, then exit  
  
Before running pg_upgrade you must:  
  create a new database cluster (using the new version of initdb)  
  shutdown the postmaster servicing the old cluster  
  shutdown the postmaster servicing the new cluster  
  
When you run pg_upgrade, you must provide the following information:  
  the data directory for the old cluster  (-d DATADIR)  
  the data directory for the new cluster  (-D DATADIR)  
  the "bin" directory for the old version (-b BINDIR)  
  the "bin" directory for the new version (-B BINDIR)  
  
For example:  
  pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin  
or  
  $ export PGDATAOLD=oldCluster/data  
  $ export PGDATANEW=newCluster/data  
  $ export PGBINOLD=oldCluster/bin  
  $ export PGBINNEW=newCluster/bin  
  $ pg_upgrade  

其他大版本升级思路

不管是小版本还是大版本升级,最重要的是减少业务停机时间,降低升级风险。

1、pg_upgrade + zfs, 支持从PostgreSQL 8.3+升级到任何更高版本

https://github.com/digoal/blog/blob/master/201412/20141219_01.md

2、逻辑复制的方式,工具 - 支持从PostgreSQL 9.4+升级到任何更高版本

https://github.com/aliyun/rds_dbsync

https://www.2ndquadrant.com/en/resources/pglogical/

3、采用FDW+ETL的方式, 支持升级到PostgreSQL 9.0+版本

https://github.com/digoal/blog/blob/master/201710/20171027_01.md

https://github.com/digoal/blog/blob/master/201710/20171027_02.md

4、采用数据库订阅功能-逻辑复制, 支持从PostgreSQL 10+升级到更高版本

https://github.com/digoal/blog/blob/master/201704/20170413_01.md

https://github.com/digoal/blog/blob/master/201702/20170227_01.md

https://github.com/digoal/blog/blob/master/201712/20171204_04.md

https://github.com/digoal/blog/blob/master/201706/20170624_01.md

Flag Counter

digoal’s 大量PostgreSQL文章入口