Postgres replication part 1 (of potentially 1)
As is often the case when dealing with servers, there are outdated versions. The reason is almost always the same: there wasn't enough time to keep things up to date.
It makes sense — sticking to the LTS of anything is hard work. You have a working system, and even if it's a fairly uncomplicated beast, updating dependencies to a new version is rarely simple. It might seem like everything is fine, but then on a Saturday at 01:30, things start breaking down because that once- in-a-blue-moon event without a unit test executes — and it depends on that one deprecated functionality nobody really needed.
In this case, it was Postgres. Postgres 9.6, to be exact. It's been quite a while since it was supported. The reason makes sense: 10 came around, nothing new was needed, everything worked as it should, and other new features had higher priority. Then 11, 12, and 13 came out, and an upgrade was no longer simple because there are extensions and upgrading might break everything. Also, the storage has changed, so who knows if PostGIS will make all the data go bad.
But then, at some point, there's an update that makes everything faster, and the load gets really, really bad. So, what do you do?
You can actually start replication from 9.6 into 17 without any problems. The problem is that when you want to read the data, it'll tell you there's a mismatch of PG versions. It makes complete sense, but it'd also be nice if PG just said something along the lines of: "Hey, you're about to read X TB of data from a legacy system. I can do that, but once it's done, I can't do anything with the data." Instead, it'll tell you after you've synced X TB of data that there's a version incompatibility — and sorry, but it can't start.
In PG's defense, they're not claiming it'll work, and it's not really expected. But when you're tasked with delivering a PG 17 version of PG 9.6 data, you might not have the time to read all the documentation. Instead, you'll discover it after having wasted time setting up replication, copying over the data, and then trying to start things. So, not really a spoiler — but just don't do it. The answer is: it won't work. You can't use built-in replication between major versions.
Setting up basic replication
Let's rewind a bit. How does replication work, and what needs to be set up? It's actually seemingly simple to configure replication in PG. First, on your primary server, you do the following:
# max replication clients allowed https://postgresqlco.nf/doc/en/param/max_replication_slots/
max_replication_slots = 10
# Maximum number of simultaneously running WAL sender processes https://postgresqlco.nf/doc/en/param/max_wal_senders/
max_wal_senders = 10
# in the hba configuration
host replication replicator 1.2.3.4/24 md5There you have it — those two in the configuration file, and a user with replication permissions in your hba-file, will make the server ready for replication. Then you simply create a replication slot from the (10 in this case) available slots by issuing select * from pg_create_physical_replication_slot('my_replication_test');. Still, everything is safe. Once you run the following, it's not:
until pg_basebackup --pgdata=/var/lib/postgresql/data -R --slot='my_replication_test' -h localhost -p 5435 -U user -X stream -P
do
echo "Waiting for primary to connect..."
sleep 1
doneWhat's done so far?
We told the primary server in the configuration that we allow up to 10 replication slots, and we also allow up to 10 simultaneously running replication clients. Then we created a slot called my_replication_test, which uses one of the 10 allowed slots. By running pg_basebackup on the replica and telling it to use the slot my_replication_test, we'll start the replication, and PG will keep track of where we're at.
There are more options available — they differ a bit between versions, but the ones here are the basic ones. You can read more in the Postgres docs.
Are we doing dangerous stuff?
Yes! Creating the slot and setting the configuration is safe, but once you run pg_basebackup, you tell your primary server that replication is happening and a client is currently at position X out of Y available. If your day is over, it's a Friday, and you have other things to do, DO NOT LEAVE THINGS AS IS! Because replication in PG is centralized. The primary server takes care of the replicas and sees that you read the first 100MB, your test works, and you're happy. But during the weekend, as there are changes, your primary server will keep a WAL (Write-Ahead Log) for your test. It might actually grow by 64 MB every 5 minutes.
As the article mentions, there's max_slot_wal_keep_size, available from version 13. That will save you from this insanity.
But basically, if you're using an older PG version and one of your replicas dies, your primary database will eventually run out of disk space. It might take some time, but unless you delete that slot, it will happen.
I don't know the rationale behind that. To me, it seems pretty insane and not something that should exist in a stable version. Replicas shouldn't be able to kill the primary server. They might die, get out of sync, but they shouldn't affect the state of the primary. Ever. I don't really know the rationale, but it seems