In PostgreSQL you configure the size of the wal (write ahead log) segments when you compile from source.
If you use an installer or if you use the packages provided by your OS distribution the size of the wal segments is usually 16MB. Although 16MB seems very low
you don’t need to worry about that in most of the cases, it just works fine.
However there are cases where you might want to adjust this, e.g. when you have an application that generates thousands of transactions in a very short time
and therefore forces PostgreSQL to generate huge amounts of wal segments.
In this post we’ll look at a specific case: Usually you want to archive the wal segments for being able to do point in time recovery in case your severs crashes for some reason.
Does the size of the wal segments matter for archiving?
Archiving of wal segments in PostgreSQL is done by specifying an archive_command. Whatever you put there will be executed by PostgreSQL once a new wal segment is completed.
Usually you’ll find something like this in archive_command (from the documentation):
|
1
2
|
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unixarchive_command = 'copy "%p" "C:\server\archivedir\%f"' # Windows |
Or something like this:
|
1
|
archive_command = 'rsync -a %p postgres@[SOME_OTHER_HOST]:/path/to/wal_archive/%f' |
Or:
|
1
|
archive_command ='scp %p postgres@[SOME_OTHER_HOST]:/path/to/wal_archive/%f' |
Lets test how the size of wal segments impact the three ways of archiving outlined above. To begin with lets create 100 files each 16MB (the same as the default wal segment size in PostgreSQL) and 25 files 64MB each:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
rm -rf /var/tmp/test16mbmkdir /var/tmp/test16mbfor i in {1..100}; do dd if=/dev/zero of=/var/tmp/test16mb/${i} bs=1M count=16donels -la /var/tmp/test16mbrm -rf /var/tmp/test64mbmkdir /var/tmp/test64mbfor i in {1..25}; do dd if=/dev/zero of=/var/tmp/test64mb/${i} bs=1M count=64donels -la /var/tmp/test64mbdu -sh /var/tmp/test16mbdu -sh /var/tmp/test64mb |
This will give us a total size of 1.6GB for each of the wal sizes (16MB and 64MB). Lets start by testing the “cp” way:
|
1
2
3
4
5
6
|
echo 3 > /proc/sys/vm/drop_cachesmkdir -p /var/tmp/targetrm -rf /var/tmp/target/*time for i in `ls /var/tmp/test16mb`; do cp /var/tmp/test16mb/${i} /var/tmp/target/done |
My result (on a VM local on my notebook):
|
1
2
3
|
real 0m17.444suser 0m0.275ssys 0m8.569s |
The same test for the 64MB files:
|
1
2
3
4
5
6
|
echo 3 > /proc/sys/vm/drop_cachesmkdir -p /var/tmp/targetrm -rf /var/tmp/target/*time for i in `ls /var/tmp/test64mb`; do cp /var/tmp/test16mb/${i} /var/tmp/target/done |
It is almost 3 times as fast to copy the large files than to copy the smaller files:
|
1
2
3
|
real 0m5.365suser 0m0.065ssys 0m1.835s |
Of course, for production systems, you would copy the files not locally but rather to e.g. NFS mount and then the numbers will change.
What are the numbers for scp? For the smaller files:
|
1
2
3
4
5
6
|
echo 3 > /proc/sys/vm/drop_cachesmkdir -p /var/tmp/targetrm -rf /var/tmp/target/*time for i in `ls /var/tmp/test16mb`; do scp /var/tmp/test16mb/${i} root@localhost:/var/tmp/target/done |
The result:
|
1
2
3
|
real 2m51.708suser 0m14.136ssys 0m35.292s |
Quite a huge overhead. What is the result with the 64MB files?:
|
1
2
3
4
5
6
|
echo 3 > /proc/sys/vm/drop_cachesmkdir -p /var/tmp/targetrm -rf /var/tmp/target/*time for i in `ls /var/tmp/test64mb`; do scp /var/tmp/test64mb/${i} root@localhost:/var/tmp/target/done |
Approximately double as fast:
|
1
2
3
|
real 1m23.326suser 0m10.353ssys 0m30.814s |
And finally rsync, for the smaller files:
|
1
2
3
4
5
6
|
echo 3 > /proc/sys/vm/drop_cachesmkdir -p /var/tmp/targetrm -rf /var/tmp/target/*time for i in `ls /var/tmp/test16mb`; do rsync -a /var/tmp/test16mb/${i} root@localhost:/var/tmp/target/${i}done |
The result:
|
1
2
3
|
real 0m51.624suser 0m4.488ssys 0m10.247s |
For the larger ones:
|
1
2
3
4
5
6
|
echo 3 > /proc/sys/vm/drop_cachesmkdir -p /var/tmp/targetrm -rf /var/tmp/target/*time for i in `ls /var/tmp/test64mb`; do rsync -a /var/tmp/test64mb/${i} root@localhost:/var/tmp/target/${i}done |
The result:
|
1
2
3
|
real 0m34.342suser 0m3.623ssys 0m9.685s
|