Upgrading operating systems for PostgreSQL
If you upgrade the operating system on which PostgreSQL runs,
an upgrade of locale data changes in glibc
2.28 might corrupt your database indexes.
To avoid this issue, migrate using either:
For more information about how GitLab plans to address this issue, see epic 8573.
Backup and restore
Use pg_dump
or the GitLab backup tool, with all data types except db
excluded
(so only the database is backed up).
The restore recreates the entire database, including the indexes.
Advantages:
- Simpler and more straightforward than replication.
- Removes any database bloat in indexes and tables, reducing disk use.
Disadvantages:
- Downtime is likely to be longer and particularly problematic for large databases.
Replication and failover
Set up streaming replication from the old database server to the new server.
As part of the plan to switch to the new server, reindex all affected indexes:
- In a database console, run
REINDEX INDEX <index name> CONCURRENTLY
on each index.
This approach was used for GitLab.com. To learn more about this process and how the different types of indexes were handled, see the blog post about upgrading the operating system on our Postgres database clusters.
After reindexing bad indexes, the collation must be refreshed.
To update the system catalog to record the current collation version,
run the query ALTER COLLATION <collation_name> REFRESH VERSION
.
Advantages:
- Downtime is shorter: the time to perform the necessary reindexing, plus validation.
- Likely to be faster if database is large.
Disadvantages:
- Technically complicated: setting up replication and ensuring all necessary reindexing is completed.
- Preserves database bloat.
Checking glibc
versions
To see what version of glibc
is used, run ldd --version
.
You can compare the behavior of glibc
on your servers using shell commands.
The following table shows the glibc
versions shipped for different operating systems:
Operating system |
glibc version
|
---|---|
CentOS 7 | 2.17 |
RedHat Enterprise 8 | 2.28 |
RedHat Enterprise 9 | 2.34 |
Ubuntu 18.04 | 2.27 |
Ubuntu 20.04 | 2.31 |
Ubuntu 22.04 | 2.35 |
Ubuntu 24.04 | 2.39 |
For example, suppose you are upgrading from CentOS 7 to RedHat
Enterprise 8. In this case, using PostgreSQL on this upgraded operating
system requires using one of the two mentioned approaches, because glibc
is upgraded from 2.17 to 2.28. Failing to handle the collation changes
properly causes significant failures in GitLab, such as runners not
picking jobs with tags.
On the other hand, if PostgreSQL has already been running on glibc
2.28
or higher with no issues, your indexes should continue to work without
further action. For example, if you have been running PostgreSQL on
RedHat Enterprise 8 (glibc
2.28) for a while, and want to upgrade
to RedHat Enterprise 9 (glibc
2.34), there should be no collations-related issues.
Verifying glibc
collation versions
For PostgreSQL 13 and higher, you can verify that your database collation version matches your system with this SQL query:
SELECT collname AS COLLATION_NAME,
collversion AS VERSION,
pg_collation_actual_version(oid) AS actual_version
FROM pg_collation
WHERE collprovider = 'c';
Matching collation example
For example, on a Ubuntu 22.04 system, the output of a properly indexed system looks like:
gitlabhq_production=# SELECT collname AS COLLATION_NAME,
collversion AS VERSION,
pg_collation_actual_version(oid) AS actual_version
FROM pg_collation
WHERE collprovider = 'c';
collation_name | version | actual_version
----------------+---------+----------------
C | |
POSIX | |
ucs_basic | |
C.utf8 | |
en_US.utf8 | 2.35 | 2.35
en_US | 2.35 | 2.35
(6 rows)
Mismatched collation example
On the other hand, if you’ve upgraded from Ubuntu 18.04 to 22.04 without reindexing, you might see:
gitlabhq_production=# SELECT collname AS COLLATION_NAME,
collversion AS VERSION,
pg_collation_actual_version(oid) AS actual_version
FROM pg_collation
WHERE collprovider = 'c';
collation_name | version | actual_version
----------------+---------+----------------
C | |
POSIX | |
ucs_basic | |
C.utf8 | |
en_US.utf8 | 2.27 | 2.35
en_US | 2.27 | 2.35
(6 rows)