We updated two database servers this weekend, one from postgresql 9.1 and the other from 9.2 and brought both of them to 9.3. What follows are my combined process notes in the hopes that it will help you.
To do this, you must have enough free disk space on your data drive to make a duplicate of the existing cluster (that is, all databases hosted on the server). So for example, our data drive on one server had 55% usage and I had to clear it to 50% (the drive is dedicated to database storage). On the other server it was 66% consumed. In both cases I removed files that were unrelated to the cluster (backups and WAL archives) and moved them off-server. In the case of the second server this wasn’t enough. If you can easily install or mount a new drive, that’s much easier than these steps but we didn’t have that luxury.
You can free up disk space by re-indexing the databases, running
vacuum full, or dump and restore. Re-index can be done without taking the database offline. The other two require taking down the database and may take hours or days for a multi-gigabyte cluster. Restoring the database from backup file took 18 hours on a 250GB database (13GB gzipped,
pg_dump backup file) and 39 hours for our 450GB cluster (25GB backup file). From everything I’ve read, for databases in the hundreds of gigabytes and larger,
vacuum full will basically take forever. It’s faster to dump and rebuild the database.
However, you can recover a significant amount of space by re-indexing. We recovered 100GB of our 600GB cluster by running re-index on each database. Note that this took 3 hours for one 260GB database and 4.5 hours for a different 250GB database. The major difference of the two was the latter had older data — so the indexing was more fragmented.
sudo su - postgres -c 'psql app-database-production'
REINDEX DATABASE "app-database-production";
We’re using Scientific Linux. The PostgreSQL Global Development Group has made a repository of builds available for binary distributions. You install the repository by installing the RPM for the repository (this was weirdly meta for me but it works). This creates a
pgdg93 repository. See the repository packages page for more links.
sudo rpm -ivh http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-redhat93-9.3-1.noarch.rpm
You can then install the new PostgreSQL 9.3 releases:
sudo yum install postgresql93 postgresql93-devel postgresql93-libs postgresql93-server postgresql93-contrib
postgresql93-contrib is only needed for the
pg_upgrade tool we’re going to use. You can remove it after the upgrade if you want.
Make a database folder
Create the new database data folder as
postgres user. The Scientific Linux distro puts postgresql into
/usr/pgsql-VERSION. The default data file location is
/var/lib/pgsql/VERSION/data, although ours is mounted on a separate drive.
sudo su postgres -c '/usr/pgsql-9.3/bin/initdb -D /var/lib/pgsql/9.3/data'
Disable database access
Stop all connections to the database and disable your web application. This next phase can take several hours so you’ll want to make sure you have time. Our 845GB cluster took a little over 2 hours of server downtime.
In our case, closing connections meant stopping
resque workers that we have managed by
monit, and disabling the web applications with
capistrano maintenance mode. We also stop monitoring the database
postmaster process to ensure that
monit doesn’t restart it while we’re doing the upgrade. Obviously these are meant to jog your thoughts, your own infrastructure will look different.
worker-server$ sudo monit -g resque-workers stop
database-server$ sudo monit unmonitor postmaster
database-server$ sudo /etc/init.d/postgresql-9.1 stop
dev$ cap production deploy:web:disable REASON="a scheduled system upgrade" UNTIL="at 11pm Pacific Time"
Run the upgrade
Run the new
pg_upgrade to migrate from the old version (-b,-d) to the new version (-B,-D). This is the part that takes a couple hours per server.
sudo su postgres -c '/usr/pgsql-9.3/bin/pg_upgrade -B /usr/pgsql-9.3/bin -b /usr/pgsql-9.2/bin -D /var/lib/pgsql/9.3/data -d /var/lib/pgsql/9.2/data'
Verify the new cluster
Manually inspect the differences between the startup scripts:
Transfer any important things to the 9.3 script and remove the 9.2 one. In our case we have a custom
Similarly compare the
postgresql.conf files in the old data directory with the new ones. The
postgresql.conf can be tedious if you’ve done a lot of tuning. (p.s. Anyone know of a good diff tool for configuration files that can compare uncommented lines in either version with their commented pairs in the other?)
diff /var/lib/pgsql/9.2/data/postgresql.conf /var/lib/pgsql/9.3/data/postgresql.conf
diff /var/lib/pgsql/9.2/data/pg_hba.conf /var/lib/pgsql/9.3/data/pg_hba.conf
Start the new postgresql and analyze the new cluster to optimize your database for the new version. (Note that
analyze_cluster.sh is installed into the working directory when
pg_upgrade is run.) The analyze script has three phases. The minimal one will get the database up and running in a couple minutes. So you can bring things back online at this point or wait until it’s fully complete.
sudo /etc/init.d/postgresql-9.3 start
sudo su postgres -c ./analyze_cluster.sh
Bring things back online
If you’re running
god or something) to manage your postgresql server, you’ll need to modify the script with new references.
Now, bring everything back up online that you disabled earlier.
database-server$ sudo monit reload
worker-server$ sudo monit start all
dev$ cap production deploy:web:enable
Test that things are working with everything up and running.
If you’re satisfied with the new system, you can delete the old cluster. This script is installed in the working directory that you ran
sudo su postgres -c ./delete_old_cluster.sh
If you’d rather be a little more careful (after all it only copied the database files over) you can delete the old
data/base folder, which is the bulk of the storage, and keep other configuration files around in case you need to recover them.
1. How to install PostgreSQL 9.2 on RHEL/CentOS/Scientific Linux 5 and 6
4. How to optimize PostgreSQL database size