古いバージョンのPostgreSQL(PG)を使用している企業や企業は、少なくともPostgreSQL12またはPostgreSQL13から最新の安定バージョンにアップグレードするときに課題に直面します。最新バージョンにアップグレードする理由はたくさんあります。しなければならない。これの主な理由のいくつかは、組み込み機能の重要な拡張機能、セキュリティ更新、パフォーマンスの改善、およびデータベース管理に有益な新しい実装を利用することです。
PostgreSQLのアップグレードには、他の主流のデータベースに比べて簡単ではないため、いくつかの課題があります。この種の問題に直面している場合でも、心配する必要はありません。 PostgreSQLは、使用する特定のバージョンに縛られることはありません。このブログでは、TimescaleDBとPostGISを既存のPostgreSQL11ホストにインストールしながらこの課題の例を紹介します。
なぜpg_upgradeなのか?
pg_upgradeは、PostgreSQLのメジャーバージョンをアップグレードするためのツールとして非常に長い間使用されてきました。マイナーバージョンのアップグレードでは、このツールを使用する必要はありません。つまり、現在のバージョンの11.9から11.13にアップグレードする必要はありません。
pg_upgradeを使用してPostgreSQLをメジャーバージョンにアップグレードする場合、ツールは、PostgreSQLデータファイルに保存されているデータを新しいPostgreSQLメジャーバージョンにアップグレードできるようにすることで機能します。これは、データのダンプ/リロードを必要とせずに機能します。大きなデータセットがある場合は、時間がかかることがあります。
さて、ここで大騒ぎが起こります。特にメジャーバージョンリリースのPostgreSQLには、システムテーブルのレイアウトを変更することが多い新機能が追加されていることが知られていますが、内部データストレージ形式が変更されることはめったにありません。 pg_upgradeはこの事実を利用して、新しいシステムテーブルを作成し、古いユーザーデータファイルを再利用するだけで、迅速なアップグレードを実行します。将来のメジャーリリースで、古いデータ形式が読み取れなくなるような方法でデータストレージ形式が変更された場合、pg_upgradeはそのようなアップグレードには使用できなくなります。 (コミュニティはそのような状況を回避しようとします。)
pg_upgradeは、特に本番環境では危険であると考える人もいます。このツールは、QAから開発、本番環境に至るまで、他の場所で広く使用されています。データセットに保存されている既知のUnicodeや文字セットなど、制限や注意事項があります。その場合、pg_dump / pg_restoreの使用を検討することもできますが、データの大きさによっては、完了するまでに時間がかかる場合があります。 PG 14.0などの新しいバージョンのPostgreSQLの場合、ダンプ/復元(またはエクスポート/インポート)または論理レプリケーションのみを実行できます。それ以外の場合は、pg_upgradeを使用します。
大規模なデータセットの場合、pg_upgradeを使用するには、同じホストでこれを実行する必要があります。デフォルトでは、データディレクトリからすべての物理ファイルのコピーが適用されます。その場合、pg_upgradeは-kまたは--linkオプションをサポートします。これは、ファイルを新しいクラスターにコピーする代わりにハードリンクを使用することを意味します。
pg_upgradeは、たとえば32/64ビットバイナリを含む互換性のあるコンパイル時設定をチェックすることにより、新旧のクラスターがバイナリ互換であることを確認するために最善を尽くします。 pg_upgradeで確認することはできませんが、外部モジュールがバイナリ互換であることも重要です。
pg_upgradeは、8.4.X以降から、スナップショットやベータリリースを含むPostgreSQLの現在のメジャーリリースへのアップグレードをサポートしています。
このセットアップでは、ClusterControlを使用して単一ノード用のPostgreSQL11データベースクラスターをデプロイしました。以下は、Centos7およびUbuntuFocal(20.04.1)でテストされています。
$ /usr/pgsql-11/bin/postgres --version
postgres (PostgreSQL) 11.13
postgres=# \dx
List of installed extensions
Name | Version | Schema | Description
------------------------+---------+------------+-------------------------------------------------------------------
fuzzystrmatch | 1.1 | public | determine similarities and distance between strings
pg_stat_statements | 1.6 | public | track execution statistics of all SQL statements executed
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
postgis | 3.1.4 | public | PostGIS geometry and geography spatial types and functions
postgis_raster | 3.1.4 | public | PostGIS raster types and functions
postgis_sfcgal | 3.1.4 | public | PostGIS SFCGAL functions
postgis_tiger_geocoder | 3.1.4 | tiger | PostGIS tiger geocoder and reverse geocoder
postgis_topology | 3.1.4 | topology | PostGIS topology spatial types and functions
timescaledb | 2.3.1 | public | Enables scalable inserts and complex queries for time-series data
(9 rows)
PostgreSQLサーバーのバージョン: 11.13
TimescaleDBバージョン: 2.3.1
PostGISバージョン: 3.1.4
ClusterControlでこれをテストする場合、TimescaleDBを使用するには2つの方法があります。 TimescaleDBクラスターをデプロイするか、PostgreSQLを使用してTimescaleDBプラグインを有効にすることができます。
PostgreSQL13のセットアップ
PostgreSQLおよびTimescaleDBリポジトリでLinux環境用のパッケージマネージャーセットアップを使用する方が簡単です。そのための手順は次のとおりです。
まず、PostgreSQLリポジトリを追加しましょう。
CentOS / RHEL /OracleLinuxの場合
sudo yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
他のアーキテクチャについては、https://download.postgresql.org/pub/repos/yum/reporpms/をベースにして、EL-7-x86_64サブディレクトリを置き換えることができます。
TimescaleDBリポジトリも追加しましょう。
vi /etc/yum.repos.d/timescale_timescaledb.repo
次に、このファイルに次の内容を追加します
[timescale_timescaledb]
name=timescale_timescaledb
baseurl=https://packagecloud.io/timescale/timescaledb/el/7/\$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/timescale/timescaledb/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
EL 7以外のバージョンを使用している場合は、それに応じてbaseurlを置き換えてください。
Ubuntu/Debianの場合
Ubuntu FocalのPGリポジトリを追加します:
deb http://apt.postgresql.org/pub/repos/apt/ focal-pgdg main
それでは、TimescaleDBのリポジトリを追加しましょう
sudo sh -c "echo 'deb [signed-by=/usr/share/keyrings/timescale.keyring] https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main' > /etc/apt/sources.list.d/timescaledb.list"
wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/timescale.keyring
アップグレードが必要なパッケージ、およびリポジトリに到着したばかりの新しいパッケージのアップグレードのパッケージリストを更新します。
sudo apt-get update
ubuntuのDebianを使用している場合は、URLのサブディレクトリを置き換えることができます。
リポジトリの準備ができたので、準備は完了です。
TimescaleDBとPostGISを使用してPostgreSQLバージョン13をインストールします
PostgreSQL13のインストールは同じホストで実行できます。まず、データベースポートなどが一意であることを確認する必要があります。つまり、同じホストにインストールされている現在のPostgreSQL11とは異なる必要があります。
CentOS / RHEL /OracleLinuxの場合
以下のコマンドを実行して、PostgreSQL13とその依存パッケージをインストールします。
yum install postgresql13.x86_64 postgresql13-server.x86_64 postgresql13-contrib.x86_64 postgresql13-libs.x86_64
次に、以下のコマンドを実行して、データベースクラスターとそれに必要なデータベースのコレクションを初期化します。
$ /usr/pgsql-13/bin/postgresql-13-setup initdb
この時点で、PG11とPG13の両方に2つのデータディレクトリが必要です。
[[email protected] ~]# ls -alth /var/lib/pgsql/* -d
drwx------. 4 postgres postgres 51 Sep 22 14:19 /var/lib/pgsql/13
drwx------. 4 postgres postgres 33 Sep 21 18:53 /var/lib/pgsql/11
PostgreSQL 13がうまくいったので、TimescaleDBをインストールしましょう。インストールするプラグインがPostreSQL11と同じバージョンであることを確認する必要があります。
pg_upgradeがスムーズに機能するようにするには、ソースとメジャーバージョンの宛先のプラグインが同じバージョンである必要があることに注意してください。これは、pg_upgradeが、古いバージョンまたはソースデータベースバージョンのPostgreSQLによってロードまたは使用されたプラグインまたは拡張機能にリンクされた指定ライブラリを検索するためです。これは、showduplicatesを実行するか、dnfまたはyumのいずれかを使用して、以下のような情報で確認することにより、EnterpriseLinuxで確認できます。
$ yum --showduplicates list timescaledb_13.x86_64 timescaledb-2-postgresql-13.x86_64 timescaledb-2-oss-postgresql-13.x86_64 timescaledb-2-loader-postgresql-13.x86_64|grep '2.3.1'
Repository pgdg-common is listed more than once in the configuration
timescaledb-2-loader-postgresql-13.x86_64 2.3.1-0.el7 timescale_timescaledb
timescaledb-2-oss-postgresql-13.x86_64 2.3.1-0.el7 timescale_timescaledb
timescaledb-2-postgresql-13.x86_64 2.3.1-0.el7 timescale_timescaledb
または、infoオプションで確認します:
$ yum info timescaledb-2-loader-postgresql-13-2.3.1-0.el7.x86_64 timescaledb-2-postgresql-13-2.3.1-0.el7.x86_64
これで、PG13バージョンのTimescaleDBパッケージをインストールする準備が整いました。
$ yum install timescaledb-2-loader-postgresql-13-2.3.1-0.el7.x86_64 timescaledb-2-postgresql-13-2.3.1-0.el7.x86_64
インストール後、timescaledb-tuneツールを実行してpostgresql.conf構成ファイルを調整してみてください。以下のコマンドを実行するだけです:
$ timescaledb-tune --pg-config=/usr/pgsql-13/bin/pg_config
それでは、PG13バージョンのPostGISパッケージもインストールしましょう。
$ yum install -y postgis31_13.x86_64
Ubuntu/Debianの場合
実行するだけです:
$ apt install postgresql-client-13 postgresql-13
Ubuntu / Debianディストリビューションの優れている点は、pg_lsclusters、pg_ctlclusterなどのPostgreSQLクラスターの管理に非常に便利なPostgreSQL用のツールがあることです。
$ pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
11 main 5432 online postgres /var/lib/postgresql/11/main log/postgresql-%Y-%m-%d_%H%M%S.log
13 main 5433 online postgres /var/lib/postgresql/13/main /var/log/postgresql/postgresql-13-main.log
Ubuntu / Debianでは、ポートはインストールフェーズで処理され、それに応じて一意に検出および設定されるため、ポートを変更する必要はありません。
では、TimescaleDBをインストールしましょう。
$ apt install timescaledb-2-loader-postgresql-13 timescaledb-2-postgresql-13
オプションで、timescaledb-tuneツールを実行して、次のようにツールを呼び出すだけで、postgresql.conf構成ファイルを調整できます。
$ timescaledb-tune
これで、PG13用のPostGISパッケージをインストールする準備が整いました。
$ apt install postgresql-13-postgis-3-scripts postgresql-13-postgis-3
postgresql.confを確認してください
postgresql.conf構成ファイルを確認することをお勧めします。 Enterprise Linuxバージョンでは、postgresql.confはdata_directoryまたはPGDATAパスのいずれかにあります。 Ubuntu / Debianの場合は、/ etc / postgresql /
shared_preload_libraries = 'pg_stat_statements,timescaledb' # pg_stat_statements is not required but if you are using ClusterControl, make sure this is appended.
port = 5532 # make sure that the port number is unique than the old version of your PostgreSQL
listen_address = * # depends on your setup but if you need to specify the available network interfaces to its IP addresses (IPv4 or IPv6) set it accordingly.
PostgreSQL構成ファイルの古いバージョンと新しいバージョンを比較して、postgresql.confが必要な設定と同じであることを確認することをお勧めします。
次のステップに進む前に、PostgreSQLバージョン13が適切にロードされていることも確認する必要があります。ホストに最新バージョンを取得またはインストールしていることを確認してください。データベースを起動し、データベースが正しく起動して実行されることを確認します。
ELディストリビューションを開始するには、次のコマンドを実行します。
$ sudo -iu postgres /usr/pgsql-13/bin/pg_ctl -D /var/lib/pgsql/13/data/ -o "-c config_file=/var/lib/pgsql/13/data/postgresql.conf" start
$ sudo -iu postgres /usr/lib/postgresql/13/bin/pg_ctl -D /var/lib/postgresql/13/main/ -o "-c config_file=/etc/postgresql/13/main/postgresql.conf" start
または、pg_ctlclusterツールを使用して、PGクラスターを開始、再起動、または停止します。
準備ができたら、pg_upgradeを実行します…
次に進む前に、まず、古いサーバーからのバックアップが常に用意されていて、利用可能であることを確認してください。メジャーアップグレードを続行する前に、常に論理バックアップと物理バックアップをグッドプラクティスとして使用してください。
準備ができたので、pg_upgradeを実行します。実際には、pg_upgradeのメイン手順に進む前に、最初にpg_upgradeを実行して、非互換性と問題を判別する必要があります。 pg_upgradeを実行する前に、このプロセスの実行中にPG11とPG13の両方がダウンしていることを確認してください。これは、このプロセスにダウンタイムが必要であることを意味します。
これを行うには、-checkオプションを指定して次のコマンドを実行します。
$ sudo -iu postgres /usr/lib/postgresql/13/bin/pg_upgrade -o "-c config_file=/etc/postgresql/11/main/postgresql.conf" --old-datadir=/var/lib/postgresql/11/main/ -O "-c config_file=/etc/postgresql/13/main/postgresql.conf" --new-datadir=/var/lib/postgresql/13/main/ --old-bindir=/usr/lib/postgresql/11/bin --new-bindir=/usr/lib/postgresql/13/bin --check
設定と異なる場合は、それに応じて--old-datadir値またはconfig_fileを置き換えます。
これにより、以下の結果のように互換性チェックが実行されます。
Performing Consistency Checks
-----------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for system-defined composite types in user tables ok
Checking for reg* data types in user tables ok
Checking for contrib/isn with bigint-passing mismatch ok
Checking for tables WITH OIDS ok
Checking for invalid "sql_identifier" user columns ok
Checking for presence of required libraries ok
Checking database user is the install user ok
Checking for prepared transactions ok
Checking for new cluster tablespace directories ok
*Clusters are compatible*
すべてのチェックが「ok」を示し、チェックが成功したことを意味し、下部のメッセージがクラスターに互換性があることを示している場合は、問題ありません。
最後に、-checkオプションを指定せずにコマンドを再実行します。
$ sudo -iu postgres /usr/lib/postgresql/13/bin/pg_upgrade -o "-c config_file=/etc/postgresql/11/main/postgresql.conf" --old-datadir=/var/lib/postgresql/11/main/ -O "-c config_file=/etc/postgresql/13/main/postgresql.conf" --new-datadir=/var/lib/postgresql/13/main/ --old-bindir=/usr/lib/postgresql/11/bin --new-bindir=/usr/lib/postgresql/13/bin
Performing Consistency Checks
-----------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for system-defined composite types in user tables ok
Checking for reg* data types in user tables ok
Checking for contrib/isn with bigint-passing mismatch ok
Checking for tables WITH OIDS ok
Checking for invalid "sql_identifier" user columns ok
Creating dump of global objects ok
Creating dump of database schemas ok
Checking for presence of required libraries ok
Checking database user is the install user ok
Checking for prepared transactions ok
Checking for new cluster tablespace directories ok
If pg_upgrade fails after this point, you must re-initdb the
new cluster before continuing.
Performing Upgrade
------------------
Analyzing all rows in the new cluster ok
Freezing all rows in the new cluster ok
Deleting files from new pg_xact ok
Copying old pg_xact to new server ok
Setting oldest XID for new cluster ok
Setting next transaction ID and epoch for new cluster ok
Deleting files from new pg_multixact/offsets ok
Copying old pg_multixact/offsets to new server ok
Deleting files from new pg_multixact/members ok
Copying old pg_multixact/members to new server ok
Setting next multixact ID and offset for new cluster ok
Resetting WAL archives ok
Setting frozenxid and minmxid counters in new cluster ok
Restoring global objects in the new cluster ok
Restoring database schemas in the new cluste ok
Copying user relation files ok
Setting next OID for new cluster ok
Sync data directory to disk ok
Creating script to analyze new cluster ok
Creating script to delete old cluster ok
Checking for extension updates notice
Your installation contains extensions that should be updated
with the ALTER EXTENSION command. The file
update_extensions.sql
when executed by psql by the database superuser will update
these extensions.
Upgrade Complete
----------------
Optimizer statistics are not transferred by pg_upgrade so,
once you start the new server, consider running:
./analyze_new_cluster.sh
Running this script will delete the old cluster's data files:
./delete_old_cluster.sh
データセットのサイズによっては、少し時間がかかる場合があります。上記のコマンド例では、物理ファイルであるトランザクションログをコピーします。ただし、ディスクサイズが狭い場合は、ハードリンクを使用する-kまたは--linkオプションを使用できます。すべてがうまくいけば、完全なアップグレードを通知する上記のようなメッセージと、使用している可能性のある拡張機能を更新するための通知が表示されます。この設定では、スムーズに進みます。 update_extensions.sqlには、次のもののみが含まれています。
$ cat update_extensions.sql
\connect postgres
ALTER EXTENSION "pg_stat_statements" UPDATE;
お気づきのとおり、pg_upgradeは一連のアクションを実行します。ソースクラスターのすべての行を分析し、トランザクションメタデータログとそのマルチトランザクションステータスデータおよびその他をコピーします。
すべてが良好に見えることがわかったら、analyze_new_cluster.shスクリプトを実行します。このスクリプトが実行されます
vacuumdb --all --analyze-only.
$ sudo -iu postgres PGPORT=5433 ./analyze_new_cluster.sh
PostgreSQL 13のポートを指定して、vacuumdbが適切なターゲットサーバーで正しく実行されるようにする必要があることに注意してください。
この場合、TimescaleDBとPostGIS拡張機能を有効にしたアップグレードの結果はうまくいきます。すべてが順番に表示されたら、必ずサーバーを起動し、一連のテストとチェックを実行してください。
$ sudo -iu postgres psql -p5433
psql (13.4 (Ubuntu 13.4-1.pgdg20.04+1))
Type "help" for help.
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+---------+---------+-----------------------
mydb | postgres | UTF8 | C.UTF-8 | C.UTF-8 |
postgres | postgres | UTF8 | C.UTF-8 | C.UTF-8 |
template0 | postgres | UTF8 | C.UTF-8 | C.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | C.UTF-8 | C.UTF-8 | postgres=CTc/postgres+
| | | | | =c/postgres
(4 rows)
postgres=# \c mydb
You are now connected to database "mydb" as user "postgres".
mydb=# set search_path="$user",public;
SET
mydb=# \dt+
List of relations
Schema | Name | Type | Owner | Persistence | Size | Description
--------+-----------------+-------+----------+-------------+------------+-------------
public | conditions | table | postgres | permanent | 8192 bytes |
public | global_points | table | postgres | permanent | 16 kB |
public | roads | table | postgres | permanent | 16 kB |
public | sample_table | table | postgres | permanent | 8192 bytes |
public | spatial_ref_sys | table | postgres | permanent | 6968 kB |
(5 rows)
私のPostGISとハイパーテーブルのいくつかをチェックしています:
mydb=# \d roads
Table "public.roads"
Column | Type | Collation | Nullable | Default
------------+----------------------+-----------+----------+---------
road_id | integer | | |
road_name | character varying | | |
roads_geom | geometry(LineString) | | |
mydb=# \d sample_table
Table "public.sample_table"
Column | Type | Collation | Nullable | Default
--------+--------------------------+-----------+----------+------------------------------------------
id | integer | | not null | nextval('sample_table_id_seq'::regclass)
time | timestamp with time zone | | not null |
name | character varying | | not null |
Indexes:
"sample_table_pkey" PRIMARY KEY, btree (id, "time")
"sample_table_time_idx" btree ("time" DESC)
Triggers:
ts_insert_blocker BEFORE INSERT ON sample_table FOR EACH ROW EXECUTE FUNCTION _timescaledb_internal.insert_blocker()
Number of child tables: 371 (Use \d+ to list them.)
mydb=# \d conditions
Table "public.conditions"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+---------
time | timestamp with time zone | | not null |
location | text | | not null |
location2 | character(10) | | not null |
temperature | double precision | | |
humidity | double precision | | |
Indexes:
"conditions_time_idx" btree ("time" DESC)
Triggers:
ts_insert_blocker BEFORE INSERT ON conditions FOR EACH ROW EXECUTE FUNCTION _timescaledb_internal.insert_blocker()
Number of child tables: 366 (Use \d+ to list them.)
mydb=# select count(*) from sample_table;
count
-------
2588
(1 row)
mydb=# SELECT name FROM global_points WHERE ST_DWithin(location, 'SRID=4326;POINT(-110 29)'::geography, 1000000);
name
--------
Town
Forest
(2 rows)
mydb=# SELECT n, ST_AsEWKT(ST_GeometryN(the_geom, n)) As geomewkt
mydb-# FROM (
mydb(# VALUES (ST_GeomFromEWKT('MULTIPOINT(1 2 7, 3 4 7, 5 6 7, 8 9 10)') ),
mydb(# ( ST_GeomFromEWKT('MULTICURVE(CIRCULARSTRING(2.5 2.5,4.5 2.5, 3.5 3.5), (10 11, 12 11))') )
mydb(# )As foo(the_geom)
mydb-# CROSS JOIN generate_series(1,100) n
mydb-# WHERE n <= ST_NumGeometries(the_geom);
n | geomewkt
---+-----------------------------------------
1 | POINT(1 2 7)
1 | CIRCULARSTRING(2.5 2.5,4.5 2.5,3.5 3.5)
2 | POINT(3 4 7)
2 | LINESTRING(10 11,12 11)
3 | POINT(5 6 7)
4 | POINT(8 9 10)
(6 rows)
これで、すべてが新しいクラスターとして機能する準備ができたように見えます。
準備が整ったら、次のコマンドを実行できます:
$ sudo -iu postgres ./delete_old_cluster.sh
これは非常に危険なスクリプトであるため、スクリプトのみを実行するようにしてください。古いPostgreSQLクラスター内のすべてのファイルが削除されます。
pg_upgradeは、PostgreSQLデータベースサーバーを管理およびアップグレードするための優れたツールです。 TimescaleDBやPostGIS拡張機能を有効にするなどの複雑なセットアップを処理できます。このツールには制限がありますが、特にDBA作業や、QAおよび開発環境以外の本番サーバーでの使用を止めることはできません。