PostgreSQL 9.4 in RAM HOWTO
15 Nov 2015
First, we need a RAM disk we can use. Happily, on Ubuntu,
the /run dir is a tmpfs mount, so let's use that!
$ su -
# mkdir -p /run/pgsql-9.4.5-data
# chown -R postgres:postgres /run/pgsql-9.4.5-data
# chmod 700 /run/pgsql-9.4.5-data
# su - postgres
$ /usr/local/pgsql-9.4.5/bin/initdb \
    --pgdata=/run/pgsql-9.4.5-data \
    --encoding=UTF8 \
    --no-locale
Normally, we would edit postgresql.conf to tune our PostgreSQL instance to run optimally with our compter's resources. However, all data in /run/pgsql-9.4.5-data will be lost on the next reboot. So instead, let's specify all the settings at the command-line.
Here are the settings that we want to look at modifying from their defaults:
First, turn off fsync; it makes no sense on a ramdisk:
#fsync = on ==> fsync = off
Consider turning all of these memory settings down to their minimums, seeing as our whole dataset is already cached in RAM anyway:
shared_buffers = 128MB ==> shared_buffers = 128kB #temp_buffers = 8MB ==> temp_buffers = 800kB #work_mem = 4MB ==> work_mem = 64kB #maintenance_work_mem = 64MB ==> maintenance_work_mem = 1024kB
You should't be using WAL anyway (use unlogged tables) but try tuning this down to the minimum, too, except for checkpoint_segments, which may as well be as high as possible in case you accidentally use WAL:
#wal_buffers = -1 ==> wal_buffers = 32kB #checkpoint_segments = 3 ==> checkpoint_segments = 64
Obviously, random_page_cost is exactly the same as seq_page_cost in RAM, but additionally, they are the same as cpu_tuple_cost:
#seq_page_cost = 1.0 ==> seq_page_cost = 0.01 #random_page_cost = 4.0 ==> random_page_cost = 0.01
Try tuning down effective_cache_size, seeing as you should encourage direct reads from ramdisk:
#effective_cache_size = 4GB ==> effective_cache_size = 64kB
So here's what our command line looks like to start up postgres:
/usr/local/pgsql-9.4.5/bin/postgres \
    -D /run/pgsql-9.4.5-data \
    --fsync=off \
    --shared-buffers=128kB \
    --temp-buffers=800kB \
    --work-mem=64kB \
    --maintenance-work-mem=1024kB \
    --wal-buffers=32kB \
    --checkpoint-segments=64 \
    --seq-page-cost=0.01 \
    --random-page-cost=0.01 \
    --effective-cache-size=64kB
Seeing as this is essentially a temporary database, we may as well use the built-in postgres database and postgres user instead of going through the bother of creating a different user and database.
We need to load our schema, so we can do that now.
# gvim /usr/local/pgsql-9.4.5/bin/ramdb.sql
-- Note that this might be run multiple times on the same
-- database, so make it idempotent.
-- Also, use unlogged tables to bypass the WAL to increase performance
create unlogged table if not exists sessions (
    id uuid constraint session_pk primary key not null,
    data text not null);
# chmod +x /usr/local/pgsql-9.4.5/bin/ramdb.sql # chown postgres:postgres /usr/local/pgsql-9.4.5/bin/ramdb.sql
And here's how we load it in:
/usr/local/pgsql-9.4.5/bin/psql \
    -X \
    -U postgres \
    -d postgres \
    -f /usr/local/pgsql-9.4.5/bin/ramdb.sql
Now we can log in and start using our in-memory PostgreSQL:
/usr/local/pgsql-9.4.5/bin/psql \
    -U postgres \
    -d postgres
systemd script
We can take all that we have learned and turn it into a systemd script, like so:
# cd /etc/systemd/system # vi pg-ram.service
[Unit]
Description=PostgreSQL 9.4.5 in RAM
# This unit can only run after the network is up and running
# (that is, the network target has run)
After=network.target
[Service]
# PostgreSQL is a traditional UNIX daemon that forks a child,
# and the initial process exits
Type=forking
# Wait 120 seconds on startup and shutdown to consider the process
# correctly started up or shut down.
TimeoutSec=120
# The UNIX user and group to execute PostgreSQL as
User=postgres
Group=postgres
# Set the PGROOT environmental variable for PostgreSQL
Environment=PGROOT=/run/pgsql-9.4.5-data
# If StandardOutput= or StandardError= are set to syslog, journal or kmsg,
# prefix log lines with "postgres"
SyslogIdentifier=postgres
# Let systemd know where PostgreSQL keeps its pid file
PIDFile=/run/pgsql-9.4.5-data/postmaster.pid
# IMPORTANT! Run ExecStartPre with root-permissions
# so that the mkdir command on /run will succeed
# (won't succeed as user postgres)
PermissionsStartOnly=true
# Set up everything before PostgreSQL starts
ExecStartPre= /bin/mkdir -p /run/pgsql-9.4.5-data
ExecStartPre= /bin/chown -R postgres:postgres /run/pgsql-9.4.5-data
ExecStartPre= /bin/chmod 700 /run/pgsql-9.4.5-data
# Important: the leading minus sign means ignore errors; in this case,
# initdb may have already been run on a previous start, and will error
# out trying to re-create a database cluster dir that already exists.
ExecStartPre=-/usr/bin/sudo -u postgres \
        /usr/local/pgsql-9.4.5/bin/initdb \
            --pgdata=/run/pgsql-9.4.5-data \
            --encoding=UTF8 \
            --no-locale
# After PostgreSQL starts, load the database schema
ExecStartPost= /usr/local/pgsql-9.4.5/bin/psql \
    -X \
    -U postgres \
    -d postgres \
    -f /usr/local/pgsql-9.4.5/bin/ramdb.sql
# Start PostgreSQL in RAM
ExecStart= /usr/local/pgsql-9.4.5/bin/pg_ctl \
    -s -D ${PGROOT} start -w -t 120 \
    -o "--fsync=off --shared-buffers=128kB \
    --temp-buffers=800kB --work-mem=64kB  \
    --maintenance-work-mem=1024kB --wal-buffers=32kB \
    --checkpoint-segments=64 --seq-page-cost=0.01  \
    --random-page-cost=0.01 --effective-cache-size=64kB"
# Reload PostgreSQL in RAM
ExecReload=/usr/local/pgsql-9.4.5/bin/pg_ctl -s -D ${PGROOT} reload
# Stop PostgreSQL in RAM
ExecStop=  /usr/local/pgsql-9.4.5/bin/pg_ctl -s -D ${PGROOT} stop -m fast
# Use the lowest allowable setting for the OOM killer; this should
# actually disable the OOM killer for PostgreSQL
OOMScoreAdjust=-1000
[Install]
# This unit is part of target multi-user
WantedBy=multi-user.target
Let's test:
# systemctl daemon-reload # systemctl start pg-ram # systemctl status pg-ram # systemctl stop pg-ram # systemctl status pg-ram
Yup: all good!