ダイエット中のZabbixのPostgreSQLインデックス

最近、ZabbixをPostgreSQLデータベースで動作するように移動しました。 SSDを搭載したサーバーに移行することで、速度が大幅に向上しました。 また、データベース内のホストの重複に関する問題、 バグリクエストも解決しました。 この記事はここで終わるかもしれませんが、Zabbixは多くのディスク容量を使用することに気づいたので、以下でどのようになったかを説明します。 そして、どのようにそれを理解したか。



Zabbixには比較的大きなデータベースがあります。 ほぼ1,500のホストを監視し、約18万のメトリックを収集します。 データベースではパーティション化を使用しているため、履歴データを簡単にクリアできます。 この場合、パーティションごとに独自のインデックスがあります。 さて、あなたは私がほのめかしていることを理解しています。



はい、インデックスについて説明します。 多くのインデックスがほぼ2倍に成長し、各パーティションでボリュームが5〜7 Gbを占めることがわかりました。 また、10日間の履歴データと3か月の傾向を保存すると、合計で約70 GBの追加データが取得されます。 合計データベースボリュームが約220 Gbであるため、SSDの使用は非常に具体的です。



アプローチナンバーワン。 彼らは問題を真正面から解決し、完全なインデックス再作成を開始しました。 予想通り、70ギガバイト近くを解放し、うまくいきました。 短所:操作時間。 むしろ、この時点でロックがテーブルに適用され、インデックスの再作成に約3時間かかるという事実ですらあります。



アプローチ番号2。 pg_repackに注目しました 。 このユーティリティを使用すると、テーブルをロックせずにvacumm fullを作成し、インデックスを再作成できます。 彼らはそれをインストールし、セットアップし、開始し、喜んで準備しました。 1ギガバイト未満が解放されたことがわかったときの失望を想像してください。 ドキュメントを開いて非常に注意深く読んで、ポイントがあります-逐語的:



「ターゲットテーブルには、PRIMARY KEY、または少なくともNOT NULL列のUNIQUE合計インデックスが必要です。」 次に、データベースを開き、必要なテーブルにもどちらもないことを確認します。



もちろん、それらを追加することは可能ですが、これによりデータベースのサイズが大きくなり、開発者には明らかにプライマリキーを追加しない理由がありました。 たとえば、監視ログに関する情報を含むテーブルでは、行を完全に複製できることがわかりました。 最後に、pg_repackを放棄しなければなりませんでした。



3番目のアプローチは勝利です。 前日にパーティションを取得した場合、誰もそのパーティションに書き込みを行わないため、Zabbixサーバーのダウンタイムなしに再インデックスを作成できます。 発明-検証済み。 いいえ、ロックはパーティションではなくテーブル全体に重ねられます。 さて、まあ、もしインデックスの再作成ができないなら、新しいインデックスを作成してみてはいかがでしょうか。 アルゴリズムは簡単です:



  1. 「CREATE INDEX CONCURRENTLY」という構造で新しいインデックスを作成します。これにより、データベースに長いロックをかけることがなくなります。このパーティションに誰も書き込みを行わないため、インデックスが正常に作成されます。

  2. 古いインデックスを削除します。
  3. 新しいインデックスの名前を古いものに変更します。
  4. 喜んで胸を打ちました。


現在、毎晩、テーブルを通過してこれらすべての操作を実行するスクリプトを実行しています。



スクリプト
for i in `seq 1 10`; do dd=`date +%Y_%m_%d -d "$i day ago"` index_name="history_p$dd""_1" index_name_new="history_p$dd""_1_new" echo "$index_name" psql -U postgres -d zabbix -c "CREATE INDEX CONCURRENTLY $index_name_new ON partitions.history_p$dd USING btree (itemid, clock); " echo "Done CREATE" psql -U postgres -d zabbix -c "DROP INDEX partitions.$index_name" echo "Done DROP" psql -U postgres -d zabbix -c "ALTER INDEX IF EXISTS partitions.$index_name_new RENAME TO $index_name" echo "Done ALTER" done echo "Reindex history_uint_p Start \n" for i in `seq 1 10`; do dd=`date +%Y_%m_%d -d "$i day ago"` index_name="history_uint_p$dd""_1" index_name_new="history_uint_p$dd""_1_new" echo "$index_name" psql -U postgres -d zabbix -c "CREATE INDEX CONCURRENTLY $index_name_new ON partitions.history_uint_p$dd USING btree (itemid, clock); " echo "Done CREATE" psql -U postgres -d zabbix -c "DROP INDEX partitions.$index_name" echo "Done DROP" psql -U postgres -d zabbix -c "ALTER INDEX IF EXISTS partitions.$index_name_new RENAME TO $index_name" echo "Done ALTER" done echo "Reindex trends_p Start \n" for i in `seq 1 2`; do dd=`date +%Y_%m -d "1 month ago"` index_name="trends_p$dd""_1" index_name_new="trends_p$dd""_1_new" echo "$index_name" psql -U postgres -d zabbix -c "CREATE INDEX CONCURRENTLY $index_name_new ON partitions.trends_p$dd USING btree (itemid, clock); " echo "Done CREATE" psql -U postgres -d zabbix -c "DROP INDEX partitions.$index_name" echo "Done DROP" psql -U postgres -d zabbix -c "ALTER INDEX IF EXISTS partitions.$index_name_new RENAME TO $index_name" echo "Done ALTER" done echo "Reindex trends_uint_p Start \n" for i in `seq 1 2`; do dd=`date +%Y_%m -d "1 month ago"` index_name="trends_uint_p$dd""_1" index_name_new="trends_uint_p$dd""_1_new" echo "$index_name" psql -U postgres -d zabbix -c "CREATE INDEX CONCURRENTLY $index_name_new ON partitions.trends_uint_p$dd USING btree (itemid, clock); " echo "Done CREATE" psql -U postgres -d zabbix -c "DROP INDEX partitions.$index_name" echo "Done DROP" psql -U postgres -d zabbix -c "ALTER INDEX IF EXISTS partitions.$index_name_new RENAME TO $index_name" echo "Done ALTER" done
      
      







スクリプトを厳しく批判しないでください-これは記事を明確にするためのドラフトです。



ご清聴ありがとうございました!



All Articles