Amazon Aurora PostgreSQLでZabbixデータベースをパーティショニングしてみる
こんにちは。プラットフォーム技術部の佐藤(賢)です。
TimescaleDBが使えない環境でZabbixデータベースのパーティショニングをやってみましたので紹介します。
はじめに
Zabbixデータベースのパーティショニングとは
Zabbixのデータベースではデータが大量になると、古いデータを削除するハウスキーパーの処理負荷が問題になる場合があります。
この問題を対処するため、ZabbixネイティブではTimescaleDBが利用できるようになりました。
TimescaleDBはいわゆる時系列データベースです。データの時間範囲ごとにチャンクと呼ばれる領域に保存し、チャンク単位で削除を実施することで、ハウスキーパーの処理負荷を軽減できるようになっています。
実は「時系列単位にデータを保存して削除してハウスキーパー負荷軽減」という考え方自体は、TimescaleDB以前からありました。データベースの時系列パーティショニングを使うというものです。
最近ですと、MySQLネイティブの機能で時系列パーティショニングを実現する方法が以下の記事で紹介されています。
Partitioning a Zabbix MySQL(8) database with Perl or Stored Procedures – Zabbix Blog
TimescaleDBはPostgreSQLの拡張機能として実現されていますのでMySQLでは使えない、であればMySQLネイティブでパーティショニングして負荷軽減しようというものです。
またデータベースがMySQLの場合に限らず、拡張機能が提供されていないクラウドサービスなどではPostgreSQLベースの環境でも利用できない場合があります。
例えばAzure Database for PostgreSQLでは利用できますが、Amazon Aurora PostgreSQLでは利用できません。
「AWSのRDSでは使えないのか」と嘆いても仕方がありませんので、前述のMySQLパーティショニング記事のようにAmazon Aurora PostgreSQLでのZabbixデータベースパーティショニングにチャレンジしたいと思います。
MySQLでのパーティショニングでやっていること
先ほどのMySQLパーティショニング記事を紐解くと、おおざっぱに以下を実施していることがわかります。
- history系、trends系テーブルのパーティショニング設定
- パーティション管理情報を保存するためのテーブル作成(manage_partitions)
- パーティション管理用のプロシージャー作成(create_next_partitionsやdrop_partitionsなど)
- パーティション管理用プロシージャーを定期実行するイベント作成(e_part_manage)
- Zabbix Webコンソールからhistory、trendsのハウスキーパーを無効化
基本的には、これらをPostgreSQLネイティブで実現すればよいです。
PostgreSQLで実現するには
PostgreSQLネイティブの場合は、拡張機能を使うことでパーティショニングの管理を簡素化できます。
そもそもMySQL用のプロシージャーなどをPostgreSQL用に移植するのが大変ですが、それらを自前で構築する必要がありません。
利用する拡張機能は以下の2つです。Amazon Aurora PostgreSQLでも利用可能です。
拡張機能 | 提供機能 |
pg_partman | 管理用テーブル、管理用プロシージャーなどを提供します |
pg_cron | OS上cronのような定期実行環境をPostgreSQL上で提供します |
それぞれの拡張機能に関してはAWS公式ドキュメントでも紹介されていますので適宜ご参照ください。
- pg_partman エクステンションによる PostgreSQL パーティションの管理 – Amazon Relational Database Service
- PostgreSQL pg_cron エクステンションによるメンテナンスのスケジューリング – Amazon Relational Database Service
環境
今回構築する環境は以下のとおりです。
- Amazon Aurora PostgreSQL 14
- Red Hat Enterprise Linux 9
- Zabbix 6.4 beta4
Zabbixパッケージ群のインストールは完了している状態から開始します。バージョンは構築開始時(2022年12月初旬)の最新版です。またPostgreSQLデータベースは以下で構築していきます。
- マスターユーザー: postgres
- Zabbixデータベースユーザー名: zabbix
- Zabbixデータベース名: zabbix
- Zabbixデータベーススキーマ名: zabbix
スキーマは将来的にpublic利用が非推奨になっていきますので、zabbixスキーマを用意して構築します。
パーティショニング単位と保存期間は以下の通りにします。
テーブル種別 | パーティショニング単位 | 事前作成パーティション数 | 保存期間 |
history系 | 1日単位 | 7個 | 90日 |
trends系 | 1月単位 | 3個 | 2年 |
構築作業の実際
PostgreSQL拡張機能利用の準備
Auroraで使用しているDB cluster parameter groupでshared_preload_librariesとcron.database_nameを設定します。AWSデフォルト提供のパラメーターグループを使っている場合は変更できませんので、新たに作成してPostgreSQLクラスターに設定します。
shared_preload_librariesにpg_cronを追加し、pg_cron拡張でスキーマを配置するデータベース(cron.database_name)をZabbixデータベース名に変更しています。
Zabbixデータベース作成と拡張機能の有効化
マスターユーザーで実施します。PostgreSQLインスタンスのホスト名は$DBHost変数に設定しています。
$ psql -h $DBHost -U postgres
-- ロール、データベース作成
CREATE ROLE zabbix WITH LOGIN PASSWORD '********';
GRANT zabbix TO postgres;
CREATE DATABASE zabbix OWNER zabbix;
-- 接続データベース変更
\c zabbix
-- pg_partman拡張有効化
CREATE SCHEMA partman;
CREATE EXTENSION pg_partman SCHEMA partman;
GRANT ALL ON SCHEMA partman TO zabbix;
GRANT ALL ON ALL TABLES IN SCHEMA partman TO zabbix;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA partman TO zabbix;
GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA partman TO zabbix;
GRANT TEMPORARY ON DATABASE zabbix TO zabbix;
-- pg_cron拡張有効化
CREATE EXTENSION pg_cron;
GRANT USAGE ON SCHEMA cron TO zabbix;
-- zabbixスキーマ作成(public利用回避)
CREATE SCHEMA AUTHORIZATION zabbix;
Zabbixデータベースへの初期スキーマ作成とデータ投入
zabbixユーザーで実施します。スキーマはサーチパスのデフォルトが"$user, public"ですので、ユーザー名と同じ名前のスキーマを用意しておくと、そちらが優先的に使用されます。
$ zcat /usr/share/zabbix-sql-scripts/postgresql/server.sql.gz | psql -h $DBHost -U zabbix zabbix
zabbixユーザーで接続しhistory、trends系テーブルをパーティショニングで再作成します。
$ psql -h $DBHost -U zabbix zabbix
-- パーティショニング対象テーブルをいったん削除
DROP TABLE history;
DROP TABLE history_uint;
DROP TABLE history_str;
DROP TABLE history_log;
DROP TABLE history_text;
DROP TABLE trends;
DROP TABLE trends_uint;
-- パーティショニング対象テーブルを再作成
CREATE TABLE history (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
value DOUBLE PRECISION DEFAULT '0.0000' NOT NULL,
ns integer DEFAULT '0' NOT NULL,
PRIMARY KEY (itemid,clock,ns)
) PARTITION BY RANGE (clock);
CREATE TABLE history_uint (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
value numeric(20) DEFAULT '0' NOT NULL,
ns integer DEFAULT '0' NOT NULL,
PRIMARY KEY (itemid,clock,ns)
) PARTITION BY RANGE (clock);
CREATE TABLE history_str (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
value varchar(255) DEFAULT '' NOT NULL,
ns integer DEFAULT '0' NOT NULL,
PRIMARY KEY (itemid,clock,ns)
) PARTITION BY RANGE (clock);
CREATE TABLE history_log (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
timestamp integer DEFAULT '0' NOT NULL,
source varchar(64) DEFAULT '' NOT NULL,
severity integer DEFAULT '0' NOT NULL,
value text DEFAULT '' NOT NULL,
logeventid integer DEFAULT '0' NOT NULL,
ns integer DEFAULT '0' NOT NULL,
PRIMARY KEY (itemid,clock,ns)
) PARTITION BY RANGE (clock);
CREATE TABLE history_text (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
value text DEFAULT '' NOT NULL,
ns integer DEFAULT '0' NOT NULL,
PRIMARY KEY (itemid,clock,ns)
) PARTITION BY RANGE (clock);
CREATE TABLE trends (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
num integer DEFAULT '0' NOT NULL,
value_min DOUBLE PRECISION DEFAULT '0.0000' NOT NULL,
value_avg DOUBLE PRECISION DEFAULT '0.0000' NOT NULL,
value_max DOUBLE PRECISION DEFAULT '0.0000' NOT NULL,
PRIMARY KEY (itemid,clock)
) PARTITION BY RANGE (clock);
CREATE TABLE trends_uint (
itemid bigint NOT NULL,
clock integer DEFAULT '0' NOT NULL,
num integer DEFAULT '0' NOT NULL,
value_min numeric(20) DEFAULT '0' NOT NULL,
value_avg numeric(20) DEFAULT '0' NOT NULL,
value_max numeric(20) DEFAULT '0' NOT NULL,
PRIMARY KEY (itemid,clock)
) PARTITION BY RANGE (clock);
パーティション管理情報の設定
pg_partman拡張機能のcreate_parentファンクションを使うと、管理情報の登録と初期パーティションの作成がおこなえるのですが、メンテナンス処理の動作確認をおこないたいので少々細工します。
- start_partitionsにパーティションの保存期限より以前の日付を指定して保存期限前の過去パーティションを作成
- メンテナンス処理で期限切れのパーティションが削除されることを確認します
- premakeは1を指定して将来用の初期パーティションは1つのみ作成し、そのあと管理情報を本来の値に再設定
- メンテナンス処理でパーティションが追加作成されることを確認します
SELECT partman.create_parent(
p_parent_table => 'zabbix.history',
p_control => 'clock',
p_type => 'native',
p_interval => 'daily',
p_start_partition := '2022-09-01',
p_premake => 1,
p_epoch => 'seconds');
SELECT partman.create_parent(
p_parent_table => 'zabbix.history_uint',
p_control => 'clock',
p_type => 'native',
p_interval => 'daily',
p_start_partition := '2022-09-01',
p_premake => 1,
p_epoch => 'seconds');
SELECT partman.create_parent(
p_parent_table => 'zabbix.history_str',
p_control => 'clock',
p_type => 'native',
p_interval => 'daily',
p_start_partition := '2022-09-01',
p_premake => 1,
p_epoch => 'seconds');
SELECT partman.create_parent(
p_parent_table => 'zabbix.history_log',
p_control => 'clock',
p_type => 'native',
p_interval => 'daily',
p_start_partition := '2022-09-01',
p_premake => 1,
p_epoch => 'seconds');
SELECT partman.create_parent(
p_parent_table => 'zabbix.history_text',
p_control => 'clock',
p_type => 'native',
p_interval => 'daily',
p_start_partition := '2022-09-01',
p_premake => 1,
p_epoch => 'seconds');
SELECT partman.create_parent(
p_parent_table => 'zabbix.trends',
p_control => 'clock',
p_type => 'native',
p_interval => 'monthly',
p_start_partition := '2020-11-01',
p_premake => 1,
p_epoch => 'seconds');
SELECT partman.create_parent(
p_parent_table => 'zabbix.trends_uint',
p_control => 'clock',
p_type => 'native',
p_interval => 'monthly',
p_start_partition := '2020-11-01',
p_premake => 1,
p_epoch => 'seconds');
各項目の意味は以下のとおりです。
項目名 | 設定内容 | |
p_parent_table | 親テーブル名 | |
p_control | パーティションレンジを制御するカラム名 | |
p_type | native固定(古いバージョンのPostgreSQLでトリガーベースでのパーティショニングを使用したい場合はpartmanを指定) | |
p_interval | パーティションの期間 | |
p_start_partition | 開始パーティションの日時(:=日付でも可) | |
p_premake | 事前に作成するパーティション数 | |
p_epoch | p_controlのデータがtimestamp形式以外の数値の場合に数値単位としてsecondsやnanosecondsなどを指定 |
これで初期パーティションも作成されました。
こちらの作業は2022年12月9日に実施したのですが、historyはhistory_p2022_12_09を中心に将来分1個、過去分はstart_partition時点から作成されていることが確認できます。
-- historyテーブル
\d+ zabbix.history
Partitioned table "zabbix.history"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+------------------+-----------+----------+-----------------------+---------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
value | double precision | | not null | '0'::double precision | plain | | |
ns | integer | | not null | 0 | plain | | |
Partition key: RANGE (clock)
Indexes:
"history_pkey" PRIMARY KEY, btree (itemid, clock, ns)
Partitions: history_p2022_09_01 FOR VALUES FROM (1661990400) TO (1662076800),
history_p2022_09_02 FOR VALUES FROM (1662076800) TO (1662163200),
history_p2022_09_03 FOR VALUES FROM (1662163200) TO (1662249600),
:
history_p2022_12_08 FOR VALUES FROM (1670457600) TO (1670544000),
history_p2022_12_09 FOR VALUES FROM (1670544000) TO (1670630400),
history_p2022_12_10 FOR VALUES FROM (1670630400) TO (1670716800),
history_default DEFAULT
-- trendsテーブル
\d+ zabbix.trends
Partitioned table "zabbix.trends"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
-----------+------------------+-----------+----------+-----------------------+---------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
num | integer | | not null | 0 | plain | | |
value_min | double precision | | not null | '0'::double precision | plain | | |
value_avg | double precision | | not null | '0'::double precision | plain | | |
value_max | double precision | | not null | '0'::double precision | plain | | |
Partition key: RANGE (clock)
Indexes:
"trends_pkey" PRIMARY KEY, btree (itemid, clock)
Partitions: trends_p2020_11 FOR VALUES FROM (1604188800) TO (1606780800),
trends_p2020_12 FOR VALUES FROM (1606780800) TO (1609459200),
trends_p2021_01 FOR VALUES FROM (1609459200) TO (1612137600),
:
trends_p2022_11 FOR VALUES FROM (1667260800) TO (1669852800),
trends_p2022_12 FOR VALUES FROM (1669852800) TO (1672531200),
trends_p2023_01 FOR VALUES FROM (1672531200) TO (1675209600),
trends_default DEFAULT
-- 登録された管理情報表示例
SELECT * FROM partman.part_config WHERE parent_table = 'zabbix.history'\gx
-[ RECORD 1 ]--------------+--------------------------------
parent_table | zabbix.history
control | clock
partition_type | native
partition_interval | 1 day
constraint_cols |
premake | 1
optimize_trigger | 4
optimize_constraint | 30
epoch | seconds
inherit_fk | t
retention |
retention_schema |
retention_keep_table | t
retention_keep_index | t
infinite_time_partitions | f
datetime_string | YYYY_MM_DD
automatic_maintenance | on
jobmon | t
sub_partition_set_full | f
undo_in_progress | f
trigger_exception_handling | f
upsert |
trigger_return_null | t
template_table | partman.template_zabbix_history
publications |
inherit_privileges | f
constraint_valid | t
subscription_refresh |
drop_cascade_fk | f
パーティション設定の変更
パーティションの保存期限(retention値)はcreate_parent ファンクションでは設定できません。また保存期限経過後のテーブルやインデックスは削除せずにデタッチして維持する状態になっていますので(retention_keep_tableとretention_keep_indexのbool値)、SQLで管理情報を更新します。
メンテナンス処理の確認用に初期パーティション数(premake値)を1にしましたので、history系7個、trends系3個に増やします。また空のテーブルでもパーティションが作成されるようにinfinite_time_partitionsをtrueに設定します。
-- history系テーブルのパーティション設定
UPDATE partman.part_config
SET retention = '90 days',
retention_keep_table = false,
retention_keep_index = false,
premake = 7,
infinite_time_partitions = true
WHERE parent_table LIKE 'zabbix.history%';
-- trends系テーブルのパーティション設定
UPDATE partman.part_config
SET retention = '2 years',
retention_keep_table = false,
retention_keep_index = false,
premake = 3,
infinite_time_partitions = true
WHERE parent_table LIKE 'zabbix.trends%';
メンテナンススケジュール設定
pg_cron拡張機能を使ってメンテナンススケジュールを設定します。
-- パーティションのメンテナンススケジュール設定
SELECT cron.schedule('0 1 * * *', $$CALL partman.run_maintenance_proc()$$);
-- 履歴削除スケジュール設定
SELECT cron.schedule('0 2 * * *', $$DELETE
FROM cron.job_run_details
WHERE end_time < now() - interval '30 days'$$);
-- 確認
SELECT * FROM cron.job;
jobid | schedule | command | nodename | nodeport | database | username | active | jobname
-------+-----------+-------------------------------------------------+-----------+----------+----------+----------+--------+---------
1 | 0 1 * * * | CALL partman.run_maintenance_proc() | localhost | 5432 | zabbix | zabbix | t |
2 | 0 2 * * * | DELETE +| localhost | 5432 | zabbix | zabbix | t |
| | FROM cron.job_run_details +| | | | | |
| | WHERE end_time < now() - interval '30 days' | | | | | |
(2 rows)
パーティションのメンテナンス用にpartman.run_maintenance_procプロシージャの実行と、pg_cronの実行履歴削除をそれぞれ1日1回実行するようにしています。
開発環境でAurora起動時間が短い場合などは、partman.run_maintenance_procプロシージャの実行頻度を多くして「必要なパーティションがまだ作られていない」といった状態に陥らないよう注意する必要があります。
ところでパーティションレンジに該当するパーティションが存在しなかった場合はどうなるのでしょうか。データ自体はデフォルトパーティションに保存されるので失われることはありません(_default付きのパーティション)。
ただデフォルトパーティションにデータが存在すると、そちらの値が新たにアタッチしたいパーティションレンジに含まれてしまう場合、パーティションのアタッチに失敗します。
大抵の場合、新規パーティション追加に失敗し続けるため、どこかでサービスを止めてデフォルトパーティション内のデータ退避、パーティションの手動アタッチと退避データのリストアといったリカバリー作業が必要になります。
実は経過を早く確認するために15分毎という短いパーティションレンジで動作確認している最中に、partman.run_maintenance_procプロシージャがこんなログを出し続けていることに気がつき、慌ててテーブルを削除して再作成したのは内緒です(データ移行は諦めました)。
ERROR: updated partition constraint for default partition "history_text_default" would be violated by some row
CONTEXT: SQL statement "ALTER TABLE zabbix.history_text ATTACH PARTITION zabbix.history_text_p2022_12_08_1630 FOR VALUES FROM ('1670484600') TO ('1670485500')"
初回メンテナンス実行後のパーティション状態
初回メンテナンス実行後にパーティション状態を確認すると、期限切れパーティションの削除と将来用パーティション作成が正常におこなわれていることが確認できます(メンテナンス実行日は2022年12月9日です)。
historyテーブルはhistory_p2022_09_09以前が削除され、history_p2022_12_16まで作成されました。
-- historyテーブル
\d+ zabbix.history
Partitioned table "zabbix.history"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+------------------+-----------+----------+-----------------------+---------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
value | double precision | | not null | '0'::double precision | plain | | |
ns | integer | | not null | 0 | plain | | |
Partition key: RANGE (clock)
Indexes:
"history_pkey" PRIMARY KEY, btree (itemid, clock, ns)
Partitions: history_p2022_09_10 FOR VALUES FROM (1662768000) TO (1662854400),
history_p2022_09_11 FOR VALUES FROM (1662854400) TO (1662940800),
history_p2022_09_12 FOR VALUES FROM (1662940800) TO (1663027200),
:
history_p2022_12_14 FOR VALUES FROM (1670976000) TO (1671062400),
history_p2022_12_15 FOR VALUES FROM (1671062400) TO (1671148800),
history_p2022_12_16 FOR VALUES FROM (1671148800) TO (1671235200),
history_default DEFAULT
trendsテーブルはtrends_p2020_11以前が削除され、trends_p2023_03まで作成されました。
-- trendsテーブル
\d+ zabbix.trends;
Partitioned table "zabbix.trends"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
-----------+------------------+-----------+----------+-----------------------+---------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
num | integer | | not null | 0 | plain | | |
value_min | double precision | | not null | '0'::double precision | plain | | |
value_avg | double precision | | not null | '0'::double precision | plain | | |
value_max | double precision | | not null | '0'::double precision | plain | | |
Partition key: RANGE (clock)
Indexes:
"trends_pkey" PRIMARY KEY, btree (itemid, clock)
Partitions: trends_p2020_12 FOR VALUES FROM (1606780800) TO (1609459200),
trends_p2021_01 FOR VALUES FROM (1609459200) TO (1612137600),
trends_p2021_02 FOR VALUES FROM (1612137600) TO (1614556800),
:
trends_p2023_01 FOR VALUES FROM (1672531200) TO (1675209600),
trends_p2023_02 FOR VALUES FROM (1675209600) TO (1677628800),
trends_p2023_03 FOR VALUES FROM (1677628800) TO (1680307200),
trends_default DEFAULT
Zabbix設定
Webフロントエンドの設定を実施しログインします。
左メニューの[Administration]>[Housekeeping]からHistoryとTrendsのハウスキーピング処理を無効化します(Enable internal housekeepingをオフ)。
メンテナンス処理にpg_partman_bgwではなくpg_cronを使う理由
pg_partmanにはbackground worker(pg_partman_bgw)が用意されていて、そちらをロードすることでメンテナンス処理を実行できるようになっていますが、AWSでは提供されておらずpg_cronを使うようになっています。
実はpg_cronはhot standby状態(RecoveryInProgress()応答がfalse)では動作しないようになっており、Reader instanceが存在するAWSのRDSでは都合がよいです。
RecoveryInProgress()の結果はpg_is_in_recoveryでも確認できるのですが、Reader instanceではこちらがfalseですので、pg_cron処理が実行されないことがわかります。
SELECT pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
オンプレでレプリケーションクラスター構成をとる場合なども、pg_partman_bgwではなくpg_cronなどを使ってメンテナンス処理をおこなったほうがよいです。
パーティショニングの弊害
データベース機能でネイティブパーティショニングを実現する場合の弊害をZabbix視点で少しあげておきます。
アイテムの保存期間を個別に設定できない
本来ですとアイテムごとにヒストリーやトレンドの保存期限を設定できますが、パーティショニング時はテーブルごとに一律になります。アイテムのデータタイプで保存先テーブルが決まりますので、ホストやアイテム項目に関係なく、データタイプごとに一律になります。
将来のアップグレード対応が煩雑
Zabbixのバージョンアップではテーブル構成の変更などを自動で実行するようになっています。大抵SQL実行で処理されるのですが、これらはパーティショニングを考慮していません。エラーになる可能性もありますので、その場合は個別の手当てが必要になります。
ただ実際にはパーティショニングされた、おそらく大量のデータが保持されているhistoryやtrendsテーブルにそのまま自動アップグレードを施すことは現実的ではありません。ALTERでカラムの追加、削除やタイプ変更など実施したら途方もない時間がかかります。
従って現実的な移行方法としては、設定系のみ自動アップグレード後に新バージョンに合わせた再パーティショニングを施しデータ移行という段取りになります。パーティショング自体よりも、その起因となる大量のデータ移行をいかに効率よく実施するかが課題になります。
パーティショニングはZabbixサポート対象外
TimescaleDBの場合はそちらを前提とした処理コードがZabbixにも組み込まれていますので、TimescaleDB部分まで踏み込んだ調査や問題解決サポートも提供される可能性が高いです。内容次第ではありますが、少なくとも門前払いはないでしょう。
しかしながら、データベース機能を利用したパーティションニングはTimescaleDBと異なり、Zabbixの一切関与しないところで実装しているので自己解決していく必要があります。
最後に
Zabbixデータベースでのパーティショニングをご紹介しましたが、時系列パーティショニング自体は、通常のアプリケーション用途としても有用なケースが多数あると思われます。
AWS Database Blogにも時系列データを取り扱う際のpg_partman拡張の利用方法など紹介されていますので、ぜひご活用ください。
Designing high-performance time series data tables on Amazon RDS for PostgreSQL
さて、本記事の記載を始めてから約2ヵ月動かしてみましたが、パーティショニング処理は問題なく稼働しています。データが存在するhistoryやtrendsテーブルはもちろんのこと、データの存在しないhistory_logも旧パーティションの削除と将来パーティションの作成が順当におこなわれていました。この報告をもって本記事は終了いたします。
zabbix=> \d+ history;
Partitioned table "zabbix.history"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+------------------+-----------+----------+-----------------------+---------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
value | double precision | | not null | '0'::double precision | plain | | |
ns | integer | | not null | 0 | plain | | |
Partition key: RANGE (clock)
Indexes:
"history_pkey" PRIMARY KEY, btree (itemid, clock, ns)
Partitions: history_p2022_11_08 FOR VALUES FROM (1667865600) TO (1667952000),
history_p2022_11_09 FOR VALUES FROM (1667952000) TO (1668038400),
history_p2022_11_10 FOR VALUES FROM (1668038400) TO (1668124800),
:
history_p2023_02_11 FOR VALUES FROM (1676073600) TO (1676160000),
history_p2023_02_12 FOR VALUES FROM (1676160000) TO (1676246400),
history_p2023_02_13 FOR VALUES FROM (1676246400) TO (1676332800),
history_default DEFAULT
zabbix=> \d+ trends;
Partitioned table "zabbix.trends"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
-----------+------------------+-----------+----------+-----------------------+---------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
num | integer | | not null | 0 | plain | | |
value_min | double precision | | not null | '0'::double precision | plain | | |
value_avg | double precision | | not null | '0'::double precision | plain | | |
value_max | double precision | | not null | '0'::double precision | plain | | |
Partition key: RANGE (clock)
Indexes:
"trends_pkey" PRIMARY KEY, btree (itemid, clock)
Partitions: trends_p2021_02 FOR VALUES FROM (1612137600) TO (1614556800),
trends_p2021_03 FOR VALUES FROM (1614556800) TO (1617235200),
trends_p2021_04 FOR VALUES FROM (1617235200) TO (1619827200),
:
trends_p2023_03 FOR VALUES FROM (1677628800) TO (1680307200),
trends_p2023_04 FOR VALUES FROM (1680307200) TO (1682899200),
trends_p2023_05 FOR VALUES FROM (1682899200) TO (1685577600),
trends_default DEFAULT
zabbix=> select count(*) from history_log;
count
-------
0
(1 row)
zabbix=> \d+ history_log;
Partitioned table "zabbix.history_log"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
------------+-----------------------+-----------+----------+-----------------------+----------+-------------+--------------+-------------
itemid | bigint | | not null | | plain | | |
clock | integer | | not null | 0 | plain | | |
timestamp | integer | | not null | 0 | plain | | |
source | character varying(64) | | not null | ''::character varying | extended | | |
severity | integer | | not null | 0 | plain | | |
value | text | | not null | ''::text | extended | | |
logeventid | integer | | not null | 0 | plain | | |
ns | integer | | not null | 0 | plain | | |
Partition key: RANGE (clock)
Indexes:
"history_log_pkey" PRIMARY KEY, btree (itemid, clock, ns)
Partitions: history_log_p2022_11_08 FOR VALUES FROM (1667865600) TO (1667952000),
history_log_p2022_11_09 FOR VALUES FROM (1667952000) TO (1668038400),
history_log_p2022_11_10 FOR VALUES FROM (1668038400) TO (1668124800),
:
history_log_p2023_02_11 FOR VALUES FROM (1676073600) TO (1676160000),
history_log_p2023_02_12 FOR VALUES FROM (1676160000) TO (1676246400),
history_log_p2023_02_13 FOR VALUES FROM (1676246400) TO (1676332800),
history_log_default DEFAULT
zabbix=>