<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>OSS &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/tag/oss/feed/index.xml" rel="self" type="application/rss+xml" />
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<description>OSS専門の技術ブログ。PostgreSQL、Zabbixを中心に10種類以上のOSSの解説、アップデート情報、運用ヒントを提供。</description>
	<lastBuildDate>Thu, 15 Oct 2026 03:51:41 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2018/07/blog-icon-150x150.png</url>
	<title>OSS &#8211; SRA OSS Tech Blog</title>
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>PostgreSQL 19検証報告</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgsql/pg19report/</link>
		
		<dc:creator><![CDATA[データベース技術グループ]]></dc:creator>
		<pubDate>Thu, 02 Jul 2026 22:30:13 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[PostgreSQL 18]]></category>
		<category><![CDATA[PostgreSQL 19]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=20859</guid>

					<description><![CDATA[2026年秋にリリース予定となっている PostgreSQL 19 の新機能や性能向上、非互換変更点の主要なものについて内容を説明し、動作検証を報告する文書を公開します。インストール手順やコマンド実行手順が記載してあるた ...]]></description>
										<content:encoded><![CDATA[<p>2026年秋にリリース予定となっている PostgreSQL 19 の新機能や性能向上、非互換変更点の主要なものについて内容を説明し、動作検証を報告する文書を公開します。インストール手順やコマンド実行手順が記載してあるため、PostgreSQL 19 の新機能を実際に動かしながら確認しようとする方へのガイドブックとしても利用できます。</p>
<p><span id="more-20859"></span></p>
<p>PostgreSQL 19 の主な強化点は以下の通りです。これらについてレポートで取り扱っています。<br />
なお、2026年 9月リリースの beta4版までで「バイナリpg_dumpall」「プロパティグラフ問合せ」「テンポラルテーブル更新」「パーティションの分割／統合」など、当初の beta1 には含まれていた機能追加が取り下げられました。</p>
<ul>
<li>性能向上
<ul>
<li>各種プランナ改善</li>
<li>タプルデフォーム高速化</li>
<li>SIMD利用拡大</li>
<li>外部キー制約検査の高速化</li>
<li>基数ソート</li>
</ul>
</li>
<li>SQL機能
<ul>
<li>グルーピングの拡張</li>
<li>COPYコマンドの拡張</li>
<li>各種の追加関数</li>
</ul>
</li>
<li>運用管理
<ul>
<li>Autovacuumスコア</li>
<li>各種モニタリングビューの追加</li>
<li>ログ出力の拡張</li>
<li>REPACKコマンド</li>
</ul>
</li>
<li>レプリケーション
<ul>
<li>ストリーミングレプリケーションの拡張</li>
<li>論理レプリケーションの拡張</li>
</ul>
</li>
<li>拡張モジュール
<ul>
<li>pg_plan_advice追加</li>
<li>pg_stash_advice追加</li>
<li>pg_stat_statements改善</li>
</ul>
</li>
</ul>
<h2>検証レポート</h2>
<p>レポートは以下リンクから参照できます。</p>
<ul>
<li><a href="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/09/pg19_report_1.2.pdf">PostgreSQL 19 検証レポート(2026年 9月 24日版、PDFファイル、94ページ、2.1MB)</a></li>
</ul>
<p>PostgreSQL 19の機能のさらなる詳細はPostgreSQL 19公式ドキュメントを参照してください。</p>
<ul>
<li><a href="https://www.postgresql.org/docs/19/" target="_blank" rel="noopener noreferrer">PostgreSQL 19 公式ドキュメント（英語）</a></li>
</ul>
<p>&nbsp;</p>
<div>
<div style="background-color: #fffacd; padding: 20px; border-radius: 8px; text-align: center;">2026/10/27（火）「PostgreSQL 19 リリース記念セミナー」開催！<br />
コントリビューターが新機能をわかりやすく解説します。<br />
詳しくは<a href="https://www.sraoss.co.jp/event_seminar/detail/20261027-postgresql19-webinar/?utm_source=techblog&amp;utm_medium=email&amp;utm_campaign=pg19-seminar" target="_blank" rel="noopener"><strong style="color: #2581c4;">こちら</strong></a>をご覧ください。</div>
</div>

<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

<p>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>YugabyteDB Voyager の紹介</title>
		<link>https://www.sraoss.co.jp/tech-blog/yugabytedb/yugabytedb-voyager-intro/</link>
		
		<dc:creator><![CDATA[三和 陽菜 (Haruna Miwa)]]></dc:creator>
		<pubDate>Wed, 24 Jun 2026 06:01:04 +0000</pubDate>
				<category><![CDATA[YugabyteDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Voyager]]></category>
		<category><![CDATA[マイグレーション]]></category>
		<category><![CDATA[分散SQL]]></category>
		<category><![CDATA[移行]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=20755</guid>

					<description><![CDATA[YugabyteDB Voyagerは、YugabyteDBへの移行を支援するツールです。移行可否のアセスメントから、スキーマ移行、データ移行まで、データベース移行に必要な操作全般を管理することができます。 本稿では、ま ...]]></description>
										<content:encoded><![CDATA[<p>YugabyteDB Voyagerは、YugabyteDBへの移行を支援するツールです。移行可否のアセスメントから、スキーマ移行、データ移行まで、データベース移行に必要な操作全般を管理することができます。<br />
本稿では、まずYugabyteDB Voyagerの概要について解説し、さらに移行方式の一つであるオフラインマイグレーションについて、具体的な操作方法を解説します。</p>
<p><span id="more-20755"></span></p>
<h1>概要</h1>
<p>YugabyteDB Voyagerは、無料かつオープンソースのYugabyteDB移行ツールです。PostgreSQL、Oracle、MySQLといった主要なデータベースを移行元としてサポートしており、オンプレミス環境・クラウド環境のどちらでも使用可能なため、さまざまなシステム構成からの移行に対応できます。また、すべてのYugabyteDB製品を移行対象としてサポートしています。</p>
<p>YugabyteDB Voyagerは、YugabyteDBに移行するにあたりどの程度修正が必要な箇所があるかをリストアップし、移行可能かどうかのアセスメントを支援します。また、実際に移行すると決定した際には、テーブル定義やインデックス定義については自動で変換を行い、移行に必要な労力を最小限に抑えます。データ移行の際にはチューニングを行い、インポートパフォーマンスの向上を自動で行います。</p>
<p>さらに、ソースデータベースとしてPostgreSQLを使用する場合、データベース停止が必要なオフラインマイグレーションの他に、ダウンタイムを最小限に抑えるライブマイグレーションが利用可能です。ビジネスクリティカルなアプリケーションにおいて、YugabyteDBへの移行を強力に支援します。</p>
<h1>移行方式</h1>
<p>YugabyteDB Voyagerで利用可能な移行方式は以下の通りです。</p>
<table>
<thead>
<tr>
<th>移行方式</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>オフラインマイグレーション</td>
<td>アプリケーションを停止した状態でデータを移行する方式です。</td>
</tr>
<tr>
<td>ライブマイグレーション</td>
<td>アプリケーションを停止せずにデータを移行する方式です。データをエクスポートする際、まずはある時点を基準としたスナップショットを取得します。それ以降に発生したデータ更新は、ディスク上のイベントキューに保管します。データをインポートする際はまず、スナップショットをインポートします。その後、イベントキューに保管されているデータの変更処理を反映させます。</td>
</tr>
<tr>
<td>フォールフォワード付きライブマイグレーション</td>
<td>ライブマイグレーションの際、移行元のDBにレプリカデータベースを用意します。YugabyteDBへの移行後、移行元DBは停止しますがレプリカデータベースには変更を反映し続けます。移行後、うまくいかなかった場合にはレプリカデータベースへ切り戻すことができます。</td>
</tr>
<tr>
<td>フォールバック付きライブマイグレーション</td>
<td>YugabyteDBへ移行した後、データの変更があった場合には移行元DBへも変更を反映させます。移行後、うまくいかなかった場合には元のDBへ切り戻すことができます。</td>
</tr>
</tbody>
</table>
<h1>オフラインマイグレーション</h1>
<p>今回は、PostgreSQLからYugabyteDBへのオフラインマイグレーションを実行してみます。<br />
環境は以下の通りです。</p>
<table>
<tbody>
<tr>
<th>OS</th>
<td>Rocky Linux release 9.7 (Blue Onyx)</td>
</tr>
<tr>
<th>PostgreSQL</th>
<td>17.9</td>
</tr>
<tr>
<th>YugabyteDB</th>
<td>2024.2.2.0</td>
</tr>
<tr>
<th>YugabyteDB Voyager</th>
<td>2026.3.1</td>
</tr>
</tbody>
</table>
<p>今回は移行元データベースとしてPostgreSQLサーバ1台、移行先データベースとしてYugabyteDB3台のクラスタ構成を構築しています。<br />
各サーバの情報は以下の通りです。</p>
<table>
<tbody>
<tr>
<th></th>
<th>PostgreSQL</th>
<th>YugabyteDB#1</th>
<th>YugabyteDB#2</th>
<th>YugabyteDB#3</th>
</tr>
<tr>
<td>IPアドレス</td>
<td>172.20.0.15</td>
<td>172.20.0.11</td>
<td>172.20.0.12</td>
<td>172.20.0.13</td>
</tr>
</tbody>
</table>
<p>今回はPostgreSQLサーバ、YugabyteDBクラスタの構築手順については記載を省略します。YugabyteDBクラスタの構築については<a href="https://www.sraoss.co.jp/tech-blog/yugabytedb/yugabytedb-oss/">YugabyteDB OSS版の使い方</a>、<a href="https://www.sraoss.co.jp/tech-blog/yugabytedb/yugabytedb-aeon-self-managed/">YugabyteDB Aeon Self-Managed (旧 YugabyteDB Anywhere) の使い方</a>も参考にしてください。</p>
<h2>YugabyteDB Voyagerのインストール</h2>
<p>まず、YugabyteDB Voyagerをインストールします。<br />
<a href="https://docs.yugabyte.com/stable/yugabyte-voyager/install-yb-voyager/" target="_blank" rel="noopener">公式ドキュメント</a>の手順に従って、インストールしてください。<br />
本稿ではPostgreSQLサーバにYugabyteDB Voyagerをインストールしています。</p>
<h2>ソースデータベースに対する事前準備</h2>
<p>まず、ソースデータベース(PostgreSQL)にマイグレーション用のユーザを作成します。マイグレーション用ユーザは移行対象のすべてのリソースに対してREAD権限を持っている必要があります。</p>
<p>今回はybvoyagerユーザを作成します。<br />
ソースデータベースに接続し、以下のSQLを実行しました。</p>
<pre>CREATE USER ybvoyager PASSWORD 'password';</pre>
<p>次に、必要な権限を与えます。移行対象のデータベースに接続し、/opt/yb-voyager/guardrails-scripts/以下にある yb-voyager-pg-grant-migration-permissions.sql を実行します。</p>
<pre>psql -h 172.20.0.15 \
     -d db1 \
     -U postgres \
     -v voyager_user='ybvoyager' \
     -v schema_list='public' \
     -v is_live_migration=0 \
     -v is_live_migration_fall_back=0 \
     -f /opt/yb-voyager/guardrails-scripts/yb-voyager-pg-grant-migration-permissions.sql</pre>
<p>これで、ソースデータベースに対する準備は完了しました。</p>
<h2>ターゲットデータベースに対する事前準備</h2>
<p>ターゲットデータベース(YugabyteDB)に移行先のデータベースを用意します。<br />
移行先のデータベース名はソースデータベースと同じ名前でも異なる名前でも問題ありません。(以降のyb-voyagerコマンド実行時に、データベース名を指定しない場合、yb-voyagerは移行先データベースを yugabyte データベースとみなします。)<br />
移行先データベース名をyugabyteから変更したい場合は、YugabyteDB クラスタにデータベースを作成してください。</p>
<pre>CREATE DATABASE db1 WITH COLOCATION = true;</pre>
<p>次に、ターゲットデータベースについてもマイグレーション用ユーザを作成します。スーパーユーザとして作成する必要があります。<br />
今回はybvoyagerユーザを作成しました。</p>
<pre>CREATE USER ybvoyager SUPERUSER PASSWORD 'password';</pre>
<h2>エクスポートディレクトリの設定</h2>
<p>yb-voyagerはすべてのマイグレーションの状態をエクスポートディレクトリに書き出します。これは、Voyagerが使用するメタデータに加えて、スキーマやデータのダンプも含まれます。そのため、ソースデータベース全体を格納できる、十分な空き容量のあるファイルシステム上にエクスポートディレクトリを作成してください。</p>
<pre>mkdir -p $HOME/yb-migrate/export-dir</pre>
<p>マイグレーションを実行すると、yb-voyagerによって、以下のディレクトリが作成されます。</p>
<p>assessment: アセスメント時のメタデータと、アセスメント結果を格納します。<br />
schema: ソースデータベースのスキーマがCSV形式で格納されます。<br />
data: ソースデータベースのデータがCSV形式で格納されます。<br />
metainfo/temp yb-voyagerが内部予約しているディレクトリです。<br />
logs: コマンド実行時のログファイルが格納されます。</p>
<h2>設定ファイルの用意</h2>
<p>yb-voyagerコマンドには、設定値を一括で記載する設定ファイルが用意されています。設定ファイルを使用すると、コマンド実行時に逐一パラメータを指定する必要がないため便利です。(v2025.6.2以降に導入された機能です。)</p>
<p>/opt/yb-voyager/config-templates以下にテンプレートファイルが提供されているので、このテンプレートファイルをコピーして使用します。今回はオフラインマイグレーション用のファイル(offline-migration.yaml)を使用します。</p>
<pre>cp /opt/yb-voyager/config-templates/offline-migration.yaml ~</pre>
<p>ファイル内の、エクスポートディレクトリに関する項目、ソースデータベースの接続情報、ターゲットデータベースへの接続情報を編集する必要があります。以下は設定例です。</p>
<pre>export-dir: /voyager/export-dir
yugabyted-control-plane:
  db-conn-string: postgresql://yugabyte:yugabyte@172.20.0.11:5433  
source:
  db-type: postgresql
  db-host: 172.20.0.15
  db-port: 5432
  db-name: db1
  db-schema: public
  db-user: ybvoyager
  db-password: password
target:
  db-host: 172.20.0.11
  db-port: 5433
  db-name: db1
  db-user: ybvoyager
  db-password: password
</pre>
<h2>マイグレーションのアセスメント</h2>
<p>以下のコマンドを実行して、マイグレーションのアセスメントを実施します。<br />
このとき、先ほど作成したYAMLファイルのパスを&#8211;config-fileに指定します。<br />
今回は、~/offline-migration.yamlを指定しています。</p>
<pre>yb-voyager assess-migration --config-file ~/offline-migration.yaml</pre>
<p>実行すると、評価レポートのパスがコンソールに出力されます。<br />
評価レポートはJSON形式とHTML形式で出力されます。以下はhtml形式の評価レポートです。</p>
<p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-20773" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report.png" alt="" width="1857" height="997" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report.png 1857w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-300x161.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-1024x550.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-768x412.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-1536x825.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-304x163.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-282x151.png 282w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<p>移行の難易度や、非互換のオブジェクトが存在しているかを確認することができます。</p>
<h2 id="スキーマのエクスポート">スキーマのエクスポート</h2>
<p>アセスメントが完了したら、次はソースデータベースからスキーマをエクスポートします。<br />
以下のコマンドを実行してください。</p>
<pre>yb-voyager export schema --config-file ~/offline-migration.yaml</pre>
<p>実行すると、エクスポートディレクトリのschemaディレクトリに、結果が保存されます。</p>
<p>スキーマのエクスポートの際に、yb-voyagerはスキーマ定義の調整を自動で行います。</p>
<h2>スキーマの分析</h2>
<p>スキーマのエクスポート時に、yb-voyagerはスキーマ定義の調整を自動で行います。しかし、自動調整だけではYugabyteDBへのインポートが失敗する可能性があります。YugabyteDBはPostgreSQLと互換性がありますが、分散システムであるため、スキーマに若干の手動変更が必要になります。</p>
<p>以下コマンドを実行し、スキーマを分析してください。</p>
<pre>yb-voyager analyze-schema --config-file ~/offline-migration.yaml</pre>
<p>手動変更が必要なDDLステートメント一覧を表示するレポートを出力します。</p>
<p><img decoding="async" class="alignnone size-full wp-image-20769" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report.png" alt="" width="1857" height="998" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report.png 1857w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-300x161.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-1024x550.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-768x413.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-1536x825.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-304x163.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-282x152.png 282w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<h3>スキーマの手動修正</h3>
<p>生成されたレポートに記載のあるすべての問題について、EXPORT_DIR/schema/以下にある、対象のDDLを修正してください。手動で修正を加えたら、yb-voyager analyze-schema コマンドを再実行してください。変更内容を反映した新しいレポートが生成されます。生成されたレポートに問題がなくなるまで、この手順を繰り返す必要があります。</p>
<h2>スキーマのインポート</h2>
<p>スキーマの修正が完了したら、ターゲットデータベースにスキーマをインポートします。</p>
<pre>yb-voyager import schema --config-file ~/offline-migration.yaml</pre>
<p>yb-voyagerコマンドは、エクスポートディレクトリのschemaサブディレクトリにあるDDL を、ターゲットのYugabyteDBデータベースに適用します。もし、スキーマのインポートが途中で異常終了してしまった場合は、設定ファイルのignore-existパラメータをtrueに変更してから再実行してください。すでに作成に成功したオブジェクトは無視するようになります。</p>
<h2 id="データのエクスポート">データのエクスポート</h2>
<p>スキーマ移行が完了したら、次はデータ移行を行います。まずは、ソースデータベースからデータをエクスポートします。</p>
<pre>yb-voyager export data --config-file ~/offline-migration.yaml</pre>
<p>このコマンドは、EXPORT_DIR/data以下にCSV形式でデータをダンプします。</p>
<h3>注意事項</h3>
<p>データエクスポートの際は、以下の点に注意してください。</p>
<ul>
<li>PostgreSQLの場合、ソースデータベース上でロックを獲得しようとしている他のプロセスが存在しないことを確認してください。並列ジョブが複数ある場合、データをダンプすることはできません。</li>
<li>シーケンスの移行は、シーケンスの作成とレジューム値の設定という2つのステップで構成されています。レジューム値はデータのエクスポート時に生成されます。また、すべてのテーブルデータがインポートされた直後に、ターゲットのYugabyteDBデータベースにこれらのレジューム値は設定されます。PostgreSQLの場合、移行対象テーブルに紐づけられている、または、テーブルが所有するシーケンスのみが移行時に復元されます。</li>
<li>ソースデータベース上のテーブルの行サイズが大きすぎて、デフォルトのRPCメッセージサイズを超えている場合、インポートデータは「ERROR: Sending too long RPC message&#8230;」というエラーで失敗します。そのため、行サイズが大きいテーブルは、該当箇所を削除してから個別に移行する必要があります。</li>
</ul>
<h2>データのインポート</h2>
<p>データをエクスポートできたら、次はターゲットデータベースにデータをインポートします。</p>
<pre>yb-voyager import data --config-file ~/offline-migration.yaml</pre>
<p>進行状況を確認したい場合は、yb-voyager import data statusを実行してください。</p>
<p>デフォルトでは、yb-voyagerは複数の接続を使用して並列にデータをインポートします。並列度はクラスタのリソース使用状況に基づいて判断されます。</p>
<p>yb-voyagerは、データダンプファイル(EXPORT_DIR/data)をより小さなバッチに分割します。yb-voyagerは、ターゲットのYugabyteDBデータベースクラスタのすべてのノードが使用されるように、バッチを同時に取り込みます。このフェーズは、データインポート中にyb-voyagerが終了した場合でも再開できるように設計されています。再開後、データのインポートは処理が中断された地点から続行されます。</p>
<h3>注意事項</h3>
<p>データインポートの際は、以下の点に注意してください。</p>
<ul>
<li>大規模データセットをインポートする場合は、ターミナルセッションが終了してもインポート処理が中断されないように、screenセッションでimport dataを実行してください。</li>
<li>yb-voyagerのimport dataコマンドがデータ取り込み完了前に終了した場合は、同じ引数で再度実行すれば、データインポート処理が再開されます。</li>
</ul>
<h2>データインポート後のスキーマ調整</h2>
<p>ソースデータベースにNOT VALID制約がある場合は、データインポート後に制約を作成するコマンドを実行する必要があります。</p>
<pre>yb-voyager finalize-schema-post-data-import --config-file ~/offline-migration.yaml</pre>
<h2>マイグレーションの検証</h2>
<p>スキーマとデータのインポートが完了したら、データが正しく移行されていることを確認します。<br />
ソースデータベースとターゲットデータベース(YugabyteDB)の両方で検証用クエリを手動で実行して確認を行います。<br />
例えば、各テーブルの行数を確認するクエリを実行して行数がそろっているかどうかの確認を行ってください。</p>
<h2 id="マイグレーションの終了">マイグレーションの終了</h2>
<p>データが正しく移行されていることを確認できたら、移行する際に作成されたディレクトリ・データをクリーンアップします。<br />
yb-voyager end migration コマンドで、クリーンアップを実行します。</p>
<pre>yb-voyager end migration --config-file ~/offline-migration.yaml</pre>
<p>必要であれば、移行に使用したybvoyagerユーザの削除も行ってください。<br />
yb-voyagerで移行を実施すると、移行されたすべてのオブジェクトはybvoyagerユーザが所有している状態となります。<br />
オブジェクトの所有者を別のユーザに変更してから、ybvoyagerユーザを削除してください。</p>
<h1>終わりに</h1>
<p>本稿ではYugabyteDBへのマイグレーション支援ツール YugabyteDB Voyagerの使用方法を紹介しました。<br />
YugabyteDBはPostgreSQL互換データベースであるとはいえ、アーキテクチャが異なりますので、移行する際はスキーマ定義の修正が必要になります。<br />
YugabyteDB Voyagerは、スキーマ定義の互換性の評価から実施できますので、マイグレーションを行う際の強力なツールとなります。<br />
YugabyteDBへの移行を検討している方は、ぜひYugabyteDB Voyagerをご活用ください。</p>
<h1>参考</h1>
<p><a href="https://docs.yugabyte.com/stable/yugabyte-voyager/">YugabyteDB Voyager 公式ドキュメント</a></p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/consulting/yugabytedb/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-yugabyte" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、YugabyteDB のコンサルティングサービスを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pgpool-II 4.7 の紹介</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgpool/pgpool-4-7/</link>
		
		<dc:creator><![CDATA[越野 太基 (Taiki Koshino)]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 01:12:44 +0000</pubDate>
				<category><![CDATA[Pgpool-II]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[Pgpool-II 4.6]]></category>
		<category><![CDATA[Pgpool-II 4.7]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19057</guid>

					<description><![CDATA[2025 年 12 月 23 日、Pgpool-II の新しいメジャーバージョン 4.7 がリリースされました。 Pgpool-II 4.7 では、クライアント情報表示機能や、Watchdog と heartbeat r ...]]></description>
										<content:encoded><![CDATA[<p>2025 年 12 月 23 日、Pgpool-II の新しいメジャーバージョン 4.7 がリリースされました。</p>
<p>Pgpool-II 4.7 では、クライアント情報表示機能や、Watchdog と heartbeat receiver のセキュリティ強化、オンラインリカバリの機能が強化されました。また、フロントエンド/バックエンドプロトコルバージョン 3.2 サポートの追加、PostgreSQL 18 への対応も行われました。</p>
<p>Pgpool-II 4.7 の新機能及び変更点は Pgpool-II 公式ドキュメントの以下のページに記載されています。</p>
<p><a href="https://www.pgpool.net/docs/47/ja/html/release-4-7-0.html" target="_blank" rel="noopener">Pgpool-II 4.7 リリースノート</a></p>
<p>本記事では、これらの新機能について詳しく紹介します。</p>
<p><span id="more-19057"></span></p>
<h3>クライアント情報を表示するための pcp_proc_info, show pool_pools の機能強化</h3>
<p>4.6 までは Pgpool-II 経由で PostgreSQL に接続した場合、PostgreSQL 側からは各クライアントの接続情報を確認することができず、Pgpool-II のネットワークアドレスとポート番号のみしかわかりませんでした。<br />
そのため障害が起きてもどのクライアント接続で障害が発生しているのかを調査することが困難でした。</p>
<p>4.7 からは <a href="https://www.pgpool.net/docs/latest/ja/html/pcp-proc-info.html" target="_blank" rel="noopener">pcp_proc_info</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/sql-show-pool-pools.html" target="_blank" rel="noopener">show pool_pools</a> コマンドで Pgpool-II 経由で接続しているクライアントのホスト名、ポート番号、最後に実行した SQL を参照できるようになりました。</p>
<p><span class="PRODUCTNAME">Pgpool-II</span> の子プロセス情報を表示する <a href="https://www.pgpool.net/docs/latest/ja/html/pcp-proc-info.html" target="_blank" rel="noopener">pcp_proc_info</a> コマンドでは client_host(ホスト名), client_port(ポート番号), statement(最後に実行した SQL) が追加されました。</p>
<p>これにより PostgreSQL からでも Pgpool-II 経由で接続しているクライアントの接続情報や最後に実行したクエリ情報を参照できるようになり障害時などに障害が起きているクライアント接続を調査することが容易になりました。</p>
<pre>sraoss@server1:~/setuptest$ pcp_proc_info -p 50001 --verbose
Database : test
Username : sraoss
Start time : 2026-01-08 12:15:18 (0:15 before process restarting)
Client connection count : 1
Major : 3
Minor : 0
Backend connection time : 2026-01-08 12:15:18
Client connection time : 2026-01-08 12:15:18
Client idle duration : 0
Client disconnection time : 2026-01-08 12:16:38
Pool Counter : 1
Backend PID : 20250
Connected : 0
PID : 20195
Backend ID : 0
Status : Wait for connection
Load balance node : 0
client_host : 127.0.0.1
client_port : 54726
statement : SELECT 1;</pre>
<p><span class="PRODUCTNAME">Pgpool-II</span> のコネクションプールの状態を表示する <a href="https://www.pgpool.net/docs/latest/ja/html/sql-show-pool-pools.html" target="_blank" rel="noopener">show pool_pools</a> コマンドにも、client_host(ホスト名), client_port(ポート番号), statement(最後に実行した SQL) が追加されました。</p>
<p>これらの変更で子プロセスやコネクションプーリングの情報とあわせてクライアント情報を参照できるようになりました。</p>
<pre class="PROGRAMLISTING">test=# show pool_pools;
 pool_pid |                      start_time                      | client_connection_count | pool_id | backend_id | database | username | backend_connection_time | client_connection_time | client_disconnection_time | client_idle_duration | majorversion | minorversion | pool_counter | pool_backendpid | pool_connected |       status        | load_balance_node |  client_host  | client_port |  statement  
----------+------------------------------------------------------+-------------------------+---------+------------+----------+----------+-------------------------+------------------------+---------------------------+----------------------+--------------+--------------+--------------+-----------------+----------------+---------------------+-------------------+---------------+-------------+-------------
[snip]
 1336537  | 2025-06-24 10:53:35                                  | 0                       | 0       | 0          | test     |  sraoss  | 2025-06-24 10:55:58     | 2025-06-24 10:55:59    |                           | 0                    | 3            | 0            | 1            | 1336703         | 1              | Idle                | 0                 | 192.168.10.11 | 39216       | 
 1336537  | 2025-06-24 10:53:35                                  | 0                       | 0       | 1          | test     |  sraoss  | 2025-06-24 10:55:58     | 2025-06-24 10:55:59    |                           | 0                    | 3            | 0            | 1            | 1336704         | 1              | Idle                | 1                 | 192.168.10.11 | 39216       | select 1;
 1336537  | 2025-06-24 10:53:35                                  | 0                       | 1       | 0          |          |          |                         |                        |                           | 0                    | 0            | 0            | 0            | 0               | 0              | Idle                | 0                 | 192.168.10.11 | 39216       | 
 1336537  | 2025-06-24 10:53:35                                  | 0                       | 1       | 1          |          |          |                         |                        |                           | 0                    | 0            | 0            | 0            | 0               | 0              | Idle                | 0                 | 192.168.10.11 | 39216       | select 1;</pre>
<h3>pgpool_adm_pcp_proc_info 関数の追加</h3>
<p>pgpool_adm エクステンションに、Pgpool-II の子プロセスの情報を表示する <a href="https://www.pgpool.net/docs/latest/ja/html/pgpool-adm-pcp-proc-info.html" target="_blank" rel="noopener">pgool_adm_pcp_proc_info</a> 関数が追加されました。 pgpool_adm エクステンションは Pgpool-II 経由でも、あるいは直接 PostgreSQL から呼び出せる関数群です。</p>
<p><a href="https://www.pgpool.net/docs/latest/ja/html/pgpool-adm-pcp-proc-info.html" target="_blank" rel="noopener">pgool_adm_pcp_proc_info</a> で表示される情報は pcp_proc_info コマンドと同様ですが、pgpool_adm エクステンションの関数であるため 、PostgreSQL クライアントからでも呼び出せます。</p>
<p>pgpool_adm を使うメリットは、SQLが使用でき WHERE 句で条件を指定して表示内容を絞り込むことができることです。(pcp コマンドの場合は、出力結果を整形するために OS のコマンドを併用する必要があります。)</p>
<p>導入には以下コマンドで各サーバーで pgpool_adm をインストールしてください。</p>
<pre class="PROGRAMLISTING"># 各サーバーで以下を実行してインストール 
$ psql test
test=# CREATE EXTENSION pgpool_adm;</pre>
<p>その後 Pgpool-II や PostgreSQL のクライアント上で <a href="https://www.pgpool.net/docs/latest/ja/html/pgpool-adm-pcp-proc-info.html" target="_blank" rel="noopener">pgpool_adm_pcp_proc_info</a> を実行します。<br />
connected 列は接続状況を表示(0=接続なし, 1=接続中) しており、今回の例のように WHERE 句に &#8220;connected = 1&#8221; を指定することで接続中の情報に絞ることもできます。</p>
<pre class="PROGRAMLISTING">test=# select * from pcp_proc_info(host =&gt; '', port =&gt; 11001, username =&gt; 'sraoss', password =&gt; 'sraoss') where connected = '1';
-[ RECORD 1 ]-------------+----------------------------------------------------------------------------------------------------------------------------
database                  | test
username                  | sraoss
start_time                | 2026-01-08 10:56:08
client_connection_count   | 0
major                     | 3
minor                     | 0
backend_connection_time   | 2026-01-08 10:58:37
client_connection_time    | 2026-01-08 10:58:37
client_idle_duration      | 0
client_disconnection_time | 
pool_counter              | 1
backend_pid               | 14750
connected                 | 1
pid                       | 14585
backend_id                | 0
status                    | Execute command
load_balance_node         | 1
client_host               | 127.0.0.1
client_port               | 59120
statement                 | select * from pcp_proc_info(host =&gt; '', port =&gt; 11001, username =&gt; 'sraoss', password =&gt; 'sraoss') where connected = '1';</pre>
<p>また pg_stat_activity と組み合わせてより詳細な情報を表示することも可能です。<br />
以下の SQL では <a href="https://www.pgpool.net/docs/latest/ja/html/pgpool-adm-pcp-proc-info.html" target="_blank" rel="noopener">pgpool_adm_pcp_proc_info</a> とpg_stat_activity を結合して <a href="https://www.pgpool.net/docs/latest/ja/html/pgpool-adm-pcp-proc-info.html" target="_blank" rel="noopener">pgool_adm_pcp_proc_info</a> では取得できない state を pg_stat_activity をから取得しています。<br />
他にも wait_event など pg_stat_activity にしかない情報も同時に取得するなど要件に応じてクライアント情報を取得できます。</p>
<pre>test=# SELECT p.username, p.database, p.client_port, s.state, s.wait_event, s.query,
              p.pid as pgpool_pid, s.pid as backend_pid
              FROM pcp_proc_info(host =&gt; '', port =&gt; 11001,
                                 username =&gt; 'sraoss', password =&gt; 'sraoss') AS p
              JOIN pg_stat_activity AS s ON s.pid::text = p.backend_pid;
-[ RECORD 1 ]-------------+----------------------------------------------------------------------------------------------------------------------------
username                  | sraoss
 database                 |  test
 client_host              | 192.168.100.101
client_port               | 50001
state                     | active  
query                     | select 1;
pgpool_pid                | 21467
backend_pid               | 21500</pre>
<h3>ライフチェックログの改善</h3>
<p>ライフチェックが開始したとき Watchdog は ライフチェックが開始したことを知らせるログを出力します。<br />
4.6 までは正常に開始したタイミングでしかログが出力されないため、正常に動作しているかを確認するために開始ログが出るまでログを監視する必要があり、またライフチェックが正常に開始していない状況に気づくのが困難でした。</p>
<pre>LOG:  watchdog: lifecheck started</pre>
<p>4.7 からはライフチェックが開始されるまで定期的にライフチェックが開始していない警告を出力するようになり、ライフチェック開始までログファイルを監視する必要がなくなりました。<br />
間隔は wd_interval × 10 秒です。</p>
<pre><i>WARNING:  watchdog: lifecheck has not started yet</i></pre>
<h3>Watchdog と heartbeat receiver のセキュリティ強化</h3>
<p>Watchdog と heartbeat receiver が受け付けるアドレスを制限することができるようになりました。</p>
<p>4.6 まではいずれのプロセスも、ホストが持つすべてのネットワークアドレスへの接続を受け付けていました。</p>
<pre>tcp        0      0 <b>0.0.0.0:9000</b>            0.0.0.0:*     LISTEN   3583037/pgpool: watchdog
Tcp6       0      0 <b>:::9000                 </b>:::*          LISTEN   3583037/pgpool: watchdog
Udp        0      0 <b>0.0.0.0:9694</b>            0.0.0.0:*              3583050/pgpool: heartbeat receiver
udp        0      0 <b>0.0.0.0:9694</b>            0.0.0.0:*              3583044/pgpool: heartbeat receiver
udp6       0      0 <b>:::9694                 </b>:::*                   3583044/pgpool: heartbeat receiver
udp6       0      0 <b>:::9694                 </b>:::*                   3583050/pgpool: heartbeat receiver</pre>
<p>4.7 からはセキュリティ上の点から <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HOSTNAME" target="_blank" rel="noopener">hostname</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HEARTBEAT-HOSTNAME" target="_blank" rel="noopener">heartbeat_hostname</a> で指定したネットワークアドレスへのみ接続を受け付けるようになりました。</p>
<pre># pgpool.conf 設定例
hostname0 = '192.168.100.50'
wd_port0 = 9000
heartbeat_hostname0 = '192.168.100.101'
heartbeat_port0 = 9694
hostname1 = '192.168.100.60'
wd_port0 = 9000
heartbeat_hostname1 = '192.168.100.102'
heartbeat_port1 = 9694
hostname2 = '192.168.100.70'
wd_port0 = 9000
heartbeat_hostname2 = '192.168.100.103'
heartbeat_port2 = 9694</pre>
<pre>tcp        0      0 <b>192.168.100.50:</b><b>9000</b><b>    </b>0.0.0.0:*     LISTEN      41636/pgpool: watchdog
tcp        0      0 <b>192.168.100.50:</b><b>9000</b><b>    </b>0.0.0.0:*     LISTEN      41638/pgpool: watchdog
udp        0      0 <b>192.168.100.101:9694 </b>  0.0.0.0:*                 41649/pgpool: heartbeat receiver
udp        0      0 <b>192.168.100.101:9694</b>   0.0.0.0:*                 41650/pgpool: heartbeat receiver</pre>
<p>もし他ノードから <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HOSTNAME" target="_blank" rel="noopener">hostname</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HEARTBEAT-HOSTNAME" target="_blank" rel="noopener">heartbeat_hostname</a> で指定したネットワークアドレス以外へ heartbeat を送る設定とすると以下メッセージのように lifecheck に失敗します。<br />
4.7 へ移行する場合は <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HOSTNAME" target="_blank" rel="noopener">hostname</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HEARTBEAT-HOSTNAME" target="_blank" rel="noopener">heartbeat_hostname</a> で watchdog と heartbeat で LISTEN するソケットを設定し、他ノードから heartbeat を送るソケットを <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HOSTNAME" target="_blank" rel="noopener">hostname</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HEARTBEAT-HOSTNAME" target="_blank" rel="noopener">heatbeat_hostname</a> で指定したネットワークアドレスとしてください。</p>
<pre>WARNING:  watchdog: lifecheck has not started yet</pre>
<p>また 4.7. 1 ではさらに Watchdog と heartbeat それぞれについて LISTEN するソケットを個別で指定できるようになりました。<br />
これによりノード外部から見えるアドレスと、ノード内部から認識されるアドレスが異なる可能性があるコンテナ環境や、ポートフォワーディングを設定している場合でも、より柔軟に設定できるようになりました。<br />
Watchdog については <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-WD-LISTEN-ADDRESS" target="_blank" rel="noopener">wd_listen_address</a> によってネットワークアドレスを、<a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-WD-LISTEN-PORT" target="_blank" rel="noopener">wd_listen_port</a> によってポートも指定することができます。<br />
heartbeat についてはそれぞれ <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-WD-HEARTBEAT-LISTEN-ADDRESSES" target="_blank" rel="noopener">wd_heartbeat_listen_addresses</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-WD-HEARTBEAT-LISTEN-PORT" target="_blank" rel="noopener">wd_heartbeat_listen_port</a> によって指定できます。<br />
これらのパラメータが設定されているとき <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HOSTNAME" target="_blank" rel="noopener">hostname</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HEARTBEAT-HOSTNAME" target="_blank" rel="noopener">heartbeat_hostname</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-WD-PORT" target="_blank" rel="noopener">wd_port</a>, <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-watchdog-config.html#GUC-HEARTBEAT-PORT" target="_blank" rel="noopener">heartbeat_port</a> のローカルの設定は上書きされてソケットが作成されます。</p>
<pre># pgpool.conf 設定例
hostname0 = '192.168.100.50'
wd_port0 = 9000
heartbeat_hostname0 = '192.168.100.101'
heartbeat_port0 = 9694
wd_listen_address = 192.168.100.100
wd_listen_port = 50000
wd_heartbeat_listen_addresses = 102.168.100.110
wd_heartbeat_listen_port = 51000</pre>
<pre>tcp        0      0 <b>192.168.100.100:50000    </b>0.0.0.0:*     LISTEN      41636/pgpool: watchdog
udp        0      0 <b>192.168.100.110:51000 </b>   0.0.0.0:*                 41649/pgpool: heartbeat receiver
udp        0      0 <b>192.168.100.110:51000</b>    0.0.0.0:*                 41650/pgpool: heartbeat receiver</pre>
<p>これらのパラメータが導入された背景は、Docker 環境を代表とした TCP 転送ルールを設けているインターフェース間で通信をする際に LISTEN するソケットを転送ルールに合わせて設定したいケースに対応するためです。<br />
例えばノード 0 が IP:192.168.0.0, ポート番号:10000 のソケットに接続しようとし、TCP 転送ルールによってノード 1 の IP:192.168.100.100,ポート番号:20000 のソケットにリダイレクトされる環境の場合、ノード 1 側でリダイレクト後のネットワークアドレス、ポート番号(今回の例では IP:192.168.100.100, ポート番号:20000)に設定することで TCP 転送ルールがある場合でも通信が可能となりました。</p>
<h3>オンラインリカバリに使用するデータベースを指定する recovery_database パラメータの追加</h3>
<p>オンラインリカバリとは障害が発生して切り離されてしまった PostgreSQL ノードをプライマリに再同期して復帰する処理を各ノードを停止することなく行うことができる機能です。</p>
<p>以前はオンラインリカバリに template1 データベースを使用するようにしていましたが、今回追加された <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-online-recovery.html#GUC-RECOVERY-DATABASE" target="_blank" rel="noopener">recovery_databse</a> パラメータにオンラインリカバリに使用するデータベースを指定することができるようになりました。</p>
<pre>#pgpool.conf の recovery_database を指定
recovery_database = 'postgres'</pre>
<p>デフォルト値は postgres になっています。<br />
4.6 以前から移行をする際には <a href="https://www.pgpool.net/docs/latest/ja/html/runtime-online-recovery.html#GUC-RECOVERY-DATABASE" target="_blank" rel="noopener">recovery_database</a> に指定したデータベースで下記コマンドを実施してオンラインリカバリに必要な関数をインストールしておく必要があります。</p>
<pre class="PROGRAMLISTING">psql postgres -c "CREATE EXTENSION pgpool_recovery"</pre>
<h3><tt class="FILENAME">.pcppass</tt>ファイルからの読み取りに失敗時の挙動改善</h3>
<p>.pcppass ファイルは pcp コマンドを実行したときに読み込まれるパスワードファイルです。</p>
<p>4.6 までは pcp コマンド実行時に .pcppass ファイルが未作成かパスワードファイルの権限設定が不適切の場合、エラーで終了していました。<br />
また -d, &#8211;debug オプションがないとデバッグ情報が出力されず失敗の原因も特定できませんでした。</p>
<pre>FATAL:  authentication failed for user "sraoss"
DETAIL:  username and/or password does not match</pre>
<p>失敗後は .pcppass ファイルを適切な権限で作成するか、パスワード入力を受け付けるオプションである -W オプションをつけて pcp コマンドを再実行する必要がありました。</p>
<pre>pcp_node_info -p 9898 -W
Password:</pre>
<p>4.7 からはエラーを出力して終了するのではなく、クライアントのコマンドプロンプトにフォールバックして引き続きパスワードを入力することができるようになりました。</p>
<p>また WARNING による警告が -d, &#8211;debug オプションなく出力される仕様に変更され、読み取りができなかった原因もメッセージから特定することができます。</p>
<pre class="PROGRAMLISTING">WARNING: password file ~/.pcppass is not a plain file
WARNING: password file ~/.pcppass has group or world access; permissions should be u=rw (0600) or less</pre>
<h3>フロントエンド / バックエンドプロトコルバージョン 3.2 サポートの追加</h3>
<p>PostgreSQL 18 ではプロトコルバージョン 3.2 に対応し、可変長のキャンセルキーが用いることができるようになりました。<br />
この変更に合わせ、Pgpool-II でもプロトコルバージョン 3.2 を利用できるように改善がされました。</p>
<p>max_protocol_version や PGMAXPROTOCOLVERSION を用いた以下のようなコマンドで 3.2 プロトコルを使用して PostgreSQL のフロントエンドとバックエンドを接続することができます。<br />
バージョンには 3.2 だけでなく PostgreSQL 18 のデフォルトのプロトコルバージョンである 3.0 を指定することもできます。</p>
<pre class="PROGRAMLISTING"># max_protocol_version オプションで 3.0 バージョンで接続
psql "host=localhost dbname=test user=sraoss max_protocol_version=3.0 port=11000"

# 環境変数 PGMAXPROTOCOLVERSION に 3.2 を指定して接続
PGMAXPROTOCOLVERSION="3.2" psql -p 11000 test</pre>
<p>新規接続時は指定したプロトコルバージョンで接続を確立しますが、コネクションプーリングのキャッシュがある場合は既存のキャッシュに保存されたのプロトコルバージョンを用いて接続を行うため確立済みの接続間でバージョンが異なることによるエラーの心配もありません。</p>
<h3>PostgreSQL 18 の SQL パーサの導入</h3>
<p>Pgpool-II ではメジャーリリースするたびに、PostgreSQL の最新パーサを移植しています。今回のリリースでは PostgreSQL 18 の新しいパーサを取り込みました。</p>
<p>Pgpool-II の負荷分散機能では、SQL を解析して参照か更新かを判別し、どのノードに振り分けるかを決めています。そのため、PostgreSQL の新バージョンでの SQL の変更に対応するには、SQL パーサを移植する必要があります。</p>
<p>PostgreSQL 18 での SQL のおもな変更点は以下のとおりです。</p>
<ul>
<li>生成列を仮想列として使用可能に</li>
<li>DML クエリの RETURNING にOLD/NEWのサポートを追加</li>
<li>各種制約の追加(例: WITHOUT OVERLAPS、ENFORCED/NOT ENFORCED)</li>
</ul>
<p>Pgpool-II 4.7 では上記の変更点に対応しています。</p>
<h3>logdir パラメータ名を work_dir へ変更</h3>
<p><tt>4.6 までは Pgpool-II の起動状態を記述する </tt><tt class="LITERAL">pgpool_status や memq_lock_file といった管理</tt>ファイルを logdir に指定するディレクトリに保存していました。<br />
しかし logdir というパラメータ名はログ関連のファイルを格納するディレクトリの設定パラメータと誤解されやすい問題がありました。</p>
<p>4.7 からはパラメータ名が <a href="https://www.pgpool.net/docs/47/ja/html/runtime-misc.html#GUC-WORK-DIR" target="_blank" rel="noopener">work_dir</a> へ変更となりました。</p>
<p>logdir のパラメータ自体も引き続き利用することができ、logdir に指定した値が <a href="https://www.pgpool.net/docs/47/ja/html/runtime-misc.html#GUC-WORK-DIR" target="_blank" rel="noopener">work_dir</a> の設定値へと再設定され Pgpool-II の終了時に以下ワーニングが表示されます。</p>
<pre>2026-01-08 11:50:48.193: main pid 18667: WARNING: logdir is changed to work_dir
2026-01-08 11:50:48.193: main pid 18667: DETAIL: if logdir is specified, the value will be set to work_dir</pre>
<h3>Slony モードの廃止</h3>
<p class="PROGRAMLISTING"><a href="https://www.pgpool.net/docs/latest/ja/html/runtime-config-running-mode.html#GUC-BACKEND-CLUSTERING-MODE" target="_blank" rel="noopener">backend_clustering_mode</a> で指定することができていた Slony モードが廃止されました。</p>
<p class="PROGRAMLISTING">データのレプリケーションを Slony-I が行うクラスタリングモードの一つでしたが、Slony-I は 3 年前からリリースが停止しています。<br />
現在は Slony モードについて積極的に利用するユーザーが見られず、廃止のアナウンスに異議がなかったため 4.7 からは廃止となりました。</p>
<h3>Pgpool-II の libpcp ライブラリの名称を libpgpoolpcp に変更</h3>
<p class="PROGRAMLISTING">4.7.1 のマイナリリースにて Pgpool-II のライブラリである libpcp の名称を libpgpoolpcp に変更されました。<br />
背景として、RHEL の libpcp ライブラリと Pgpool-II の libpcp ライブラリがコンフリクトする問題があったためです。</p>
<h2>おわりに</h2>
<p>今回は、Pgpool-II 4.7 の新機能について紹介しました。</p>
<p>Pgpool-II 4.7 では、より実用的で便利な機能が数多く追加・改善されています。PostgreSQL の高可用性構成や負荷分散の実現を検討されている方にとって、Pgpool-II は有力な選択肢です。ぜひこの機会に Pgpool-II の導入をご検討ください。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Apache Kafka のトランザクションについて</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/kafka-transaction/</link>
		
		<dc:creator><![CDATA[奥井 一暁 (Kazuaki Okui)]]></dc:creator>
		<pubDate>Tue, 17 Mar 2026 01:00:37 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[Apache Kafka]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19910</guid>

					<description><![CDATA[Apache Kafka（以下 Kafka）ではメッセージ送信をトランザクションにまとめてアトミックに行うことができます。 さらに Kafka から取り出したメッセージに何らかの処理を行い再度 Kafka に書き込む、と ...]]></description>
										<content:encoded><![CDATA[<p class="code-line" dir="auto" data-line="2">Apache Kafka（以下 Kafka）ではメッセージ送信をトランザクションにまとめてアトミックに行うことができます。</p>
<p class="code-line" dir="auto" data-line="2">さらに Kafka から取り出したメッセージに何らかの処理を行い再度 Kafka に書き込む、という処理を行うにあたっては Offset Commit もトランザクションに含めることができます。</p>
<p class="code-line" dir="auto" data-line="2">この記事ではトランザクションを用いて送信したメッセージが後段で読まれるまでの流れを説明し、さらに Offset Commit をトランザクション内で行う際の流れについても説明します。</p>
<p dir="auto" data-line="2"><span id="more-19910"></span></p>
<p class="code-line" dir="auto" data-line="4">Kafka バージョンは 4.1.0 を用います。</p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E3%82%8B%E6%B5%81%E3%82%8C" class="code-line" dir="auto" data-line="6">トランザクションでメッセージを送る流れ</h2>
<p>メッセージ送信だけでなく Offset Commit も一つのトランザクションにまとめられるのが Kafka のトランザクションの特徴ですが、まずトランザクションを用いて単純にメッセージを送る流れから説明します。</p>
<p class="code-line" dir="auto" data-line="10">トランザクションを使用してメッセージを送信する際の大まかな流れは以下の通りです (すべて正常に送信できた場合)。</p>
<p dir="auto" data-line="10"><img decoding="async" class="alignnone wp-image-20030 size-large" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-1024x363.png" alt="" width="1024" height="363" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-1024x363.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-300x106.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-768x272.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-1536x545.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-2048x726.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-304x108.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-282x100.png 282w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<ol class="code-line" dir="auto" data-line="14">
<li class="code-line" dir="auto" data-line="14">トランザクションを初期化</li>
<li class="code-line" dir="auto" data-line="15">トランザクションを開始</li>
<li class="code-line" dir="auto" data-line="16">メッセージを送信 (ここでは送信先は Topic A)</li>
<li class="code-line" dir="auto" data-line="17">トランザクションを Commit</li>
</ol>
<p class="code-line" dir="auto" data-line="21">このように大まかな流れはデータベースのトランザクションと同様です。そして各ステップでそれぞれ以下のメソッドが対応します。</p>
<ol class="code-line" dir="auto" data-line="23">
<li class="code-line" dir="auto" data-line="23">トランザクションを初期化 (initTransactions メソッド)</li>
<li class="code-line" dir="auto" data-line="24">トランザクションを開始 (beginTransaction メソッド)</li>
<li class="code-line" dir="auto" data-line="25">メッセージを送信 (send メソッド)</li>
<li class="code-line" dir="auto" data-line="26">トランザクションを Commit (commitTransaction メソッド)</li>
</ol>
<p class="code-line" dir="auto" data-line="28">また送信中に例外が起きた場合などは abortTransaction メソッドによりトランザクションを Abort します。これらはすべて Producer のメソッドです。</p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E6%8C%99%E5%8B%95" class="code-line" dir="auto" data-line="30">トランザクションの挙動</h2>
<p class="code-line code-active-line" dir="auto" data-line="30">ここからは各メソッドがどのように動作するかを説明します。</p>
<h3 id="1-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E5%88%9D%E6%9C%9F%E5%8C%96-inittransactions" class="code-line" dir="auto" data-line="34">1. トランザクションの初期化 (initTransactions)</h3>
<p class="code-line" dir="auto" data-line="36">まずトランザクションを利用する前に initTransactions を呼び出します。このメソッドでは Transaction Coordinator に InitProducerId リクエストを送信してトランザクション初期化の処理を行います。InitProducerId リクエストには TransactionalID が含まれています。これは Producer のパラメータで、トランザクションを識別できるようにクラスタ内で一意になるよう設定します。初期化処理ではこの ID をもとに Transaction Coordinator から Producer ID を取得します。initTransactions は Producer 起動時に 1 回実行する必要があります。</p>
<p dir="auto" data-line="36"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20035" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-1024x317.png" alt="" width="1024" height="317" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-1024x317.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-300x93.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-768x238.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-1536x476.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-304x94.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-282x87.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2.png 1743w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h3 id="2-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E9%96%8B%E5%A7%8B-begintransaction" class="code-line" dir="auto" data-line="40">2. トランザクションの開始 (beginTransaction)</h3>
<p class="code-line" dir="auto" data-line="42">次に beginTransaction メソッドによってトランザクションを開始します。このメソッドでは Transaction Coordinator にリクエストを送るわけではなく Producer 内部の状態を変更することでトランザクションを開始します。</p>
<p dir="auto" data-line="42"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20037" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-1024x317.png" alt="" width="1024" height="317" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-1024x317.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-300x93.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-768x238.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-1536x476.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-304x94.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-282x87.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1.png 1743w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h3 id="3-%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E4%BF%A1-send" class="code-line" dir="auto" data-line="46">3. メッセージを送信 (send)</h3>
<p class="code-line" dir="auto" data-line="48">メッセージの送信は通常の送信と同様 send メソッドを用います。基本的には通常の送信と同じ挙動なのですが、Broker はトランザクション中の Produce リクエストを受け取るとメッセージの書き込みの前に (未実施であれば) AddPartitionsToTxn というリクエストを Transaction Coordinator に送ります。このリクエストでは書き込み先の Topic と Partition を Transaction Coordinator に知らせ、__transaction_state というトランザクション管理用内部 Topic に記録します。これによってどの Partition がトランザクション中なのか記録することができます。</p>
<p dir="auto" data-line="48"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20039" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-1024x371.png" alt="" width="1024" height="371" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-1024x371.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-300x109.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-768x278.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-1536x556.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-2048x742.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-304x110.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-282x102.png 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h3 id="4-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92-commitabort-committransactionaborttransaction" class="code-line code-active-line" dir="auto" data-line="52">4. トランザクションを Commit/Abort (commitTransaction/abortTransaction)</h3>
<p class="code-line" dir="auto" data-line="54">必要なメッセージ送信が完了したら commitTransaction によってトランザクションを確定させます。commitTransaction ではトランザクションを Commit する旨を添えて EndTxn リクエストを Transaction coordinator に送ります。Transaction coordinator がリクエストを受け取るとまず __transaction_state に Commit する旨を記録します。さらに AddPartitionsToTxn によって記録されている Partition に対して Commit したことを示すメッセージを送ります。このメッセージは Control Batch と呼ばれる、トランザクションの終了を示す特別なメッセージです。Control Batch の送信は commitTransaction とは非同期で行われます。</p>
<p dir="auto" data-line="54"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20042" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-1024x288.png" alt="" width="1024" height="288" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-1024x288.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-300x84.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-768x216.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-1536x432.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-304x86.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-282x79.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1.png 2037w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="58">トランザクションを Abort するには abortTransaction を用います。abortTransaction ではトランザクションを Abort する旨を添えて EndTxn リクエストを送り、関連する Partition に Abort したことを示す Control Batch を送ります。</p>
<p class="code-line" dir="auto" data-line="60">Commit / Abort がされた状態の Partition は下図のようになっています。Control Batch も通常のメッセージと同じように記録されます。</p>
<p dir="auto" data-line="60"><img loading="lazy" decoding="async" class="alignnone wp-image-20043" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-1024x350.png" alt="" width="412" height="141" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-1024x350.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-300x103.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-768x263.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-304x104.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-282x97.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1.png 1236w" sizes="auto, (max-width: 412px) 100vw, 412px" /></p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E9%80%81%E4%BF%A1%E3%81%97%E3%81%9F%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AE%E8%AA%AD%E3%81%BF%E5%87%BA%E3%81%97" class="code-line" dir="auto" data-line="66">トランザクションで送信したメッセージの読み出し</h2>
<p class="code-line" dir="auto" data-line="68">次にメッセージを読み出す際にトランザクション中のメッセージや Abort したメッセージをどのように扱うかについて説明します。</p>
<p class="code-line" dir="auto" data-line="70">すでに述べたように、トランザクションの Commit / Abort は Control Batch によって行うのでトランザクション中のメッセージも Partition 内には記録されています。また Abort したメッセージも Partition 内には残っています。これらのメッセージをどのように扱うかは Consumer の設定である isolation.level によって決まります。</p>
<p class="code-line" dir="auto" data-line="70">isolation.level には read_uncommitted (デフォルト値) あるいは read_committed を設定することができます。read_uncommitted の場合、poll メソッドはトランザクション中かどうかや Abort されているかに関わらずすべてのメッセージを取得することができます。</p>
<p class="code-line code-active-line" dir="auto" data-line="72">次に read_committed の場合ですが、この説明のためには Last Stable Offset (LSO) について説明する必要があります。LSO はトランザクションが未確定の Offset のうち一番小さい Offset のこと (下図では Offset 6) です。これより前の Offset はすべて確定していることになり、Stable Offsets といいます。逆にこれより後の Offset の領域では確定と未確定が混在していることになります。混在しうるのは同じ Partition に複数の Producer がトランザクションでメッセージを送信する場合です。read_committed の場合、poll メソッドは Stable Offsets のメッセージのみ取得することができます。さらに Abort されたメッセージを取り除いた上でユーザーに返します。</p>
<p dir="auto" data-line="72"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20047" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-1024x407.png" alt="" width="1024" height="407" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-1024x407.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-300x119.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-768x305.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-1536x610.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-2048x813.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-304x121.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-282x112.png 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="78">このように、トランザクションを使って送信したメッセージを読み出す際は isolation.level を read_committed にすることで Commit 済みのメッセージのみ読むことができます。</p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8-offset-commit" class="code-line" dir="auto" data-line="80">トランザクションと Offset Commit</h2>
<p class="code-line" dir="auto" data-line="82">冒頭で述べたように、Offset Commit をトランザクションに含められる点が Kafka のトランザクションの特徴です。この仕組みは、Kafka から取得したメッセージに何らかの処理を行い、再度 Kafka に書き込むような処理で利用されます。</p>
<p dir="auto" data-line="82"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20049" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-1024x403.png" alt="" width="1024" height="403" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-1024x403.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-300x118.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-768x302.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-304x120.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-282x111.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3.png 1533w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="82">この例では以下の流れで処理が進みます。</p>
<ol class="code-line" dir="auto" data-line="84">
<li class="code-line" dir="auto" data-line="83">クライアント AP が Topic A からメッセージを取得</li>
<li class="code-line" dir="auto" data-line="84">取得したメッセージを AP で処理し、その結果を Topic A&#8217; に送信</li>
<li class="code-line code-active-line" dir="auto" data-line="85">すべての処理結果送信が完了したら Topic A の Offset Commit</li>
</ol>
<p class="code-line" dir="auto" data-line="91">ここで Offset Commit がトランザクションに入らない場合を考えてみましょう。処理結果の送信がアトミックにできたとしても Offset Commit に失敗した場合メッセージの取得からやり直すことになり、処理結果が二重に記録されてしまいます。Offset Commit がトランザクションに入れば、Offset Commit に失敗した時に Abort することができます。</p>
<p dir="auto" data-line="91">このような利点があるため、Kafka から取得したメッセージに何らかの処理を行い、再度 Kafka に書き込むという処理では Offset Commit をトランザクション内で行います。</p>
<h2 id="offset-commit-%E3%82%92%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%86%85%E3%81%A7%E8%A1%8C%E3%81%86%E9%9A%9B%E3%81%AE%E6%8C%99%E5%8B%95" class="code-line" dir="auto" data-line="105">Offset Commit をトランザクション内で行う際の挙動</h2>
<p class="code-line" dir="auto" data-line="93">Kafka ではトランザクション内で Offset Commit をするために Producer 側で sendOffsetsToTransaction というメソッドが用意されています。全体の流れで見るとトランザクションを Commit する前に sendOffsetsToTransaction をすることになります。</p>
<p dir="auto" data-line="93"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20051" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-1024x425.png" alt="" width="1024" height="425" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-1024x425.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-300x124.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-768x319.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-1536x637.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-304x126.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-282x117.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1.png 1743w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<ol class="code-line" dir="auto" data-line="97">
<li class="code-line" dir="auto" data-line="97">トランザクションを初期化 (initTransactions メソッド)</li>
<li class="code-line" dir="auto" data-line="98">Topic A からメッセージを取り出す (Consumer が poll メソッドで取得)</li>
<li class="code-line" dir="auto" data-line="99">トランザクションを開始 (beginTransaction メソッド)</li>
<li class="code-line" dir="auto" data-line="100">処理結果のメッセージを Topic A&#8217; に送信 (send メソッド)</li>
<li class="code-line" dir="auto" data-line="101">Topic A について Offset Commit (sendOffsetsToTransaction メソッド)</li>
<li class="code-line" dir="auto" data-line="102">トランザクションを Commit (commitTransaction メソッド)</li>
</ol>
<p class="code-line code-active-line" dir="auto" data-line="107">sendOffsetsToTransaction では TxnOffsetCommit リクエストを Consumer Group Coordinator に送ります。Offset Commit のやり方自体は通常の Consumer から行うものと同じで、__consumer_offsets という内部 Topic へ Offset Commit の情報が記録されます。異なるのは内部 Topic への記録の前に (未実施であれば) AddPartitionsToTxn リクエストが送信される点です。send と同様に、この操作によってトランザクションに含まれる Partition の情報が __transaction_state に記録されます。</p>
<p dir="auto" data-line="107"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20052" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-1024x347.png" alt="" width="1024" height="347" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-1024x347.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-300x102.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-768x260.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-1536x521.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-2048x694.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-304x103.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-282x96.png 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="111">Offset Commit 情報の Commit (あるいは Abort) も、__consumer_offsets の対応する Partition に Control Batch を送ることによって記録されます。</p>
<h2 id="%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%AB" class="code-line" dir="auto" data-line="113">終わりに</h2>
<p class="code-line" dir="auto" data-line="114">Kafka でトランザクションを用いてメッセージを送信し確定させるまでの挙動と、トランザクションで送信したメッセージを読み出す際の挙動について解説しました。さらに Offset Commit をトランザクション内で行う際の挙動についても解説しました。</p>
<p class="code-line" dir="auto" data-line="116">Kafka のトランザクションで Offset Commit を行う場合、本来 Consumer から行うものを Producer から行うため混乱しますが、単にメッセージを送るのみであれば使う流れはデータベースのトランザクションと同じようなものです。メッセージを送るのみの流れ、Offset Commit もする場合の流れと段階的に理解するのがよいでしょう。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pacemaker におけるスロットリング (Throttle) の仕組み</title>
		<link>https://www.sraoss.co.jp/tech-blog/pacemaker/throttling/</link>
		
		<dc:creator><![CDATA[彭 博 (Bo Peng)]]></dc:creator>
		<pubDate>Fri, 06 Mar 2026 02:11:45 +0000</pubDate>
				<category><![CDATA[Pacemaker]]></category>
		<category><![CDATA[Corosync]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19976</guid>

					<description><![CDATA[Pacemaker を運用していると、次のようなログを目にすることがあります。 notice: High CPU load detected info: New throttle mode debug: New job  ...]]></description>
										<content:encoded><![CDATA[<p><a href="https://clusterlabs.org/projects/pacemaker/" target="_blank" rel="noopener">Pacemaker</a> を運用していると、次のようなログを目にすることがあります。</p>
<pre>notice: High CPU load detected
info: New throttle mode
debug: New job limit is 1</pre>
<p>このログを初めて見たとき、「クラスタに異常が発生したのではないか」と不安に感じる方もいるかもしれません。しかし結論から言うと、これらのログは障害ではありません。クラスタノードの負荷が高くなったため、Pacemaker の 負荷保護機構 (スロットリング) が正常に動作したことを示すログです。</p>
<p>本記事では、Pacemaker の運用で頻繁に遭遇する負荷スロットリングについて、ログの意味を読み解きながら分かりやすく解説します。なお、本記事は <strong>Pacemaker 3.0.1</strong> を前提としています。</p>
<p><span id="more-19976"></span></p>
<h2>負荷スロットリングとは何か</h2>
<p>Pacemaker の負荷スロットリングとは、ノードの負荷が高くなった際にリソースアクション (<code>start / stop / monitor</code> など) の同時実行数を自動的に減らす安全機構です。Pacemaker はクラスタの状態を維持するために、リソースの起動や停止、監視など多くの処理を常に実行しています。これらは通常、並列に実行されることで迅速なフェイルオーバーや復旧を実現しています。</p>
<p>しかし、ノードがすでに高負荷状態のときに大量のリソース操作を同時実行すると、状況がさらに悪化する可能性があります。<code>monitor</code> のタイムアウトやフェイルオーバーの誤発生、さらには <code>STONITH</code> の誤発動などが連鎖的に発生し、クラスタ全体が不安定な状態に陥ることがあります。</p>
<p>このような事態を防ぐために、Pacemaker は自らの動作を意図的に減速させます。これが<strong>スロットリング</strong>です。</p>
<h2>通常時の並列制御の仕組み</h2>
<p>Pacemaker のリソースアクションは、通常時でも無制限に並列実行されるわけではありません。次の 2 つのパラメータで制御されています。</p>
<ul>
<li>node-action-limit（ノード単位）</li>
<li>batch-limit（クラスタ全体）</li>
</ul>
<h3>node-action-limit</h3>
<p><code>node-action-limit</code> は、ノード単位で同時実行できるアクション数の上限を決めるパラメータです。デフォルト値は 0 (自動) であり、次の式で自動計算されます。</p>
<pre>node-action-limit = CPUコア数 × 2</pre>
<p>たとえば 4 コアのサーバであれば、最大 8 個のリソース操作を同時に実行できます。この設計により、通常時は効率よくリソース操作を処理できるようになっています。</p>
<h3>batch-limit</h3>
<p><code>batch-limit</code> はクラスタ全体での同時実行数を制御します。<code>node-action-limit</code> が「各ノード単位の上限」であるのに対し、<code>batch-limit</code> は「クラスタ全体で同時に実行できるアクション数の上限」です。デフォルト値は 0（自動）で、Pacemaker がクラスタの状態や負荷状況を見ながら動的に調整します。</p>
<p>では、ノードが高負荷になった場合はどうなるのでしょうか。ここから動的スロットリングについて見ていきます。</p>
<h2>代表的な負荷制御ログ</h2>
<p>Pacemaker は、ノード負荷に応じたスロットリングが発生すると、次のようなログを出力します。</p>
<p>ここでは debug ログを有効化した場合の出力例を示します。</p>
<pre>debug: Current load is 1.110000 across 4 core(s)
notice: High CPU load detected: 8.040000
info: New throttle mode: high load (was medium)
debug: Node node1 has high load and supports at most 8 jobs; new job limit 1</pre>
<p>以降では、これらのログがそれぞれ何を意味しているのかを順番に解説していきます。</p>
<h3>Current load (現在のノード負荷)</h3>
<pre>debug: Current load is 1.110000 across 4 core(s)</pre>
<p>このログは、Pacemaker が現在のノード負荷をどのように認識しているかを示しています。</p>
<p>Pacemaker が負荷判定に使用している指標は load average です。ここで表示されている「Current load」は、<code>/proc/loadavg</code> の先頭フィールドである 1 分平均の load average を示しています。</p>
<h3>High CPU load detected (高負荷の検出)</h3>
<pre>notice: High CPU load detected: 8.040000</pre>
<p>このメッセージは、load average が Pacemaker の定義するしきい値を超えたことを示しています。</p>
<p>しきい値は load-threshold (デフォルト 80%) を基準に、CPU コア数から自動的に計算されます。Pacemaker は load average に対して、low / medium / high の 3 段階のしきい値を次の式で算出します。</p>
<pre>low    = load-threshold × CPUコア数 × 1.2
medium = load-threshold × CPUコア数 × 1.6
high   = load-threshold × CPUコア数 × 2.0</pre>
<p>例えば CPU 4 コア、load-threshold = 80% の場合、各段階のしきい値は次のようになります。</p>
<pre>low    = 0.8 × 4 × 1.2 = 3.84
medium = 0.8 × 4 × 1.6 = 5.12
high   = 0.8 × 4 × 2.0 = 6.40</pre>
<p>4 コア環境では、load average が 6.4 を超えた時点で High 判定となります。そのため、ログに表示されている 8.04 は、Pacemaker が明確に「高負荷」と判断した状態であることを意味します。</p>
<h3>New throttle mode (スロットルモードの遷移)</h3>
<p>高負荷が検出されると、Pacemaker はスロットルモードを変更します。</p>
<pre>info: New throttle mode: high load (was medium)</pre>
<p>このログは、CPU 負荷の段階に応じて、Pacemaker が並列実行数を制御するスロットルモードを medium から high に変更したことを示しています。Pacemaker は高負荷時に自らのアクション発行がさらに負荷を悪化させることを防ぐため、ジョブの同時実行数を段階的に制限します。</p>
<p>なお、古いバージョンではスロットルモードがビット表記で表示されることがあります。</p>
<table>
<tbody>
<tr>
<th>ビット値</th>
<th>スロットルモード</th>
</tr>
<tr>
<td>0000</td>
<td>なし</td>
</tr>
<tr>
<td>0001</td>
<td>low</td>
</tr>
<tr>
<td>0010</td>
<td>medium</td>
</tr>
<tr>
<td>0100</td>
<td>high</td>
</tr>
<tr>
<td>1000</td>
<td>extreme</td>
</tr>
</tbody>
</table>
<p>スロットルモードが頻繁に変動している場合は、CPU 負荷が継続的に高い状態にある可能性があります。その場合は ps や top などを用いて高負荷の原因となっているプロセスを特定する必要があります。</p>
<h3>New job limit is 1 の意味</h3>
<pre>debug: Node node1 has high load and supports at most 8 jobs; new job limit 1</pre>
<p>このログは、ノードの高負荷を検知した結果、Pacemaker が同時実行できるジョブ数を制限したことを示しています。</p>
<p>通常時、Pacemaker は CPU コア数 × 2 のジョブを同時に実行できます。例えば 4 コアのノードであれば、デフォルトでは最大 8 ジョブを並列実行できます。負荷の上昇に応じて同時実行数は段階的に引き下げられ、high モード に到達すると最終的に 1 まで縮小されます。</p>
<p>つまりこのログは、Pacemaker がクラスタの安定性を優先し、意図的に並列処理を最小化した状態を示しています。</p>
<h2>動作検証</h2>
<p><code>stress-ng</code> を使用して CPU 負荷を段階的に上げると、スロットルモードがどのように遷移するかを確認できます。ここでは、その挙動をログから読み取ります。</p>
<p>以下のログから分かるように、負荷の上昇に伴いスロットルモードは <code>low → medium → high</code> と段階的に遷移し、それに合わせて job limit が <code>8 → 4 → 2 → 1</code> と減少していきます。<br />
これは Pacemaker が想定どおりに負荷保護を実施していることを示しています。</p>
<pre>debug: Current load is 0.020000 across 4 core(s)
debug: Current load is 0.070000 across 4 core(s)
debug: Current load is 0.240000 across 4 core(s)
debug: Current load is 1.110000 across 4 core(s)
debug: Noticeable CPU load detected: 4.750000
debug: Current load is 4.750000 across 4 core(s)
info: New throttle mode: <strong>low load</strong> (was negligible)
debug: Node node1 has low load and supports at most 8 jobs; <strong>new job limit 4</strong>
info: Moderate CPU load detected: 6.060000
debug: Current load is 6.060000 across 4 core(s)
info: New throttle mode: <strong>medium load</strong> (was low)
debug: Node node1 has medium load and supports at most 8 jobs; <strong>new job limit 2</strong>
notice: High CPU load detected: 8.040000
debug: Current load is 8.040000 across 4 core(s)
info: New throttle mode: <strong>high load</strong> (was medium)
debug: Node node1 has high load and supports at most 8 jobs; <strong>new job limit 1</strong>
notice: High CPU load detected: 9.860000
debug: Current load is 9.860000 across 4 core(s)
notice: High CPU load detected: 11.480000
debug: Current load is 11.480000 across 4 core(s)</pre>
<h2>おわりに</h2>
<p>今回は、Pacemaker の負荷スロットリングの動作について、ログの意味や挙動を中心に解説しました。</p>
<p>「High CPU load detected」や「New throttle mode」といったメッセージは、障害ではなく、クラスタを安定させるための自己防衛機構が正常に動作していることを示しています。ただし、この状態が頻繁に発生する場合は、ノードに継続的な高負荷が発生している可能性があります。CPU 使用率や実行中プロセスを確認し、負荷の原因を特定・改善することが重要です。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>クォーラムデバイスの紹介</title>
		<link>https://www.sraoss.co.jp/tech-blog/pacemaker/quorum-device/</link>
		
		<dc:creator><![CDATA[彭 博 (Bo Peng)]]></dc:creator>
		<pubDate>Thu, 05 Mar 2026 00:44:13 +0000</pubDate>
				<category><![CDATA[Pacemaker]]></category>
		<category><![CDATA[Corosync]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19861</guid>

					<description><![CDATA[前回の記事では、スプリットブレインの発生メカニズムおよび Pacemaker/Corosync におけるその対策について解説しました。 本記事では、スプリットブレイン対策の中でも、2 ノードクラスタにおけるクォーラム確立 ...]]></description>
										<content:encoded><![CDATA[<p><a href="https://www.sraoss.co.jp/tech-blog/pacemaker/split-brain/">前回の記事</a>では、スプリットブレインの発生メカニズムおよび Pacemaker/Corosync におけるその対策について解説しました。</p>
<p>本記事では、スプリットブレイン対策の中でも、2 ノードクラスタにおけるクォーラム確立を支援する<strong>「クォーラムデバイス」</strong>に焦点を当て、その仕組みと基本的な使い方について紹介します。</p>
<p><span id="more-19861"></span></p>
<h2>クォーラムデバイスの仕組み</h2>
<p>クォーラムデバイスは、ノード間通信が切断された際に、どのノード (またはパーティション) がクラスタの運用を継続すべきかを判断するための外部投票ノードです。</p>
<p>偶数ノードで構成されたクラスタでは、ネットワーク分断時に投票数が同数となり、クォーラム (過半数) が成立しないという問題があります。特に2ノードクラスタでは、インターコネクトが切断されると双方が相手を障害と誤認し、スプリットブレイン状態に陥るリスクが高くなります。</p>
<p>このような構成では、クラスタノードとは別に調停役となるクォーラムデバイスを追加することで、クラスタ全体の投票数が奇数となり、過半数による多数決が成立します。その結果、スプリットブレイン発生時でも、どちらのノードがクラスタを継続すべきかを適切に判断できるようになります。</p>
<p>2ノードクラスタの場合、通常は各ノードが1票ずつを持ちますが、クォーラムデバイスを追加すると合計3票となります。ネットワーク分断が発生した際には、クォーラムデバイスの投票を含めた多数決により、過半数を得たノードのみがクラスタ管理を継続できます。これにより、両ノードが同時にリソースを稼働させる事態を防止できます。</p>
<p>偶数ノード構成、特に2ノードクラスタではスプリットブレインのリスクが高いため、クォーラムデバイスの利用が推奨されます。</p>
<h3>クォーラムデバイスを利用したクラスタ構成</h3>
<p>以下は、クォーラムデバイスを利用したクラスタ構成です。</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-19883" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice.png" alt="" width="2560" height="1754" /></p>
<p>クォーラムデバイスを利用する場合、クラスタノードには corosync-qdevice をインストールし、調停役となるサーバには corosync-qnetd をインストールします。corosync-qnetd デーモンはクラスタ外部で動作し、投票を行います。分断時には corosync-qnetd の判定結果に基づき、過半数を得たノードのみがクラスタを維持し、過半数を得られなかったノードはクラスタサービスを停止します。</p>
<h3>corosync-qnetd の判定アルゴリズム</h3>
<p>corosync-qnetd は、以下の判定アルゴリズムに対応しています。</p>
<ul>
<li><strong>ffsplit (fifty-fifty split)</strong>：デフォルトのアルゴリズムです。アクティブなノード数が最も多いパーティションに 1 票を与えます。クラスタが同数（1:1）に分断された場合は、<code>tie_breaker</code> の設定に基づいて投票先を決定します。デフォルトでは、最も小さな node ID を含むパーティションに 1 票を与えます。</li>
<li><strong>lms (last-man-standing)</strong>：corosync-qnetd サーバと通信できるノードが 1 台のみになった場合、そのノードに 1 票を与えます。</li>
</ul>
<h3>クォーラムデバイス構成時の注意点</h3>
<p>クォーラムデバイスを構成する際には、以下の点を考慮する必要があります。</p>
<ul>
<li>クォーラムデバイスはクラスタノードとは別のサーバで動作させる必要があります。既存のクラスタノード上で実行しないでください。</li>
<li>可能であれば、クォーラムデバイスを Corosync が使用するネットワークとは異なるネットワークに配置します。</li>
<li>複数のクラスタで 1 つのクォーラムデバイスを共有できますが、1 つのクラスタに複数のクォーラムデバイスを構成することはできません。</li>
</ul>
<h2>検証環境と前提条件</h2>
<p>本記事では、クォーラムデバイスを利用した 2 ノードクラスタ構成で動作検証を行います。</p>
<p>クラスタ構成およびクォーラムデバイスは以下になります。</p>
<table>
<tbody>
<tr>
<th width="220"></th>
<th width="220">ホスト名</th>
<th width="220">IPアドレス</th>
</tr>
<tr>
<td rowspan="2">クラスタノード</td>
<td>node1</td>
<td>192.168.100.101</td>
</tr>
<tr>
<td>node2</td>
<td>192.168.100.102</td>
</tr>
<tr>
<td>クォーラムデバイスとして動作するノード</td>
<td>qdevice</td>
<td>192.168.100.100</td>
</tr>
</tbody>
</table>
<p>今回は検証目的で RHEL クローン OS の Rocky Linux 環境を用いて検証を行います。Rocky Linux では Red Hat High Availability Add-On 相当のパッケージが highavailability リポジトリに含まれているため、今回はそちらのリポジトリを利用してインストールします。バージョン情報は以下になります。</p>
<table>
<tbody>
<tr>
<th>OS</th>
<td>Rocky Linux 10.1</td>
</tr>
<tr>
<th>Pacemaker</th>
<td>3.0.1</td>
</tr>
<tr>
<th>Corosync</th>
<td>3.1.9</td>
</tr>
<tr>
<th>PCS</th>
<td>0.12.1</td>
</tr>
<tr>
<th>corosync-qdevice</th>
<td>3.0.3</td>
</tr>
<tr>
<th>corosync-qnetd</th>
<td>3.0.3</td>
</tr>
</tbody>
</table>
<p>すべてのクラスタノードおよびクォーラムデバイスとして動作するノードにおいて、<code>/etc/hosts</code> にホスト名と IP アドレスを設定します。</p>
<pre># vi /etc/hosts
(以下を追加)
192.168.100.101 node1
192.168.100.102 node2
192.168.100.100 qdevice
</pre>
<h2>Pacemaker のインストールおよびクラスタの初期設定</h2>
<p>1. Pacemaker をインストールします。</p>
<p>各クラスタノードで highavailability リポジトリを有効にし、Pacemaker 関連パッケージをインストールします。</p>
<pre>(node1、node2 で実行)
# dnf install -y --enablerepo=highavailability pacemaker pcs
</pre>
<p>※ RHEL 環境を利用している場合は、Red Hat 社によって提供される Red Hat High Availability Add-On のパッケージを利用してインストールしてください。詳細については<a href="https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/10/html/configuring_and_managing_high_availability_clusters/installing-cluster-software" target="_blank" rel="noopener">こちら</a>を参照してください。</p>
<p>2. firewalld デーモンが起動している場合は、クラスタ通信に必要なポートを許可するように以下のコマンドを実行します。</p>
<pre>(node1、node2 で実行)
# firewall-cmd --permanent --add-service=high-availability
# <span class="strong strong">firewall-cmd --reload</span></pre>
<p>3. 両ノードで <code>hacluster</code> ユーザのパスワードを設定します。</p>
<pre>(node1、node2で実行)
# passwd hacluster
Changing password for user hacluster.
New password: (haclusterユーザのパスワードを入力)
Retype new password: (haclusterユーザのパスワードを入力)
passwd: all authentication tokens updated successfully.
</pre>
<p>4. 両ノードで以下のコマンドを実行し、pcsd の自動起動を有効化します。</p>
<pre>(node1、node2 で実行)
# systemctl start pcsd.service
# systemctl enable pcsd.service</pre>
<p>5. いずれかのノードからクラスタを構成するノードに対して、<code>hacluster</code> ユーザの認証を行います。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs host auth node1 node2 -u hacluster
Password: (haclusterユーザのパスワードを入力)
node1: Authorized
node2: Authorized
</pre>
<p>6. クラスタを作成します。クラスタの名前を <code>test_cluster</code> とします。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs cluster setup test_cluster node1 addr=192.168.100.101 node2 addr=192.168.100.102
Destroying cluster on hosts: 'node1', 'node2'...
node1: Successfully destroyed cluster
node2: Successfully destroyed cluster
Requesting remove 'pcsd settings' from 'node1', 'node2'
node1: successful removal of the file 'pcsd settings'
node2: successful removal of the file 'pcsd settings'
Sending 'corosync authkey', 'pacemaker authkey' to 'node1', 'node2'
node1: successful distribution of the file 'corosync authkey'
node1: successful distribution of the file 'pacemaker authkey'
node2: successful distribution of the file 'corosync authkey'
node2: successful distribution of the file 'pacemaker authkey'
Sending 'corosync.conf' to 'node1', 'node2'
node1: successful distribution of the file 'corosync.conf'
node2: successful distribution of the file 'corosync.conf'
Cluster has been successfully set up.
</pre>
<p>7. クラスタを起動します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs cluster start --all
</pre>
<p><code>pcs status</code> コマンドを使用して、作成したクラスタのステータスを表示します。node1、node2 が Online になっていることを確認します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs status
Cluster name: test_cluster
...
Node List:
  * Online: [ node1 node2 ]
</pre>
<p>8. クラスタを安全に運用するために、フェンシングの設定が必要になりますが、今回はクォーラムデバイスを検証することを目的としているため、以下のコマンドを実行し、フェンシングを無効にします。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs property set stonith-enabled=false
</pre>
<p>9. 検証用の Dummy リソースを作成します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs resource create Dummy ocf:heartbeat:Dummy
</pre>
<p>リソースが作成されていることを確認します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs status
Cluster name: test_cluster
...
Full List of Resources:
* Dummy (ocf:heartbeat:Dummy): Started node1
</pre>
<p>以上で、Pacemaker クラスタの初期設定は完了です。</p>
<h3>クォーラムデバイスを使わない場合の動作確認</h3>
<p>ここでは、クォーラムデバイスを使用しない状態で、2 ノード間のインターコネクト通信を切断した場合の挙動を確認します。</p>
<p>まず、疑似障害を起こすため、node1 と node2 間のインターコネクト通信を切断します。</p>
<p>しばらく待ってから <code>pcs status</code> コマンドを実行し、クラスタの状態を確認します。すると、両ノードがそれぞれ DC (Designated Controller) として選出され、それぞれのノード上でリソースが起動していることが確認できます。</p>
<pre>(node1 で実行) 
[root@node1 ~]# pcs status
Cluster name: test_cluster
Cluster Summary:
  * Stack: corosync (Pacemaker is running)
  * Current DC: node1 (version 3.0.1-3.el10-b1a23a6) - partition with quorum
...
Node List:
  * Online: [ node1 ]
  * OFFLINE: [ node2 ]

Full List of Resources:
  * Dummy       (ocf:heartbeat:Dummy):   Started node1
</pre>
<pre>(node2 で実行) 
[root@node2 ~]# pcs status
Cluster name: test_cluster
Cluster Summary:
  * Stack: corosync (Pacemaker is running)
  * Current DC: node2 (version 3.0.1-3.el10-b1a23a6) - partition with quorum
...
Node List:
  * Online: [ node2 ]
  * OFFLINE: [ node1 ]

Full List of Resources:
  * Dummy       (ocf:heartbeat:Dummy):   Started node2
</pre>
<p>これは、両ノードが自身を稼働系と誤認識している状態であり、典型的なスプリットブレイン状態です。</p>
<h2>クォーラムデバイスのインストールおよび設定</h2>
<p>ここでは、既存のクラスタ (node1、node2) にクォーラムデバイスを追加し、スプリットブレイン防止について動作検証を通して効果を検証します。</p>
<h3>クォーラムデバイスのインストール</h3>
<p>1. 既存のクラスタノード node1 と node2 に corosync-qdevice をインストールします。</p>
<pre>(node1、node2 で実行)
# dnf install -y --enablerepo=highavailability corosync-qdevice</pre>
<p>2. クォーラムデバイスとして使用されるノード qdevice に pcs および corosync-qnetd をインストールします。</p>
<pre>(qdevice で実行)
[root@qdevice ~]# dnf install -y --enablerepo=highavailability pcs corosync-qnetd</pre>
<p>3. qdevice 上で pcsd サービスを起動し、自動起動の設定を行います。</p>
<pre>(qdevice で実行)
[root@qdevice ~]# systemctl start pcsd.service
[root@qdevice ~]# systemctl enable pcsd.service
</pre>
<p>4. firewalld デーモンが起動している場合は、クラスタで必要なポートを有効化するように以下のコマンドを実行します。</p>
<pre>(qdevice で実行)
[root@qdevice ~]# firewall-cmd --permanent --add-service=high-availability
[root@qdevice ~]# firewall-cmd --reload
</pre>
<h3>クォーラムデバイスの設定</h3>
<p>ここでは、既存のクラスタにクォーラムデバイスを追加する手順を記載します。</p>
<p>1. クォーラムデバイスモデル net を指定し、クォーラムデバイスのセットアップおよび起動を行います。また、システム起動時にクォーラムデバイスが起動するように設定します。</p>
<pre>(qdevice で実行) 
[root@qdevice:~]# pcs qdevice setup model net --enable --start
Quorum device 'net' initialized
quorum device enabled
Starting quorum device...
quorum device started
</pre>
<p>起動後、<code>pcs qdevice status net --full</code> を実行し、クォーラムデバイスの状態を確認します。</p>
<pre>(qdevice で実行)
[root@qdevice ~]# pcs qdevice status net --full
QNetd address:                  *:5403
TLS:                            Supported (client certificate required)
Connected clients:              0
Connected clusters:             0
Maximum send/receive size:      32768/32768 bytes
</pre>
<p>2. クラスタノードの pcs がクォーラムデバイス qdevice にアクセスできるように、<code>hacluster</code> ユーザの認証を行います。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs host auth qdevice -u hacluster
Password: (hacluster ユーザのパスワードを入力)
qdevice: Authorized
</pre>
<p>3. クォーラムデバイスをクラスタに追加します。</p>
<p>クォーラムデバイスを追加する前に、後で比較するために、クォーラムデバイスの現在の設定と状況を確認できます。<br />
このコマンドの出力から、クラスタがクォーラムデバイスを使用しておらず、各ノードの Qdevice メンバーシップのステータスが NR (Not Registered：登録されていない) であることが分かります。</p>
<pre>[root@node1 ~]# pcs quorum config
[root@node1 ~]# pcs quorum status
Quorum information
------------------
Date:            Sun Feb 2 11:39:03 2026
Quorum provider: corosync_votequorum
Nodes:           2
Node ID:         1
Ring ID:         1.1d
Quorate:         Yes

Votequorum information
----------------------
Expected votes:   2
Highest expected: 2
Total votes:      2
Quorum:           1
Flags:            2Node Quorate WaitForAll

Membership information
----------------------
    Nodeid      Votes    Qdevice Name
         1          1    NR      node1 (local)
         2          1    NR      node2
</pre>
<p>以下のコマンドを実行し、クォーラムデバイスをクラスタに追加します。<code>host</code> にクォーラムデバイスとして動作するノードのホスト名、<code>algorithm</code> に使用するアルゴリズム (ffsplit) を指定します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs quorum device add model net host=qdevice algorithm=ffsplit
Setting up qdevice certificates on nodes...
node1: Succeeded
node2: Succeeded
Enabling corosync-qdevice...
node1: not enabling corosync-qdevice: corosync is not enabled
node2: not enabling corosync-qdevice: corosync is not enabled
Sending updated corosync.conf to nodes...
node2: Succeeded
node1: Succeeded
node1: Corosync configuration reloaded
Starting corosync-qdevice...
node2: corosync-qdevice started
node1: corosync-qdevice started
</pre>
<p>上記コマンドを実行後、クォーラムデバイスの設定を確認するには、<code>pcs quorum config</code> を実行します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs quorum config
Device:
  votes: 1
  Model: net
    algorithm: ffsplit
    host: qdevice
</pre>
<p>4. クラスタノード側からクォーラムデバイスの状態を確認します。</p>
<p>クォーラムデバイスをクラスタに追加した後、まずはクラスタノード側から、クォーラムデバイスが正しく認識・動作しているかを確認します。</p>
<pre>(node1 または node2 のいずれかで実行)
# pcs quorum status
Quorum information
------------------
Date:             Sun Feb  2 11:45:38 2026
Quorum provider:  corosync_votequorum
Nodes:            2
Node ID:          1
Ring ID:          1.1d
Quorate:          Yes

Votequorum information
----------------------
Expected votes:   3
Highest expected: 3
Total votes:      3
Quorum:           2  
Flags:            Quorate Qdevice 

Membership information
----------------------
    Nodeid      Votes    Qdevice Name
         1          1    A,V,NMW node1 (local)
         2          1    A,V,NMW node2
         0          1            Qdevice
</pre>
<p>この Membership information は、現在のクォーラム判定に参加しているメンバー (投票者) 一覧を表しています。Qdevice が 1 vote を持つメンバーとして参加していることが分かります。</p>
<p>なお、<code>A,V,NMW</code> は votequorum におけるノード状態フラグであり、それぞれの意味は次のとおりです。</p>
<ul>
<li><strong>A/NA</strong>
<ul>
<li>A (Active)：クォーラムデバイスがそのノードに対して有効な状態</li>
<li>NA (Not Active)：クォーラムデバイスがそのノードに対して無効な状態</li>
</ul>
</li>
<li><strong>V/NV</strong>
<ul>
<li>V (Voting)：クォーラムデバイスがそのノードへ投票を与えている</li>
<li>NV (Not Voting)：クォーラムデバイスがそのノードに投票を与えていない</li>
</ul>
</li>
<li><strong>MW/NMW</strong>
<ul>
<li data-start="369" data-end="440">MW (Master Wins)：master_wins フラグが有効</li>
<li data-start="369" data-end="440">NMW (Not Master Wins)：master_wins フラグが無効 (デフォルト)</li>
</ul>
</li>
</ul>
<p>続いて、<code>pcs quorum device status</code> コマンドを使って、クォーラムデバイスとの接続状態やアルゴリズム設定を確認します。</p>
<pre>(node1 または node2 のいずれかで実行)
[root@node1 ~]# pcs quorum device status
Qdevice information
-------------------
Model:                  Net
Node ID:                1
Configured node list:
      0 Node ID = 1
      1 Node ID = 2
Membership node list:   1, 2

Qdevice-net information
----------------------
Cluster name:           test_cluster
QNetd host:             qdevice:5403
Algorithm:              Fifty-Fifty split
Tie-breaker:            Node with lowest node ID
State:                  Connected
</pre>
<p>Qdevice-net information の結果から、判定アルゴリズムと決定ルールを確認できます。</p>
<ul>
<li><strong>Algorithm: Fifty-Fifty split</strong> は、クラスタが同数に分断された場合（2 ノードクラスタでは 1:1 の分断）に適用される判定アルゴリズムです。</li>
<li><strong>Tie-breaker: Node with lowest node ID</strong> は、分断時に最も小さな node ID を含むパーティションを primary component（quorum を持つ側）として選択する決定ルールを示しています。</li>
</ul>
<p>5. 次に、クォーラムデバイス側で、corosync-qnetd デーモンの状態を確認します。</p>
<p>以下のコマンドを実行します。</p>
<pre>(qdevice サーバで実行)
[root@qdevice:~]# pcs qdevice status net --full
QNetd address:                  *:5403
TLS:                            Supported (client certificate required)
Connected clients:              2
Connected clusters:             1
Maximum send/receive size:      32768/32768 bytes
Cluster "test_cluster":
    Algorithm:          Fifty-Fifty split (KAP Tie-breaker)
    Tie-breaker:        Node with lowest node ID
    Node ID 1:
        Client address:         ::ffff:192.168.100.101:33624
        HB interval:            8000ms
        Configured node list:   1, 2
        Ring ID:                1.1d
        Membership node list:   1, 2
        Heuristics:             Undefined (membership: Undefined, regular: Undefined)
        TLS active:             Yes (client certificate verified)
        Vote:                   No change (ACK)
    Node ID 2:
        Client address:         ::ffff:192.168.100.102:32998
        HB interval:            8000ms
        Configured node list:   1, 2
        Ring ID:                1.1d
        Membership node list:   1, 2
        Heuristics:             Undefined (membership: Undefined, regular: Undefined)
        TLS active:             Yes (client certificate verified)
        Vote:                   ACK (ACK)
</pre>
<p>両ノードとも、同一の Membership node list、正常な ACK 応答となっており、qnetd から見てもクラスタは健全な状態であることが確認できます。</p>
<h2>クォーラムデバイスを使ったクラスタの動作確認</h2>
<p>前の検証では、クォーラムデバイスを使用しない 2 ノードクラスタにおいて、ノード間のネットワークを切断すると、両ノードがそれぞれ <code>DC</code> となり、リソースを起動してしまう (いわゆるスプリットブレイン状態) ことを確認しました。</p>
<p>ここでは、クォーラムデバイスを導入した場合に、同じ障害を発生させたときの挙動がどのように変わるのかを確認します。</p>
<h3>正常時の状態確認</h3>
<p>まずは、ネットワーク切断前の状態を確認します。</p>
<pre>[root@node1 ~]# pcs status
Cluster name: test_cluster
Cluster Summary:
* Stack: corosync (Pacemaker is running)
* Current DC: node1 (version 3.0.1-3.el10-b1a23a6) - partition with quorum
* Last updated: Mon Feb 2 13:51:22 2026 on node1
* Last change: Mon Feb 2 13:36:39 2026 by root via root on node1
* 2 nodes configured
* 1 resource instance configured

Node List:
* Online: [ node1 node2 ]

Full List of Resources:
* Dummy (ocf:heartbeat:Dummy): Started node1

</pre>
<p>Quorum 情報を確認すると、Qdevice が投票に参加していることが分かります。</p>
<pre>[root@node1:~]# pcs quorum status
Quorum information
------------------
Date:             Mon Feb  2 13:55:20 2026
Quorum provider:  corosync_votequorum
Nodes:            2
Node ID:          1
Ring ID:          1.26
Quorate:          Yes

Votequorum information
----------------------
Expected votes:   3
Highest expected: 3
Total votes:      3
Quorum:           2  
Flags:            Quorate Qdevice 

Membership information
----------------------
    Nodeid      Votes    Qdevice Name
         1          1    A,V,NMW node1 (local)
         2          1    A,V,NMW node2
         0          1            Qdevice
</pre>
<h3>ノード間ネットワークの切断</h3>
<p>次に、疑似障害として node1 と node2 間のインターコネクト通信を切断します。（Qdevice との通信は維持された状態）</p>
<h3>障害発生後の状態確認</h3>
<p>node1 と node2 間のネットワークを切断した後、それぞれのノードで <code>pcs status</code> を実行し、クラスタの状態を確認します。</p>
<pre>[root@node1 ~]# pcs status
Cluster name: test_cluster
Cluster Summary:
  * Stack: corosync (Pacemaker is running)
  * Current DC: node1 (version 3.0.1-3.el10-b1a23a6) - partition with quorum
  * Last updated: Mon Feb  2 15:14:59 2026 on node1
  * Last change:  Mon Feb  2 15:14:13 2026 by root via root on node1
  * 2 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node1 ]
  * OFFLINE: [ node2 ]

Full List of Resources:
  * Dummy       (ocf:heartbeat:Dummy):   Started node1
</pre>
<p>node1 は クォーラムデバイスからの投票を含めて quorum を維持しており、引き続き DC として選出され、リソースを起動した状態で稼働しています。</p>
<pre>[root@node2 ~]# pcs status
Cluster name: test_cluster
Cluster Summary:
  * Stack: corosync (Pacemaker is running)
  * Current DC: node2 (version 3.0.1-3.el10-b1a23a6) - partition WITHOUT quorum
  * Last updated: Mon Feb  2 15:15:04 2026 on node2
  * Last change:  Mon Feb  2 15:14:14 2026 by root via root on node1
  * 2 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node2 ]
  * OFFLINE: [ node1 ]

Full List of Resources:
  * Dummy       (ocf:heartbeat:Dummy):   Stopped
</pre>
<p>node2 はクラスタ内では単独ノードとなり、クォーラムを満たせない状態 (partition WITHOUT quorum) となっています。その結果、DC にはなっているものの、quorum を持たないため、リソースは起動されない、という状態になっています。</p>
<h4>クォーラム状態の確認</h4>
<p>次に、node1 側で <code>pcs quorum status</code> を実行し、クォーラム状態を確認します。</p>
<pre>[root@node1 /]# pcs quorum status
Quorum information
------------------
Date:             Mon Feb  2 15:16:14 2026
Quorum provider:  corosync_votequorum
Nodes:            1
Node ID:          1
Ring ID:          1.86
Quorate:          Yes

Votequorum information
----------------------
Expected votes:   3
Highest expected: 3
Total votes:      2
Quorum:           2  
Flags:            Quorate Qdevice 

Membership information
----------------------
    Nodeid      Votes    Qdevice Name
         1          1    A,V,NMW node1 (local)
         0          1            Qdevice
</pre>
<p>この結果から分かる通り、node1 と Qdevice がそれぞれ 1 vote を保持し、合計 2 votes（quorum＝2）となるため、node1 側では quorum が維持されています。クォーラムデバイスは、デフォルト設定では存続しているノードのうち、最も小さな node ID を持つノードを含むパーティションを選択します。今回の構成では node1 が選択され、node2 側は quorum を失う結果となりました。</p>
<h4>ログの確認</h4>
<p>node2 側のログを確認すると、quorum 喪失に伴う挙動が明確に分かります。</p>
<pre>(node2ログ)
Feb 2 15:14:48 node2 pacemaker-controld[4354]: notice: Node node1 state is now lost
Feb 2 15:14:48 node2 corosync[4330]: [QUORUM] This node is within the non-primary component and will NOT provide any services.
</pre>
<p>このログは、このノードは non-primary component (quorum を持たない側) に属しており、サービスを提供してはならない、ことを示しています。</p>
<p>続く Pacemaker のログでも、quorum 喪失によりリソース管理が抑止されていることが分かります。</p>
<pre>(node2ログ)
Feb 2 15:14:49 node2 pacemaker-schedulerd[4353]: warning: Fencing and resource management disabled due to lack of quorum
Feb 2 15:14:49 node2 pacemaker-schedulerd[4353]: notice: Actions: Start Dummy ( node2 ) due to no quorum (blocked)
</pre>
<h2>おわりに</h2>
<p>本記事では、2 ノードクラスタにおけるスプリットブレイン対策として、クォーラムデバイスの仕組みと設定方法、そして実際の動作検証結果について解説しました。</p>
<p>クォーラムデバイスを導入しない場合、ノード間のネットワーク分断時に双方が自身を正当なクラスタと判断し、同時にリソースを起動してしまう可能性があります。一方で、クォーラムデバイスを追加することで投票数が奇数となり、外部の調停役による判定が加わることで、過半数を得た側のみがサービスを継続できるようになります。これにより、2 ノードクラスタ特有のスプリットブレインリスクを大きく低減できます。</p>
<p>特に、コストや設計上の理由から 2 ノード構成を採用せざるを得ない環境や、環境要件や構成上の制約により電源制御を用いたフェンシングを採用しない場合には、クォーラムデバイスは有効な補完策となります。</p>
<p>本記事が、2 ノードクラスタの設計やスプリットブレイン対策を検討されている方の参考になれば幸いです。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pacemaker クラスタのスプリットブレイン対策</title>
		<link>https://www.sraoss.co.jp/tech-blog/pacemaker/split-brain/</link>
		
		<dc:creator><![CDATA[彭 博 (Bo Peng)]]></dc:creator>
		<pubDate>Thu, 05 Mar 2026 00:00:05 +0000</pubDate>
				<category><![CDATA[Pacemaker]]></category>
		<category><![CDATA[Corosync]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=12068</guid>

					<description><![CDATA[システムを安定して稼働させるためには、冗長化構成が不可欠です。冗長化構成を採用することで、稼働系サーバに障害が発生してサービスが停止した場合でも、待機系サーバへ自動的に切り替えることができ、ダウンタイムを最小限に抑えられ ...]]></description>
										<content:encoded><![CDATA[<p>システムを安定して稼働させるためには、冗長化構成が不可欠です。冗長化構成を採用することで、稼働系サーバに障害が発生してサービスが停止した場合でも、待機系サーバへ自動的に切り替えることができ、ダウンタイムを最小限に抑えられます。</p>
<p>一方で、冗長化によって単一障害点は解消できるものの、クラスタノード間の通信が途絶えた場合には「スプリットブレイン」状態に陥るリスクが残ります。スプリットブレインが発生すると、複数のノードが同時に稼働系として振る舞い、IP アドレスの競合やファイルシステムの二重マウントなどが発生する可能性があります。最悪の場合、データ破損といった深刻な障害につながる恐れもあります。</p>
<p>そのため、クラスタ構成を安定して運用するうえで、スプリットブレイン対策は欠かせないポイントです。</p>
<p>本記事では、<a href="https://clusterlabs.org/projects/pacemaker/" target="_blank" rel="noopener">Pacemaker/Corosync</a> クラスタで広く利用されているスプリットブレイン対策の仕組みについて解説します。</p>
<p><span id="more-12068"></span></p>
<h2>スプリットブレインとは</h2>
<p>スプリットブレインとは、クラスタを構成するノード間の通信が途絶えた際に、各ノードが互いの状態を正しく認識できなくなり、複数のノードが同時に稼働系として動作してしまう状態を指します。</p>
<p>通常、クラスタではノード同士が定期的にハートビート通信を行い、相互監視を行っています。しかし、ネットワーク障害などにより通信が分断されると、各ノードは相手を「障害」と誤認する可能性があります。この状態では、同一サービスやリソースが複数ノードで同時に起動されるため、IP  アドレスの競合、ファイルシステムの二重マウント、共有データへの同時書き込み、などが発生する可能性があります。</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-19853" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-scaled.png" alt="" width="2560" height="1051" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-scaled.png 2560w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-300x123.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-1024x421.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-768x315.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-1536x631.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-2048x841.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-304x125.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/splitbrain-282x116.png 282w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></p>
<h2>スプリットブレイン対策</h2>
<p>Pacemaker/Corosync クラスタでは、スプリットブレインを防止するために複数の仕組みが用意されています。</p>
<h3>Stonith によるフェンシング</h3>
<p>STONITH (Shoot The Other Node In The Head) は、クラスタ環境で発生し得るスプリットブレインを防止するためのフェンシング手法です。ノード間の通信が途絶えた場合に、インターコネクト (クラスタ通信用ネットワーク) とは独立した経路を用いて問題のあるノードを強制的に停止または再起動させることで、データ破壊やサービスの二重起動を防ぎます。具体的には、IPMI などのハードウェア制御ボードや、共有ストレージを介した制御を利用して、異常が発生したノードを停止/再起動させます。</p>
<p>具体的には、以下のような仕組みが利用されます。</p>
<ul>
<li style="list-style-type: none;">
<ul>
<li>IPMI などのハードウェア制御ボード</li>
<li>仮想化基盤の API</li>
<li>共有ストレージを利用した制御 (SBD など)</li>
</ul>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-19879" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1.png" alt="" width="2509" height="1781" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1.png 2509w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-300x213.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-1024x727.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-768x545.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-1536x1090.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-2048x1454.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-301x214.png 301w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith1-282x200.png 282w" sizes="auto, (max-width: 2509px) 100vw, 2509px" /><br />
<img loading="lazy" decoding="async" class="aligncenter size-full wp-image-19874" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2.png" alt="" width="2532" height="1497" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2.png 2532w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-300x177.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-1024x605.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-768x454.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-1536x908.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-2048x1211.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-304x180.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/stonith2-282x167.png 282w" sizes="auto, (max-width: 2532px) 100vw, 2532px" /></p>
<p>Pacemaker/Corosync を利用した HA クラスタにおいて、STONITH は最も確実で推奨されるスプリットブレイン対策です。</p>
<h3>リソースの排他制御</h3>
<p>リソースの排他制御により、複数ノードでの同時起動を防止する方法もあります。sfex や VIPCheck は、排他制御を実現するリソースエージェントです。</p>
<p>sfex は共有ディスクを使った排他制御を実現するリソースエージェントとなります。稼働系ノードが共有ディスク上に定期的に書き込みを行うことで排他状態を維持し、ノード間通信が途絶えた場合に、両系が同時に稼働系となることを防止します。</p>
<p>VIPCheck は仮想 IP 状態をチェックすることで排他制御を実現します。共有ディスクが利用できない環境でも、リソースの二重起動を抑止できます。</p>
<p>なお、sfex および VIPCheck は Linux-HA Japan が提供するリソースエージェントであり、RHEL HA Add-on の標準パッケージには含まれていません。</p>
<h3>クォーラムによる多数決制御</h3>
<p>クォーラムとは、クラスタ処理を継続するために必要な最低限の投票数のことを指します。スプリットブレイン対策として広く使われている一般的な手法です。</p>
<p>一般的に、3台以上のノードでクラスタを構成し、過半数を獲得したパーティションのみがクラスタを継続できる仕組みです。過半数を満たさない場合はクォーラムを喪失し、<code>no-quorum-policy</code> の設定に従ってリソース停止やフェンシングが実行されます。</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-19925" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-scaled.png" alt="" width="2560" height="1143" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-scaled.png 2560w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-300x134.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-1024x457.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-768x343.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-1536x686.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-2048x915.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-304x136.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/quorum-282x126.png 282w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></p>
<p>Pacemaker における <code>no-quorum-policy</code> の各設定値の動作は以下の通りです。</p>
<ul>
<li><strong>stop (デフォルト)</strong><br />
クォーラムを喪失したノード上のすべてのリソースを停止します。</li>
<li><strong>freeze</strong><br />
現在動作しているリソースはそのまま維持しますが、新規起動や再配置は行いません。</li>
<li><strong>ignore</strong><br />
クォーラム喪失を無視し、通常どおりリソース管理を継続します。</li>
<li><strong>demote</strong><br />
Master/Slave (Promotable) リソースが存在する場合、Master を Slave に降格します。</li>
<li><strong>suicide</strong><br />
クォーラムを喪失したノードをフェンシングします。</li>
</ul>
<h3></h3>
<h3>クォーラムデバイス</h3>
<p>クォーラムデバイスは、ノード間通信が切断された際に、どのノード (またはパーティション) がクラスタの運用を継続すべきかを判断するための外部投票ノードです。特に偶数ノードで構成されたクラスタでは、ネットワーク分断時に投票数が同数となり、クォーラム (過半数) が成立しないという問題があります。なかでも2ノードクラスタでは、インターコネクトが切断されると双方が相手を障害と誤認し、スプリットブレイン状態に陥るリスクが高まります。</p>
<p>このような構成では、クラスタノードとは別に調停役となるクォーラムデバイスを追加することで、クラスタ全体の投票数が奇数となり、過半数による多数決が成立します。その結果、スプリットブレイン発生時でも、どちらのノードがクラスタを継続すべきかを適切に判断できるようになります。</p>
<p>2ノードクラスタの場合、通常は各ノードが1票ずつを持ちますが、クォーラムデバイスを追加すると合計3票となります。ネットワーク分断が発生した際には、クォーラムデバイスの投票を含めた多数決により、過半数を得たノードのみがクラスタ管理を継続できます。これにより、両ノードが同時にリソースを稼働させる事態を防止できます。</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-19865" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-scaled.png" alt="" width="2560" height="1754" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-scaled.png 2560w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-300x206.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-1024x701.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-768x526.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-1536x1052.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-2048x1403.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-304x208.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/qdevice-282x193.png 282w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></p>
<p>クォーラムデバイスを利用する場合、クラスタノードには corosync-qdevice をインストールし、調停役となるサーバには corosync-qnetd をインストールします。corosync-qnetd デーモンはクラスタ外部で動作し、投票を行います。分断時には corosync-qnetd の判定結果に基づき、過半数を得たノードのみがクラスタを維持し、過半数を得られなかったノードはクラスタサービスを停止します。</p>
<p>偶数ノード構成、特に2ノードクラスタではスプリットブレインのリスクが高いため、クォーラムデバイスの利用が推奨されます。</p>
<p>クォーラムデバイスの具体的な設定方法や、ネットワーク分断時の挙動を含む詳細な動作確認については、<a href="https://www.sraoss.co.jp/tech-blog/pacemaker/quorum-device/">こちらの記事</a>にて詳しく解説していますので、あわせてご参照ください。</p>
<h2>おわりに</h2>
<p>本記事では、スプリットブレイン対策として広く利用される以下の仕組みについて解説しました。</p>
<ul>
<li>STONITH によるフェンシング</li>
<li>リソースの排他制御</li>
<li>クォーラムによる多数決制御</li>
<li>クォーラムデバイス</li>
</ul>
<p>Pacemaker には多数のフェンスエージェントが用意されており、物理サーバ、仮想化基盤、共有ディスク環境など、それぞれの構成に応じたフェンシング方式を選択できます。HA クラスタにおいては、フェンシングの実装が最も確実なスプリットブレイン対策といえます。</p>
<p>一方で、環境要件や構成上の制約により電源制御を用いたフェンシングを採用しない場合には、クォーラム制御やクォーラムデバイスの利用によって多数決の仕組みを補強する方法があります。特に2ノードクラスタでは、クォーラムデバイスを追加することで投票数を奇数化し、分断時の判断を明確にできます。</p>
<p>HA クラスタでは、冗長化するだけでは不十分で、障害時の挙動まで考えた設計が欠かせません。本記事が、より安全で堅牢なクラスタ構築の参考になれば幸いです。</li>
</ul>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Apache Kafka の Idempotent Producer について</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/idempotent-producer/</link>
		
		<dc:creator><![CDATA[奥井 一暁 (Kazuaki Okui)]]></dc:creator>
		<pubDate>Fri, 19 Dec 2025 01:56:31 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[Apache Kafka]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19112</guid>

					<description><![CDATA[はじめに この記事は SRA Advent Calendar 2025 の20日目の記事です。 Apache Kafka（以下 Kafka）には送達保証のための機能がいくつかあります。 この記事ではその中でも送達が重複す ...]]></description>
										<content:encoded><![CDATA[<h2 id="%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB" class="code-line" dir="auto" data-line="13">はじめに</h2>
<p>この記事は <a href="https://qiita.com/advent-calendar/2025/sra" data-href="https://qiita.com/advent-calendar/2025/sra" target="_blank" rel="noopener">SRA Advent Calendar 2025</a> の20日目の記事です。</p>
<p class="code-line" dir="auto" data-line="16">Apache Kafka（以下 Kafka）には送達保証のための機能がいくつかあります。 この記事ではその中でも送達が重複するのを防止するための機能である Idempotent Producer について解説します。</p>
<p class="code-line" dir="auto" data-line="19">Idempotent Producer は Kafka のバージョン 0.11.0.0 からある機能です。この記事ではバージョン 4.1.0 を元に解説します。</p>
<p><span id="more-19112"></span></p>
<h2 id="kafka-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6" class="code-line" dir="auto" data-line="23">Kafka について</h2>
<p class="code-line" dir="auto" data-line="25">Kafka はストリーミング処理を実現するための OSS です。</p>
<p class="code-line" dir="auto" data-line="27">Kafka では Producer と呼ばれるクライアントが Broker と呼ばれるサーバにデータを送信します。Broker は複数台で Kafka クラスタを構成します。Kafka ではやり取りする一つ一つのデータを Message と呼びます。 そして Consumer と呼ばれるクライアントが Broker からデータを読み出し処理、活用します。</p>
<p dir="auto" data-line="29"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19114" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-1024x334.png" alt="" width="1024" height="334" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-1024x334.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-300x98.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-768x250.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-1536x500.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-304x99.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-282x92.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5.png 1817w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="34">今回紹介する Idempotent Producer は Broker に重複した Message が送られてきた時にそれを排除する機能です。 ではどのように重複は発生し、またそれはどのように排除されるのでしょうか。</p>
<h2 id="producer-%E3%81%AE%E8%87%AA%E5%8B%95%E3%83%AA%E3%83%88%E3%83%A9%E3%82%A4%E6%A9%9F%E8%83%BD" class="code-line" dir="auto" data-line="37">Producer の自動リトライ機能</h2>
<p class="code-line" dir="auto" data-line="38">Producer から Broker に送られる Message に重複が発生するのは Producer の自動リトライ機能によるものです。まずこちらについて説明します。</p>
<p class="code-line" dir="auto" data-line="40">Producer は Message を送ったあと Broker 側から送信が成功したかについての応答として Ack を受け取ります。この Ack をもとに Producer 側で判断して自動で Message 送信をリトライするのが自動リトライ機能です。 以下の図では送信の失敗を正しく検知し再送しています。このように自動リトライ機能は Message を確実に送るために重要な機能です。</p>
<p dir="auto" data-line="40"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19182" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-1024x567.png" alt="" width="1024" height="567" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-1024x567.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-300x166.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-768x425.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-304x168.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-282x156.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8.png 1129w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="45">自動リトライ機能は Producer の <code>retries</code> という設定値によって制御できます。 送信失敗時、Producer はこの値の回数だけ再送を試みます（0に設定すると自動再送を行いません）。ただし致命的なエラーが起こった時や <code>delivery.timeout.ms</code> というタイムアウト超過時などはそれ以上再送しません。 その場合はユーザー処理で再送することになりますが、そのような再送は Producer による自動リトライではないので区別されます。</p>
<p class="code-line" dir="auto" data-line="50">さて、以上が自動リトライ機能の概要ですが、この仕組みでは以下の図のように送信には成功したのに Ack が受け取れず再送してしまう可能性があります。重複はこのようにして発生します。</p>
<p dir="auto" data-line="50"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19184" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-1024x551.png" alt="" width="1024" height="551" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-1024x551.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-300x161.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-768x413.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-304x164.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-282x152.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3.png 1136w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h2 id="idempotent-producer" class="code-line" dir="auto" data-line="54">Idempotent Producer（重複排除機能付きの Producer）</h2>
<p class="code-line" dir="auto" data-line="55">自動リトライによって Message が重複して記録されてしまうのを防ぐのが Idempotent Producer の機能です。次はこちらについて説明します。</p>
<p class="code-line" dir="auto" data-line="57">この機能では Producer は各 Message に1ずつ増加するシーケンス番号を自動で割り当て、Producer ID とともに送信します。 こうすることで Broker 側では、同じ Producer から同じ Message が来たことを検知します。 以下の図のように、Broker はそれを検知した場合重複している Message を Broker 側に記録しません。 さらに、これだけでは Producer は送信が成功したか分からず再送し続けてしまうため、Broker 側は送信成功の Ack を返します。こうすることで Broker 側では Message は重複しませんし、Producer 側で再送し続けることもありません。</p>
<p dir="auto" data-line="57"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19185" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-1024x542.png" alt="" width="1024" height="542" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-1024x542.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-300x159.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-768x407.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-304x161.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-282x149.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6.png 1126w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="67">Idempotent Producer の重複排除で注意すべきは、検知できるのは自動リトライによる問題という点です。例えば「Producer に障害があって再起動した」という場合は元の Producer とは別の Producer として Broker は認識するので重複があっても気付けません。 また、「自動リトライでは送りきれなかったのでユーザー処理で再送する」という場合も元の Message とは別の Message として Broker は認識するので重複に気付けません。</p>
<div>
<div>またシーケンス番号がついていることによって、重複だけでなく Message を記録する順番も Broker は確認することができます。Producer では送信リクエストを同時に複数送ることができるため、ネットワークの問題などで送信リクエストが届く順番が変わってしまうというのが順番が入れかわる典型的なケースです。 Broker では上記の重複確認を行った上で、送られてきた Message のシーケンス番号が順番通りか（直前に記録したシーケンス番号+1と等しいか）確認します。順番通りでない場合は OUT_OF_ORDER_SEQUENCE_NUMBER というエラーによって Producer 側に通知します。この場合、他の送信リクエストを追い抜いてしまっただけという可能性があるので Producer は自動で Message を再送します。追い抜いてしまったのではなく一部の Message が送信失敗してシーケンス番号が飛んでしまったという場合も考えられますが、その場合は Producer、Broker 双方でシーケンス番号をリセットして再送します。</div>
</div>
<div></div>
<div></div>
<p class="code-line" dir="auto" data-line="70">また Idempotent Producer を有効にするには設定値が以下の条件を満たしている必要があります。デフォルトの設定ではこれらは満たされているので、Idempotent Producer はデフォルトで有効です。</p>
<table class="code-line" dir="auto" data-line="70">
<thead class="code-line" dir="auto" data-line="70">
<tr class="code-line" dir="auto" data-line="70">
<th>パラメータ</th>
<th>条件</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="72">
<tr class="code-line" dir="auto" data-line="72">
<td>enable.idempotence</td>
<td>true</td>
<td>Idempotent Producer の有効化設定です。</td>
</tr>
<tr class="code-line" dir="auto" data-line="73">
<td>max.in.flight.requests.per.connection</td>
<td>5以下</td>
<td>Producer では Message の送信リクエストを<br />
同時に複数送ることができます。<br />
同時送信数を決めるのがこのパラメータです。<br />
Idempotent Producer では<br />
実装上5までしか対応していません。</td>
</tr>
<tr class="code-line" dir="auto" data-line="74">
<td>retries</td>
<td>1以上</td>
<td>0だと再送をしないので1以上にします。</td>
</tr>
<tr class="code-line code-active-line" dir="auto" data-line="75">
<td>acks</td>
<td>all</td>
<td>Broker でデータの複製が適切にされた状態を<br />
保証することで重複検知を正しく行います。</td>
</tr>
</tbody>
</table>
<h2 id="%E9%87%8D%E8%A4%87%E6%8E%92%E9%99%A4%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89" class="code-line" dir="auto" data-line="81">重複排除のソースコード</h2>
<p class="code-line" dir="auto" data-line="84">最後に、Message の重複を検知し排除している部分を Kafka 4.1.0 のソースコードで見てみましょう。 重複の確認は <a href="https://github.com/apache/kafka/blob/4.1.0/storage/src/main/java/org/apache/kafka/storage/internals/log/UnifiedLog.java#L1081" data-href="https://github.com/apache/kafka/blob/4.1.0/storage/src/main/java/org/apache/kafka/storage/internals/log/UnifiedLog.java#L1081" target="_blank" rel="noopener">UnifiedLog の append() メソッド</a>内で行っています。このメソッドは送られてきた Message の記録をし、 記録の結果（メソッド内では appendInfo という名前）を返すメソッドです。以下はそこからの抜粋です。</p>
<pre><code class="code-line" dir="auto" data-line="83">// now that we have valid records, offsets assigned, and timestamps updated, we need to
// validate the idempotent/transactional state of the producers and collect some metadata
AnalyzeAndValidateProducerStateResult result = analyzeAndValidateProducerState(
        logOffsetMetadata, validRecords, origin, verificationGuard);

if (result.maybeDuplicate.isPresent()) {
    BatchMetadata duplicate = result.maybeDuplicate.get();
    appendInfo.setFirstOffset(duplicate.firstOffset());
    appendInfo.setLastOffset(duplicate.lastOffset);
    appendInfo.setLogAppendTime(duplicate.timestamp);
    appendInfo.setLogStartOffset(logStartOffset);
} else {
    // Append the records, and increment the local log end offset immediately after the append because a
</code></pre>
<p class="code-line" dir="auto" data-line="103">analyzeAndValidateProducerState() メソッド内で重複の確認をしており、その結果を result として受け取っています。その結果で result.maybeDuplicate.isPresent() が True だと重複があることが分かります。続く if 文では重複があるか判定していますが、重複がない場合は else 節に存在する Message 記録の処理が行われ、appendInfo に値がセットされます。 重複がある場合は else 節に入らないため Message の記録は行いません。これによって重複は排除されます。また、記録はしませんが appendInfo に値をセットし正常に Message の記録が行われたときと同じ状態にします。このようにすることで Producer には正常に Message が記録されていることが伝わります。</p>
<h2 id="%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB" class="code-line" dir="auto" data-line="107">おわりに</h2>
<p class="code-line" dir="auto" data-line="109">Idempotent Producer の仕組みについて解説しました。 重複を排除するというありがたい機能なので、仕組みを理解し適切に活用しましょう。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PostgreSQL 18 に関する技術情報</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgsql/18-0/</link>
		
		<dc:creator><![CDATA[データベース技術グループ]]></dc:creator>
		<pubDate>Fri, 07 Nov 2025 01:27:49 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[PostgreSQL 18]]></category>
		<category><![CDATA[アップデート]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=18863</guid>

					<description><![CDATA[このページでは PostgreSQL 18（2025/9/25リリース） に関する技術情報をお届けします。 本ドキュメントは PostgreSQL のリリースノートを元に弊社で解説を加えたものです。 バージョン18 の新 ...]]></description>
										<content:encoded><![CDATA[<p>このページでは PostgreSQL 18（2025/9/25リリース） に関する技術情報をお届けします。<br />
本ドキュメントは PostgreSQL のリリースノートを元に弊社で解説を加えたものです。<br />
バージョン18 の新機能については「<a href="/tech-blog/pgsql/pg18report/">PostgreSQL 18 検証報告</a>」も参照してください。</p>
<p><span id="more-18863"></span></p>
<h3>バージョン18の主要な拡張</h3>
<p>PostgreSQL 18 の主な拡張点としては以下があります。</p>
<ul>
<li>非同期 I/O</li>
<li>B-tree インデックスのスキップスキャン</li>
<li>プランナ改善（WHERE 句内に OR 条件がある場合の最適化、ほか）</li>
<li>GIN インデックスの並列作成</li>
<li>大量のテーブルアクセス時のロック処理の改善</li>
<li>組み込み照合順序 pg_unicode_fast</li>
<li>メジャーバージョンアップ時のプランナ統計情報の移行・チェック処理の並列化オプション/&#8211;swap オプションの追加</li>
<li>仮想生成列の追加</li>
<li>更新系 DML の RETURNING 句へ OLD, NEW の追加</li>
<li>UUID v7 関数の追加</li>
<li>非決定論的な照合順序利用時のLIKE句のサポート</li>
<li>CASEFOLD 関数の追加</li>
<li>各種制約の追加（WITHOUT OVERLAPS、ほか）</li>
<li>ラージオブジェクトに対するデフォルト権限設定のサポート</li>
<li>TLS v1.3 暗号スイートの追加</li>
<li>postgres_fdw、dblink への SCRAM 認証のパススルーオプションの追加</li>
<li>プランナ統計情報のダンプ／リストア</li>
<li>EXPLAIN 文の強化</li>
<li>pg_stat_all_tables への VACUUM、ANALYZE 総実行時間の追加</li>
<li>接続単位での I/O・WAL 利用量の取得</li>
<li>論理レプリケーション時の書き込み衝突の情報詳細化</li>
</ul>
<h3>バージョン18への移行/互換性のない変更点</h3>
<ol>
<li>initdbがデフォルトでチェックサム有効になりました。  (Greg Sabino Mullane) (18)</li>
<p>
これを無効にするための新たなオプション --no-data-checksums が追加されました。pg_upgrade を使う場合に、新旧データベースクラスタでチェックサムの有無を一致させるため、チェックサム無効の旧データベースクラスタに本オプションを指定する必要があります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=04bec894a04">&#167;</a></small></p>
<li>タイムゾーン省略形（GMT、JSTなど）の処理が変更されました。  (Tom Lane) (18)</li>
<p>
日付時刻データの処理に際して、timezone_abbreviations設定よりも、IANA時間帯データベース（tzdata）に基づく現在セッションのタイムゾーンの省略形を優先するようになりました。これまでは timezone_abbreviations設定を優先して、解釈が行なわれていました。
</p>
<p>
タイムゾーン省略形を含んだ日付時刻をあらわす文字列を読み込ませるときに、バージョン間で結果の差異が発生する可能性があります。
</p>
<pre>
(実行例)
17.x では「ERROR:  invalid input syntax for type timestamp with time zone」となる

db1=# SET timezone TO 'Asia/Tokyo';
db1=# SELECT 'Wed Jan 01 00:00:00 1000 LMT'::timestamptz;
         timestamptz
------------------------------
 1000-01-01 00:00:00+09:18:59
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d7674c9fa">&#167;</a></small></p>
<li>MD5による認証およびパスワード格納の方式が非推奨になりました。  (Nathan Bossart) (18)</li>
<p>
md5方式はバージョン18.x 時点では使用可能ですが、今後のメジャーバージョンで廃止される予定です。
</p>
<p>
md5方式を使う場合、CREATE ROLEやALTER ROLE などのコマンドでWARNING が出力されるようになります。これは新たな設定項目md5_password_warningsをoff にすることで抑止できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=db6a4a985">&#167;</a></small></p>
<li>VACUUMとANALYZEが継承子テーブルを処理するようになりました。  (Michael Harris) (18)</li>
<p>
新たなオプションONLYを使うと従来の動作（子テーブルについては処理しない）にできます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=62ddf7ee9">&#167;</a></small></p>
<li>CSVファイルを読むときに、COPY FROM が「\.」をファイル終端マーカーと扱わないようになりました。  (Daniel Verite, Tom Lane) (18)</li>
<p>
psqlでSTDINからCSVファイルを読むときには、引続きファイル終端マーカー（EOFマーカー）として扱います。以前のバージョンのpsqlからPostgreSQL 18のサーバに接続して「\copy」を実行するときに非互換の問題に遭遇するかもしれません。
</p>
<p>
加えて、本バージョンから「\.」を単独行として書くことが必須となりました。以前は行末に書く方法が認められていました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=770233748">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=da8a4c166">&#167;</a></small></p>
<li>UNLOGGEDパーティションテーブルが禁止されました。  (Michael Paquier) (18)</li>
<p>
以前は ALTER TABLE SET [UN]LOGGED を実行できましたが何の効果もありませんでした。パーティションテーブル（親テーブル）自体はデータを持ちませんし、パーティション（子テーブル）が自動でUNLOGGEDになることもありませんでした。
</p>
<p>
これからはパーティションテーブルをUNLOGGEDにするコマンドはエラーになります。パーティションをUNLOGGEDにすることは引続き可能です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e2bab2d79">&#167;</a></small></p>
<li>AFTERトリガを、トリガイベントがキューに入った時点で有効なロールで、実行するようになりました。  (Laurenz Albe) (18)</li>
<p>
これまでは、トリガ実行時（例えばCOMMIT時）に有効なロールで実行されました。特に、トリガイベント発生時とトリガ実行時の間でロールの変更が有る場合に、振る舞いが変わります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=01463e1cc">&#167;</a></small></p>
<li>GRANT/REVOKEコマンドで RULE権限が廃止されました。  (Fujii Masao) (18)</li>
<p>
機能としてはPostgreSQL 8.2の時点で無効になっていて、RULE権限をGRANT/REVOKEしても何の効果もありませんでした。テーブルにRULE を付与できるのは所有者とスーパーユーザのみです。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fefa76f70">&#167;</a></small></p>
<li>システムビューpg_backend_memory_contextsのparent列が削除されました。  (Melih Mutlu) (18)</li>
<p>
pg_backend_memory_contextsに親コンテキストの連なりを示すpath列が加わったため、これは不要になりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f0d112759">&#167;</a></small></p>
<li>システムビューpg_backend_memory_contextsのlevel列と、pg_log_backend_memory_contexts() 関数で、番号が1から始まるようになりました。  (Melih Mutlu, Atsushi Torikoshi, David Rowley, Fujii Masao) (18)</li>
<p>
これまでは0から始まる番号でした。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=32d3ed816">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d9e03864b">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=706cbed35">&#167;</a></small></p>
<li>全文検索で設定ファイルや辞書ファイルを読むときに、常にlibc を使うのではなく、データベースクラスタのデフォルトの照合順序プロバイダを使うようになりました。  (Peter Eisentraut) (18)</li>
<p>
libc以外の照合順序プロバイダ（icu やbuiltin）をデフォルトとしているデータベースクラスタでは、いくつかの全文検索の関数とpg_trgm拡張でLC_CTYPEによる文字の処理が変わってきます。
</p>
<p>
pg_upgradeで本バージョンにアップグレードする場合、全文検索やpg_trgmに関するインデックスは、バージョンアップ後に全て再作成することが推奨されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fb1a18810f0">&#167;</a></small></p>
</ol>
<h3>変更点</h3>
<h4>サーバ</h4>
<h5>オプティマイザ</h5>
<ol>
<li>不要なテーブルの自己結合が自動的に除去されるようになりました。  (Andrey Lepikhov, Alexander Kuzmenkov, Alexander Korotkov, Alena Rybakina) (18)</li>
<p>
この最適化は、設定パラメータenable_self_join_eliminationを使用して無効にすることができます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fc069a3a6">&#167;</a></small></p>
<li>WHERE句における一部のIN (VALUES ...)を、オプティマイザがより適切な統計情報を活用できるようにx = ANY...へ変換するようになりました。  (Alena Rybakina, Andrei Lepikhov) (18)</li>
<p>
この変換は特定の条件（定数値で構成され、1列のみを含む VALUES リストなど）に該当する場合に限り適用されます。
</p>
<pre>
（実行例）
db1=# CREATE TABLE tbl (a INT);
db1=# INSERT INTO tbl VALUES (2);
db1=# EXPLAIN SELECT * FROM tbl WHERE a IN (VALUES (1), (2), (3));
                     QUERY PLAN
-----------------------------------------------------
 Seq Scan on tbl  (cost=0.00..45.06 rows=38 width=4)
   Filter: (a = ANY ('{1,2,3}'::integer[]))
(2 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c0962a113">&#167;</a></small></p>
<li>OR句が配列に変換され、インデックス処理が高速化されるようになりました。  (Alexander Korotkov, Andrey Lepikhov) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ae4569161">&#167;</a></small></p>
<li>INTERSECT、EXCEPT、ウィンドウ集約関数、ビューの列の別名の処理がそれぞれ高速化されました。  (Tom Lane, David Rowley) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=52c707483">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=276279295">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8d96f57d5">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=908a96861">&#167;</a></small></p>
<li>SELECT DISTINCTにおいて、ソート処理を回避するためにキーの順序が内部的に並び替えられるようになりました。  (Richard Guo) (18)</li>
<p>
この最適化は、enable_distinct_reorderingを使って無効にすることもできます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a8ccf4e93">&#167;</a></small></p>
<li>他の列に関数的に従属する列は、GROUP BY句から自動的に除外されるようになりました。  (Zhang Mingli, Jian He, David Rowley) (18)</li>
<p>
GROUP BY句に、あるテーブルの一意インデックスを構成するすべての列と、それ以外の列が含まれている場合、その「それ以外の列」は冗長とみなされ、グルーピングの対象から除外されるようになりました。この動作は、これまでも 遅延不可な主キーに対しては適用されていましたが、今回からより広く適用されるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bd10ec529">&#167;</a></small></p>
<li>GROUPING SETSの一部のHAVING句が、WHERE句にプッシュダウンされるようになりました。  (Richard Guo) (18)</li>
<p>
これにより、より早い段階での行のフィルタリングが可能になりました。また、本リリースではGROUPING SETSを使用した一部のクエリで、以前は誤った結果が返されることがありましたが、修正されました。特に、GROUPING SETSとDISTINCT ONの併用、あるいはORDER BYとの併用において、NULLの扱いに起因する誤った結果が発生していた問題が解消されています。
</p>
<pre>
（実行例）

(17.xでは以下)
db1=# SELECT DISTINCT ON (a, b) a, b
FROM (VALUES (1, 1), (2, 2)) AS t(a, b) WHERE a = b
GROUP BY GROUPING SETS ((a, b), (a));
 a | b
---+---
 1 | 1
 2 | 2
(2 rows)

(18では以下）
 a | b
---+---
 1 | 1
 1 |
 2 | 2
 2 |
(4 rows)

(17.xでは以下。ORDER BYでNULLを含む列の扱いが不十分で、誤った順序が返される)
db1=# SELECT a, b FROM (VALUES (1, 1),(2, 2)) AS t(a, b) WHERE a = b
GROUP BY CUBE (a, (a, b)) ORDER BY b, a;
 a | b
---+---
 1 | 1
 1 | 1
 1 |
 2 | 2
 2 | 2
 2 |
   |
(7 rows)

(18では以下）
 a | b
---+---
 1 | 1
 1 | 1
 2 | 2
 2 | 2
 1 |
 2 |
   |
(7 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=67a54b9e8">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=247dea89f">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f5050f795">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cc5d98525">&#167;</a></small></p>
<li>generate_series()におけるnumeric型やtimestamp型の値に対する行数の見積もりが改善されました。  (David Rowley, Song Jinzhou) (18)</li>
<p><p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=036bdcec9">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=97173536e">&#167;</a>これまでtimestamp型やnumeric型では、たとえ入力が定数であっても常にデフォルトの1000行と見積もられていましたが、本リリース以降は入力値に基づいて実際の行数を正確に推定できるようになりました。
</p>
<p></small></p>
<li>オプティマイザがRight Semi Joinプランを使用できるようになりました。  (Richard Guo) (18)</li>
<p>
セミジョインは、少なくとも1件の一致が存在するかどうかを判定する目的で使用されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=aa86129e1">&#167;</a></small></p>
<li>マージ結合でインクリメンタルソートが使用できるようになりました。  (Richard Guo) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=828e94c9d">&#167;</a></small></p>
<li>多数のパーティションにアクセスする問合せの実行プラン作成において、効率が改善されました。  (Ashutosh Bapat, Yuya Watari, David Rowley) (18)</li>
<p>
これまではプラン作成に際して同値クラスの導出句が線形探索されており、対象のテーブル数やパーティション数が多い問合せでプラン作成時間が増大しました。
</p>
<p>
探索にハッシュテーブルを利用する等の高速化が適用されました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=88f55bc97">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d69d45a5a">&#167;</a></small></p>
<li>より多くのケースでパーティション単位の結合ができるようになりました。また、メモリ使用量も削減されました。  (Richard Guo, Tom Lane, Ashutosh Bapat) (18)</li>
<p>
これまでは、パーティション単位の結合（partitionwise join）を使用できるかどうかの判断が、問合せで明示的に記述された結合条件に基づいて行われていて、実際は可能であるのに適用されないことがありました。これからは、同値クラスに基づき判断されます。
</p>
<p>
また、パーティションの組み合わせごとの結合で確保されるメモリを各結合の完了後に解放するようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9b282a935">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=513f4472a">&#167;</a></small></p>
<li>パーティションテーブルへの問合せで、プラン作成時のコスト推定が改善されました。  (Nikita Malakhov, Andrei Lepikhov) (18)</li>
<p>
結果として、これまでよりもIndex Scan、および、パラメータ化Nested Loopが選択されやすくなっています。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fae535da0">&#167;</a></small></p>
<li>SQL言語の関数のプランキャッシュが改善されました。  (Alexander Pyhalov, Tom Lane) (18)</li>
<p>
これまでは、SQL関数内で作成した実行プランは問合せが終了すると全て破棄されていました。今回の変更で、SQL関数に対してもPostgreSQLのプランキャッシュ基盤を利用できるようになりました。
</p>
<p>
付随して、SQL関数の戻り値は関数内の最後の文によって生成されるという規則が厳格化されました。これまでは最後のSQL文が「DO INSTEAD NOTHING」で実行されなかった場合に手前の問い合わせ結果が返されることがありましたが、この挙動は廃止されました。
</p>
<p>
また、下記のように関数内でDDL（データ定義言語）を実行すると、関数内の後続のSQL文に反映されるようになりました。
</p>
<pre>
db1=# CREATE TEMP TABLE t14 (x int); -- 関数定義用に1回だけ事前作成
db1=# CREATE FUNCTION f14() RETURNS void LANGUAGE SQL AS $$
        CREATE TEMP TABLE IF NOT EXISTS t14 (x int);
        INSERT INTO t14 VALUES (1); $$;
（→ この関数はバージョン17.x以前だと実行できない）
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0dca5d68d">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=09b07c295">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e22253467">&#167;</a></small></p>
<li>プランナで機能無効化の処理が改善されました。  (Robert Haas) (18)</li>
<p>
enable_seqscanなど、実行プランで特定方式を有効/無効化する設定パラメータ群は、これまでは無効化する方式のプランノードに大きなコスト値(100億)を加算して、選択されないようにしていました。
</p>
<p>
本改善でコスト値を加えるのではなく無効であることを別途管理するようになりました。これにより巨大なコスト値が生じる実行プランでも無効化指定が確実に働きます。
</p>
</ol>
<h5>インデックス</h5>
<ol>
<li>btreeインデックスのスキップスキャンに対応しました。  (Peter Geoghegan) (18)</li>
<p>
スキップスキャンは、複数列のインデックスを範囲検索する際に、範囲全体のリーフページを走査するのではなく、不要な領域を飛ばして効率的に検索する手法です。
</p>
<p>
これにより、インデックスに含まれる最初の方の列に検索条件がなくて、以降の列に有用な検索条件がある場合に、インデックスが使われやすくなります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=92fe23d93">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8a510275d">&#167;</a></small></p>
<li>パーティションキーやマテリアライズドビューの同時リフレッシュ用に、btree以外のアクセスメソッドのユニークインデックスが使用可能になりました。  (Mark Dilger) (18)</li>
<p>
引続き、使用するインデックスタイプは等価性（「=」演算子）をサポートしていなければなりません。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f278e1fe3">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9d6db8bec">&#167;</a></small></p>
<li>GINインデックスの並列作成が可能になりました。  (Tomas Vondra, Matthias van de Meent) (18)</li>
<p>
17.xまでは並列作成に対応していたのはbtreeとBRINインデックスのみでした。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8492feb98">&#167;</a></small></p>
<li>GiSTおよびbtreeインデックスアクセスメソッドにソートサポート関数が追加されて、範囲型に対するインデックス作成が高速化されました。  (Bernd Helmle) (18)</li>
<p>
特に範囲型へのGiSTインデックス作成で性能向上が期待できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e9e7b6604">&#167;</a></small></p>
</ol>
<h5>性能一般</h5>
<ol>
<li>非同期I/Oサブシステムが追加されました。  (Andres Freund, Thomas Munro, Nazir Bilal Yavuz, Melanie Plageman) (18)</li>
<p>
これにより、バックエンドは複数の読み取り要求をキューにまとめて処理できるようになり、シーケンシャルスキャン、ビットマップヒープスキャン、バキューム処理などがより効率的に実行できます。この機能は新たな設定パラメータio_methodによりデフォルトで有効化されており、制御用にio_combine_limitおよびio_max_combine_limitが追加されました。
</p>
<p>
また、fadvise()システムコールをサポートしないシステムであってもeffective_io_concurrencyやmaintenance_io_concurrencyに0より大きい値を設定して効果を得ることができるようになりました。
</p>
<p>
新たなシステムビューpg_aiosから非同期I/Oに使用されているファイルハンドルの状況を確認できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=02844012b">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=da7226993">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=55b454d0e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=247ce06b8">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=10f664684">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=06fb5612c">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c325a7633">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=50cb7505b">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=047cba7fa">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=12ce89fd0">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2a5e709e7">&#167;</a></small></p>
<li>多数のリレーションにアクセスするクエリのロック性能が改善されました。  (Tomas Vondra) (18)</li>
<p>
PostgreSQLではテーブル等を参照するだけで最も弱いACCESS SHAREテーブルロックが発生します。このような弱いロックを簡易的に高速に行う仕組みがこれまでも用意されていましたが、1つのセッションにつき固定的に16個の要素（テーブルやインデックス）しか扱えませんでした。そのため、多数のテーブルにアクセスする問い合わせは、ロック処理が負担になっていました。典型的には大きなパーティションテーブルへの問い合わせが該当します。PostgreSQL 18 から、この上限数が固定的なものではなくなり、設定max_locks_per_transactionで与えられるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c4d5cb71d">&#167;</a></small></p>
<li>ハッシュ結合とGROUP BYのパフォーマンスが向上され、メモリ使用量が削減されました。  (David Rowley, Jeff Davis) (18)</li>
<p>
加えて、EXCEPT演算子でのハッシュセット処理や、サブプラン値のハッシュ検索もパフォーマンスが向上されました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=adf97c156">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0f5738202">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4d143509c">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a0942f441">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=626df47ad">&#167;</a></small></p>
<li>通常のVACUUMでもすべてが可視なページ上のタプルをFREEZEできるようなりました。  (Melanie Plageman) (18)</li>
<p>
この変更により、 後続のテーブル全体へのFREEZEの作業を軽減できます。FREEZEの積極度は、設定パラメータvacuum_max_eager_freeze_failure_rateによって制御できます。この設定はサーバ全体またはテーブル単位で指定できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=052026c9b">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=06eae9e62">&#167;</a></small></p>
<li>VACUUMコマンド実行時のファイルの末尾切り詰めを制御するサーバ変数vacuum_truncateが追加されました。  (Nathan Bossart, Gurjeet Singh) (18)</li>
<p>
従来は同名のパラメータで切り詰めを行うかをストレージレベルでのみ制御可能でしたが、vacuum_truncateの設定でVACUUM実行時に切り詰めるか否かを指定できるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0164a0f9e">&#167;</a></small></p>
<li>effective_io_concurrencyとmaintenance_io_concurrencyのデフォルト値が16 に引き上げられました。  (Melanie Plageman) (18)</li>
<p>
従来のデフォルト値では現代のハードウェアにおけるI/O並列性を十分に活かせませんでした。今回の変更により、クエリやメンテナンス作業が利用可能なI/O並列度をより効果的に活用できるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ff79b5b2a">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cc6be07eb">&#167;</a></small></p>
</ol>
<h5>モニタリング</h5>
<ol>
<li>サーバ変数log_connectionsのログの粒度を指定できるようになりました。  (Melanie Plageman) (18)</li>
<p>
従来はboolean値で接続ログの有無のみを制御していましたが、今回の変更により、より詳細なログ出力の粒度を指定できるようになりました。従来のboolean値も引き続きサポートされます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9219093ca">&#167;</a></small></p>
<li>log_connectionsに接続段階の処理時間を報告するオプションが追加されました。  (Melanie Plageman) (18)</li>
<p>
今回の変更により、log_connectionsに新しいオプションsetup_durationsが追加され、クライアント接続の各段階で要した時間をログ出力できるようになりました。接続処理の性能やタイミングを詳細に把握可能になりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=18cd15e70">&#167;</a></small></p>
<li>log_line_prefixにクライアントが接続したサーバIPアドレスを出力できる%Lエスケープが追加されました。  (Greg Sabino Mullane) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3516ea768">&#167;</a></small></p>
<li>ロック取得失敗をログに出力するサーバ変数log_lock_failuresが追加されました。  (Yuki Seino, Fujii Masao) (18)</li>
<p>
SELECT...NOWAITがロック取得に失敗した場合の情報をログに出力できるようになりました。これにより、ロック失敗の原因を把握しやすくなりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6d376c3b0">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=73bdcfab3">&#167;</a></small></p>
<li>pg_stat_all_tablesにVACUUM/ANALYZEの実行時間を報告するカラムが追加されました。  (Sami Imseih) (18)</li>
<p>
pg_stat_all_tablesおよびその派生ビューが修正され、手動および自動のVACUUMとANALYZEに費やされた時間を表示できるようになりました。
</p>
<pre>
(追加されたカラムの一覧)

- total_vacuum_time
- total_autovacuum_time
- total_analyze_time
- total_autoanalyze_time
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=30a6ed0ce">&#167;</a></small></p>
<li>VACUUMとANALYZEに遅延時間を報告する機能が追加されました。  (Bertrand Drouvot, Nathan Bossart) (18)</li>
<p>
この情報は、サーバログ、システムビューpg_stat_progress_vacuumおよびpg_stat_progress_analyze、VERBOSEモード時のVACUUMとANALYZEの出力にあらわれます。これを報告させるには設定パラメータtrack_cost_delay_timingを有効にします。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bb8dff999">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7720082ae">&#167;</a></small></p>
<li>ANALYZE VERBOSEの出力にWAL、CPU使用、平均読み書きレート(MB/s)の統計が追加されました。  (Anthonin Bonnefoy) (18)</li>
<pre>
（出力例 - 特に追加された部分）
db1=# ANALYZE VERBOSE t32;
（中略）
INFO:  finished analyzing table "db1.public.t32"
avg read rate: 26.042 MB/s, avg write rate: 15.625 MB/s
buffer usage: 169 hits, 10 reads, 6 dirtied
WAL usage: 7 records, 5 full page images, 30023 bytes, 0 buffers full
system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4c1b4cdb8">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bb7775234">&#167;</a></small></p>
<li>VACUUM/ANALYZE (VERBOSE)と自動バキュームのログ出力に、WALバッファがいっぱいになった回数も記録されるようになりました。  (Bertrand Drouvot) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6a8a7ce47">&#167;</a></small></p>
<li>バックエンドごとのI/O統計のレポート機能が追加されました。  (Bertrand Drouvot) (18)</li>
<p>
統計はpg_stat_get_backend_io()経由でアクセス可能です。バックエンドごとのI/O統計はpg_stat_reset_backend_stats()でクリア可能です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9aea73fc6">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3f1db99bf">&#167;</a></small></p>
<li>pg_stat_ioビューにI/Oアクティビティをバイト単位で報告する列が追加されました。  (Nazir Bilal Yavuz) (18)</li>
<p>
追加された列は read_bytes、write_bytes、extend_bytesです。常にBLCKSZに等しかったop_bytes列は削除されました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f92c854cf">&#167;</a></small></p>
<li>pg_stat_ioビューの出力にWALのI/Oアクティビティについての行が追加されました。  (Nazir Bilal Yavuz, Bertrand Drouvot, Michael Paquier) (18)</li>
<p>
これにはWAL receiverのアクティビティと、その書き込みに対する待機イベントも含まれます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a051e71e2">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4538bd3f1">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7f7f324eb">&#167;</a></small></p>
<li>設定パラメータtrack_wal_io_timingで制御する、WAL I/O所要時間の追跡を参照できる場所がpg_stat_walビューからpg_stat_ioビューに変更されました。  (Bertrand Drouvot) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6c349d83b">&#167;</a></small></p>
<li>pg_stat_walビューからwal_write、wal_sync、wal_write_time、wal_sync_time列が削除されました。  (Bertrand Drouvot) (18)</li>
<p>
同じ情報はpg_stat_ioビューで参照できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2421e9a51">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6c349d83b">&#167;</a><br />
</small></p>
<li>バックエンドごとのWAL統計を返すpg_stat_get_backend_wal()関数が追加されました。  (Bertrand Drouvot) (18)</li>
<p>
この統計はpg_stat_reset_backend_stats()関数でクリアできます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=76def4cdd">&#167;</a></small></p>
<li>PGDATA/pg_wal/summariesディレクトリの内容を具体的に一覧表示するpg_ls_summariesdir()関数が追加されました。  (Yushi Ogiwara) (18)</li>
<p>
上記のPGDATAはデータベースクラスタディレクトリを意味します。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4e1fad378">&#167;</a></small></p>
<li>pg_stat_checkpointerビューに、実際に実行したチェックポイントの回数を示すnum_done列が追加されました。  (Anton A. Melnikov) (18)</li>
<p>
既存のnum_timedおよびnum_requested列は、実際に実行したものだけでなくスキップされたチェックポイントもカウントしています。追加したnum_doneではスキップされたものはカウントせず、実行したチェックポイントのみカウントします。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=559efce1d">&#167;</a></small></p>
<li>pg_stat_checkpointerビューに、SLRUバッファの書き込み回数を示すslru_written列が追加されました。  (Nitin Jadhav) (18)</li>
<p>
また、チェックポイント完了時に出力されるサーバログのメッセージも変更され、共有バッファとSLRUバッファの書き込み件数がそれぞれ個別に報告されるようになりました。なお、以前のpg_stat_checkpointerビューでは、チェックポイント完了時に出力されるサーバログとは異なる数のバッファ書き込みを出力することがありましたが、これはpg_stat_checkpointerビューはSLRUバッファの書き込みをカウントしていないためでした。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=17cc5f666">&#167;</a></small></p>
<li>pg_stat_databaseビューに、並列クエリのワーカーの情報を示す列が追加されました。  (Benoit Lobreau) (18)</li>
<p>
新たに追加された列は、起動する予定だった並列ワーカー数を示すparallel_workers_to_launchと、実際に起動された並列ワーカー数を示すparallel_workers_launchedです。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e7a9496de">&#167;</a></small></p>
<li>クエリIDの計算時、定数リスト内のすべての値ではなく、先頭と末尾の定数のみを考慮するようになりました。  (Dmitry Dolgov, Sami Imseih) (18)</li>
<p>
クエリIDは例えば、pg_stat_statementsで利用されます。以前はリストの要素数が違うと異なるクエリIDが割り当てられていましたが、通常同じIDが割り当てられることが望ましいため、今回の変更が加わりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=62d712ecf">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9fbd53dea">&#167;</a></small></p>
<li>クエリIDの計算方法が調整され、同じリレーション名を使用するクエリは、スキーマが異なっても同一クエリのグループとして扱われるようになりました。  (Michael Paquier, Sami Imseih) (18)</li>
<p>
異なるスキーマにある同名テーブルが異なる列を持つ場合であっても、クエリが同じであれば同一クエリのグループとして扱われます。
</p>
<p>
以前はクエリIDの計算にOID(オブジェクト識別子)を利用していましたが、これにより例えば同名のテーブルの作成と削除を繰り返して使用した場合にも、それらのテーブルに対する同じクエリにそれぞれ別のクエリIDが割り振られていました。これは通常ユーザが期待する動作ではなかったため、この調整が加わりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=787514b30">&#167;</a></small></p>
<li>pg_backend_memory_contextsビューにtype列が追加されました。  (David Rowley) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=12227a1d5">&#167;</a></small></p>
<li>pg_backend_memory_contextsビューにpath列が追加されました。  (Melih Mutlu) (18)</li>
<p>
これにより、メモリコンテキストの親子関係が正確に把握できるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=32d3ed816">&#167;</a></small></p>
</ol>
<h4>権限</h4>
<ol>
<li>データベースのアクセス権限の詳細を取得する関数pg_get_acl()が追加されました。  (Joel Jacobson) (18)</li>
<p>
この関数は、カタログを参照せずに、データベースオブジェクトの権限を確認する際に有用です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4564f1ceb">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d898665bf">&#167;</a></small></p>
<li>ラージオブジェクトの権限を確認する関数has_largeobject_privilege()が追加されました。  (Yugo Nagata) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4eada203a">&#167;</a></small></p>
<li>ALTER DEFAULT PRIVILEGES文でラージオブジェクトのデフォルト権限を設定できるようになりました。  (Takatsuka Haruka, Yugo Nagata, Laurenz Albe) (18)</li>
<p>
これまでもGRANT文、REVOKE文で権限指定ができましたが、ラージオブジェクト1個ごとに行う必要がありました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0d6c47766">&#167;</a></small></p>
<li>ロールpg_signal_autovacuum_workerが追加されました。  (Kirill Reshke) (18)</li>
<p>
スーパーユーザー権限を持たないユーザーでも、このロールがあれば自動バキュームを実行するプロセスにシグナルを送信することができるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ccd38024b">&#167;</a></small></p>
</ol>
<h5>サーバ設定</h5>
<ol>
<li>OAuth認証方式をサポートしました。  (Jacob Champion, Daniel Gustafsson, Thomas Munro) (18)</li>
<p>
これにより、pg_hba.confにoauth認証方式、libpq APIのOAuthオプション、トークン検証ライブラリをロードするためのサーバ変数oauth_validator_libraries、そしてコンパイル時に必要なライブラリを追加するためのconfigureコマンドのフラグ--with-libcurl が追加されました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=b3f0be788">&#167;</a></small></p>
<li>サーバ変数ssl_tls13_ciphersを追加し、コロンで区切られた複数のTLSv1.3暗号スイートを指定できるようになりました。  (Erica Zhang, Daniel Gustafsson) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=45188c2ea">&#167;</a></small></p>
<li>サーバ変数ssl_groupsのデフォルトにCurve25519を含むように変更しました。  (Daniel Gustafsson, Jacob Champion) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=daa02c6bd">&#167;</a></small></p>
<li>サーバ変数ssl_ecdh_curveの名前をssl_groupsに変更し、コロンで区切られた複数のECDH曲線を指定できるようになりました。  (Erica Zhang, Daniel Gustafsson) (18)</li>
<p>
以前の変数名も引き続き機能します。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3d1ef3a15">&#167;</a></small></p>
<li>クエリのキャンセル要求を256ビットのキーで実行可能になりました。  (Heikki Linnakangas, Jelte Fennema-Nio) (18)</li>
<p>
これによりブルートフォース攻撃が成功する可能性が低くなりました。256ビットのキーは、サーバとクライアントが、このリリースで導入された、ワイヤプロトコルバージョン3.2 をサポートしている場合にのみ可能です。それ以外の場合は、従来どおり4バイトのキーが利用されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a460251f0">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9d9b9d46f">&#167;</a></small></p>
<li>サーバ変数autovacuum_worker_slotsが追加され、自動バキュームを実行するバックグラウンドプロセスの最大数を指定できるようになりました。  (Nathan Bossart) (18)</li>
<p>
この変数が導入されたことで、autovacuum_max_workersをサーバを再起動せずに、この最大数まで変更できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c758119e5">&#167;</a></small></p>
<li>自動バキュームのトリガとなるデッドタプルの固定数を指定できるようになりました。  (Nathan Bossart, Frédéric Yhuel) (18)</li>
<p>
サーバ変数はautovacuum_vacuum_max_thresholdです。autovacuum_vacuum_threshold、autovacuum_vacuum_scale_factorを利用した従来の閾値設定では、行数の多いテーブルのバキューム頻度が低くなる問題がありましたが、この変数により改善が見込めます。引き続きパーセンテージ指定もトリガに使用できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=306dc520b">&#167;</a></small></p>
<li>サーバ変数max_files_per_processがカウントする対象プロセスが変更され、バックエンドプロセスによって開かれたファイルのみを制限するようになりました。  (Andres Freund) (18)</li>
<p>
以前は、postmasterによって開かれたファイルもこの制限にカウントされていました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=adb5f85fa">&#167;</a></small></p>
<li>必要なセマフォの数を報告するサーバ変数num_os_semaphoresが追加されました。  (Nathan Bossart) (18)</li>
<p>
max_connectionsなどの設定値に基づいて必要なセマフォの数を計算します。これにより必要なOSの設定値を簡単に把握することが可能になりました。以前は、ドキュメントに記載の式を利用する必要がありましたが、新しくセマフォが必要なコンポーネントが追加された場合などにドキュメントの更新がされていない場合などがあり、ドキュメントに従っても必要数を正しく計算できないことがありました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0dcaea569">&#167;</a></small></p>
<li>新たな設定パラメータextension_control_pathが追加されました。これにより拡張のコントロールファイル(.control)を置くパスを複数指定できます。  (Peter Eisentraut, Matheus Alcantara) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4f7f7b037">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=81eaaa2c4">&#167;</a></small></p>
</ol>
<h5>ストリーミングレプリケーションとリカバリ</h5>
<ol>
<li>新たな設定パラメータidle_replication_slot_timeoutでアクティブでないレプリケーションスロットを自動的に無効化できるようになりました。  (Nisha Moond, Bharath Rupireddy) (18)</li>
<p>
タイムアウトになったレプリケーションスロットは、pg_replication_slotビューでwal_statusが「lost」になってWALの保持が行なわれなくなり、invalidation_reasonに「idle_timeout」と理由が示されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ac0e33136">&#167;</a></small></p>
<li>設定パラメータmax_active_replication_originsが追加されました。有効なレプリケーションオリジンの最大数を制御します。  (Euler Taveira) (18)</li>
<p>
これまではmax_replication_slots設定で最大数が規定されていましたが、バージョン18からレプリケーションスロットの最大数とは別個に設定できるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=04ff636cb">&#167;</a></small></p>
</ol>
<h5>論理レプリケーション</h5>
<ol>
<li>論理レプリケーションで生成列の値を送出できるようになりました。  (Shubham Khanna, Vignesh C, Zhijie Hou, Shlok Kyal, Peter Smith) (18)</li>
<p>
パブリケーションで列リストが指定されている場合には指定すれば生成列もレプリケーションされます。列リストが指定されていない場合に生成列を含めるかどうかは、パブリケーションの新たなオプションpublish_generated_columnsの指定に従います。なお、これらに対応するのはSTORED生成列のみで、仮想生成列（VIRTUAL生成列）は対象外です。
</p>
<p>
これまでは、論理レプリケーションでパブリッシャ側からの生成列の送出はサポートされておらず、サブスクライバ側で元となる列から計算させる構成にする必要がありました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=745217a05">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7054186c4">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=87ce27de6">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6252b1eaf">&#167;</a></small></p>
<li>CREATE SUBSCRIPTIONのstreamingオプションのデフォルトがoffからparallelに変更されました。  (Vignesh C) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1bf1140be">&#167;</a></small></p>
<li>ALTER SUBSCRIPTIONがレプリケーションスロットの2相コミット動作を変更できるようになりました。  (Hayato Kuroda, Ajin Cherian, Amit Kapila, Zhijie Hou) (18)</li>
<p>
これまではCREATE SUBSCRIPTIONでtwo_phaseオプションを指定できましたが、後からは変更できませんでした。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1462aad2e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4868c96bc">&#167;</a></small></p>
<li>論理レプリケーションの変更を適用するときのコンフリクトをログ記録するようになりました。  (Zhijie Hou, Nisha Moond) (18)</li>
<p>
また、pg_stat_subscription_statsビューの新たな列でも種別ごとにコンフリクト発生回数が報告されるようになりました。「confl_insert_exists」など、コンフリクトの種類ごとに「confl_」で始まる列がいくつか追加されています。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9758174e2">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=edcb71258">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=640178c92">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6c2b5edec">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=73eba5004">&#167;</a></small></p>
</ol>
<h4>ユーティリティコマンド</h4>
<ol>
<li>仮想生成列（VIRTUAL生成列）がサポートされました。こちらが生成列のデフォルトになります。  (Peter Eisentraut, Jian He, Richard Guo, Dean Rasheed) (18)</li>
<p>
仮想生成列は、その列が読まれたときに値を計算して生成します。列の値がテーブルのデータとして書き込まれることはありません。生成した値を書き込む動作をさせるには「STORED」オプションを指定してください。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=83ea6c540">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cdc168ad4">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1e4351af3">&#167;</a></small></p>
<li>DMLコマンドのRETURNING句で「OLD」と「NEW」がサポートされました。  (Dean Rasheed) (18)</li>
<p>
これまではRETURNING句は、INSERTとUPDATEに対しては新たな値のみを、DELETEに対しては古い値のみを、MERGEに対しては処理内容に応じた値を返していました。
</p>
<p>
新たなRETURNING句では、特別な別名OLD、NEWを用いて明示的に新旧の値を返すようになりました。識別子の衝突を避けるため、OLD、NEWの別名を変更することもできます。
</p>
<pre>
（例）
db1=# UPDATE t1 SET v = 'A' WHERE id <= 3 RETURNING WITH (OLD AS o, NEW AS n)
        o.id AS old_id, o.v AS old_v, n.id AS new_id, AS n.v new_v;
 old_id |              old_v               | new_id | new_v
--------+----------------------------------+--------+-------
      1 | c4ca4238a0b923820dcc509a6f75849b |      1 | A
      2 | c81e728d9d4c2f636f067f89cc14862c |      2 | A
      3 | eccbc87e4b5ce2fe28308fd9f2a7baf3 |      3 | A
(3 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=80feb727c">&#167;</a></small></p>
<li>ローカルデータベース上の既存テーブルをLIKE句で指定して、外部テーブルを作成できるようになりました。  (Zhang Mingli) (18)</li>
<p>
これまではCREATE FOREIGN TABLEにLIKE句は使用できませんでした。リモートデータベースにpublic.t1があり、同定義のテーブルpublic.t1がローカルデータベースにあるとき、以下のように外部テーブルを作成できます。
</p>
<pre>
db2=# CREATE FOREIGN TABLE ft1 ( LIKE public.t1 )
        SERVER sv1_db1 OPTIONS ( table_name 't1', schema_name 'public');
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=302cf1575">&#167;</a></small></p>
<li>非決定論的（deterministic = false）な照合順序において、LIKE演算子が利用可能になりました。  (Peter Eisentraut) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=85b7efa1c">&#167;</a></small></p>
<li>非決定論的（deterministic = false）な照合順序において、テキスト位置検索関数が利用可能になりました。  (Peter Eisentraut) (18)</li>
<p>
これまでは「ERROR:  nondeterministic collations are not supported for ...」というエラーが出ていました。利用可能になった関数は以下の通りです。
</p>
<pre>
position()
strpos()
replace()
split_part()
string_to_array()
string_to_table()
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=329304c90">&#167;</a></small></p>
<li>組み込みの照合順序プロバイダにロケール「PG_UNICODE_FAST」が追加されました。  (Jeff Davis) (18)</li>
<p>
このロケールに対応する照合順序「pg_unicode_fast」は、ASCII以外の大文字小文字マッピングをサポートする一方、ソートは自然言語の辞書順ではなくコードポイント順です。
</p>
<pre>
（initdbでこれを指定するときの例）
$ initdb --locale-provider=builtin --builtin-locale=PG_UNICODE_FAST -E UTF8 -D $PGDATA
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d3d098316">&#167;</a></small></p>
<li>VACUUMとANALYZEがパーティションテーブルをパーティション（子テーブル）抜きに処理できるようになりました。  (Michael Harris) (18)</li>
<p>
新たなオプションONLYを指定して、そのような動作にすることができます。autovacuumはパーティション（子テーブル）のみを処理対象とするため、パーティションテーブル（親テーブル）だけに追加でANALYZEを行いたい場合に便利です。
</p>
<p>
ONLYでパーティションテーブルのみの VACUUM を指定した場合、何もしないという動作になります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=62ddf7ee9">&#167;</a></small></p>
<li>リレーション毎、および、列毎にプランナ統計を変更する関数が追加されました。  (Corey Huinker) (18)</li>
<p>
追加された関数は以下の通りです。これらはプランナ統計情報のダンプ・リストアで使われます。
</p>
<pre>
pg_restore_relation_stats()
pg_restore_attribute_stats()
pg_clear_relation_stats()
pg_clear_attribute_stats()
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e839c8ecc">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d32d14639">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=650ab8aaf">&#167;</a></small></p>
<li>ファイルコピーの方法を指定する設定パラメータfile_copy_methodが追加されました。  (Nazir Bilal Yavuz) (18)</li>
<p>
この設定値は「CREATE DATABASE ... STRATEGY=FILE_COPY」コマンドと、「ALTER DATABASE ... SET TABLESPACE ...」コマンドで、ファイルをコピーするときの動作に影響します。OSが対応していれば、デフォルトのCOPYに替えてCLONEを指定することで高速化が狙えます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f78ca6f3e">&#167;</a></small></p>
</ol>
<h5>制約</h5>
<ol>
<li>範囲型や多重範囲型の列に対して、重なりを持たないという条件を、主キー制約、ユニークキー制約、外部キー制約に指定できるようになりました。  (Paul A. Jungwirth) (18)</li>
<p>
これは「PRIMARY KEY」と「UNIQUE」に対しては新たな「WITHOUT OVERLAPS」句で、外部キー制約に対しては新たな「PERIOD」句で、指定します。いずれも対象とできるのは制約の最後の列です。
</p>
<pre>
（外部キー制約の例）
db1=# CREATE EXTENSION btree_gist;
db1=# CREATE TABLE t77m (cid int, age_r int4range, 
        PRIMARY KEY (cid, age_r WITHOUT OVERLAPS));
db1=# CREATE TABLE t77t (id int PRIMARY KEY, cid int, age_r int4range, 
        FOREIGN KEY (cid, PERIOD age_r) REFERENCES t77m (cid, PERIOD age_r));
db1=# INSERT INTO t77m VALUES (1, '[0,6)'), (2, '[6,12)'), (3, '[12,)');
db1=# INSERT INTO t77t VALUES (100, 3, '[12,)');  -- 範囲が一致している場合
db1=# INSERT INTO t77t VALUES (101, 2, '[9,11)'); -- 範囲内に収まっている場合
db1=# INSERT INTO t77t VALUES (102, 1, '[,10)');  -- 範囲をはみ出している場合
ERROR:  insert or update on table "t77t" violates foreign key constraint "t77t_cid_age_r_fkey"
DETAIL:  Key (cid, age_r)=(1, (,10)) is not present in table "t77m".
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fc0438b4e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=89f908a6d">&#167;</a></small></p>
<li>チェック制約と外部キー制約で「NOT ENFORCED」を指定できるようになりました。  (Amul Sul) (18)</li>
<p>
対応して、システムテーブルpg_constraintにconenforced列が加わりました。「NOT ENFORCED」であると制約が働かない動作になります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ca87c415e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=eec0040c4">&#167;</a></small></p>
<li>主キーと外部キーの関係において、両方とも決定論的照合順序であるか、同一の非決定論的照合順序であることが必要になりました。  (Peter Eisentraut) (18)</li>
<p>
非互換の変更点と言えます。pg_dumpによるダンプのリストア（これはpg_upgrade内でも使われます）は、この条件を満たさないと失敗します。対処にはデータベースの定義変更が必要となります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9321d2fdf">&#167;</a></small></p>
<li>「NOT NULL」指定がシステムテーブルpg_constraintに格納されるようになりました。  (Alvaro Herrera, Bernd Helmle) (18)</li>
<p>
これからはNOT NULL制約が制約名を持つようになります。加えて、外部テーブルにもNOT NULL制約を指定できるようになりました。さらに、NOT NULL制約を新たなオプション「NO INHERIT」により、継承子テーブルで継承しないように指定できるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=14e87ffa5">&#167;</a></small></p>
<li>ALTER TABLEでNOT NULL制約をNOT VALIDで作成して、データの検査を先送りできるようになりました。  (Rushabh Lathia, Jian He) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a379061a2">&#167;</a></small></p>
<li>継承親テーブルのNOT NULL制約が継承対象かどうかを指定できるようになりました。  (Suraj Kharage, Alvaro Herrera) (18)</li>
<p>
構文は下記になります。
</p>
<pre>
ALTER TABLE ... ALTER CONSTRAINT ... [NO] INHERIT
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f4e53e10b">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4a02af8b1">&#167;</a></small></p>
<li>パーティションテーブルで外部キー制約をNOT VALIDで設定できるようになりました。  (Amul Sul) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=b663b9436">&#167;</a></small></p>
<li>パーティションテーブルにALTER TABLE .. DROP CONSTRAINT ..で制約を除去するときに、ONLYを指定できるようになりました。  (Alvaro Herrera) (18)</li>
<pre>
（以下を実行すると、t84p1にはNOT NULL制約が残ります）
db1=# CREATE TABLE t84 (id int, c text NOT NULL) PARTITION BY RANGE (id);
db1=# CREATE TABLE t84p1 PARTITION OF t84 FOR VALUES FROM (1) TO (101);
db1=# ALTER TABLE ONLY t84 DROP CONSTRAINT "t84_c_not_null";
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4dea33ce7">&#167;</a></small></p>
</ol>
<h5>COPY</h5>
<ol>
<li>COPY FROMで「REJECT_LIMIT」を指定できるようになりました。これで許容できるエラーの最大数を指定できます。  (Atsushi Torikoshi) (18)</li>
<p>
これは「ON_ERROR = 'ignore'」の場合に使用できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4ac2a9bec">&#167;</a></small></p>
<li>COPY TOでマテリアライズドビューからコピーできるようになりました。  (Jian He) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=534874fac">&#167;</a></small></p>
<li>COPY FROMの「LOG_VERBOSITY」オプションの値に「silent」が追加されました。  (Atsushi Torikoshi) (18)</li>
<p>
「ON_ERROR = 'ignore'」のとき、この値が指定されていると、エラーとなった入力行数をログ出力しません。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e7834a1a2">&#167;</a></small></p>
<li>外部テーブルに対するCOPY FREEZEが使用できなくなりました。  (Nathan Bossart) (18)</li>
<p>
これまではエラーにはなりませんが「FREEZE」指定は無視されていました。これからはエラーになります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=401a6956f">&#167;</a></small></p>
</ol>
<h5>EXPLAIN</h5>
<ol>
<li>EXPLAINでANALYZEオプションを指定した場合、BUFFERSオプションも自動的に有効化されるようになりました。  (Guillaume Lelarge, David Rowley) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c2a4078eb">&#167;</a></small></p>
<li>EXPLAINのWALオプション指定時の出力内容に、WALバッファが一杯になった回数が追加されました。  (Bertrand Drouvot) (18)</li>
<pre>
（出力例）
db1=# CREATE TABLE t90 (c text);
db1=# EXPLAIN (ANALYZE, WAL, COSTS off, BUFFERS off, TIMING off)
        INSERT INTO t90 SELECT md5(g::text) FROM generate_series(1, 300000) g;
                                QUERY PLAN
--------------------------------------------------------------------------
 Insert on t90 (actual rows=0.00 loops=1)
   WAL: records=300000 bytes=26400000 buffers full=689
   ->  Function Scan on generate_series g (actual rows=300000.00 loops=1)
 Planning Time: 0.085 ms
 Execution Time: 1953.013 ms
(5 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=320545bfc">&#167;</a></small></p>
<li>EXPLAIN ANALYZEで、各インデックススキャンノードのインデックス参照回数が表示されるようになりました。  (Peter Geoghegan) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0fbceae84">&#167;</a></small></p>
<li>EXPLAINで行数が小数まで出力されるようになりました。  (Ibrar Ahmed, Ilia Evdokimov, Robert Haas) (18)</li>
<p>
loopsを伴う場合、1回あたりの行数を出力しますので小数も必要でした。たとえば、4回の繰り返しで合計11行を取得したなら「(actual rows=2.75 loops=4)」と出力されます。これまでは「(actual rows=3 loops=4)」となっていました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ddb17e387">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=95dbd827f">&#167;</a></small></p>
<li>EXPLAIN ANALYZEがプランノード「Material」と「Window Aggregate」、共通テーブル式（WITH句）などについて、内部で使用するタプルストアのメモリ使用量やディスクに書き出しの有無を報告するようになりました。  (David Rowley, Tatsuo Ishii) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1eff8279d">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=53abb1e0e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=95d6e9af0">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=40708acd6">&#167;</a></small></p>
<li>EXPLAINがプランノード「WindowAgg」について、ウィンドウ定義の詳細を報告するようになりました。  (Tom Lane) (18)</li>
<pre>
（実行例 - Window:の行が本バージョンから追加された）
db1=# CREATE TABLE t94 (id int, score float4);
db1=# INSERT INTO t94 SELECT g, random() FROM generate_series(1, 100) g;
db1=# explain SELECT id, avg(score) OVER w1 FROM t94
        WINDOW w1 AS (ORDER BY id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
                                         QUERY PLAN                             
--------------------------------------------------------------------------------------------
 WindowAgg  (cost=5.36..7.07 rows=100 width=12)
   Window: w1 AS (ORDER BY id ROWS BETWEEN '1'::bigint PRECEDING AND '1'::bigint FOLLOWING)
   ->  Sort  (cost=5.32..5.57 rows=100 width=8)
         Sort Key: id
         ->  Seq Scan on t94  (cost=0.00..2.00 rows=100 width=8)
(5 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8b1b34254">&#167;</a></small></p>
<li>EXPLAIN ANALYZEがプランノード「Parallel Bitmap Heap Scan」について、パラレルワーカーのキャッシュ統計を報告するようになりました。  (David Geier, Heikki Linnakangas, Donghang Lin, Alena Rybakina, David Rowley) (18)</li>
<pre>
（出力例 - 各ワーカーで「exact」と「lossy」のページ数が報告される)
db1=# explain (analyze, buffers off, costs off, timing off) 
        SELECT id FROM t95 WHERE c1 <= 2 AND c2 <= 2 AND c3 <= 2;
                                 QUERY PLAN
-----------------------------------------------------------------------------
 Gather (actual rows=11107.00 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Bitmap Heap Scan on t95 (actual rows=3702.33 loops=3)
         Recheck Cond: (c3 <= 2)
         Rows Removed by Index Recheck: 235532
         Filter: ((c1 <= 2) AND (c2 <= 2))
         Rows Removed by Filter: 55121
         Heap Blocks: exact=381 lossy=1707
         Worker 0:  Heap Blocks: exact=203 lossy=1830
         Worker 1:  Heap Blocks: exact=184 lossy=1101
         ->  Bitmap Index Scan on t95_c3_idx (actual rows=176471.00 loops=1)
               Index Cond: (c3 <= 2)
               Index Searches: 1
 Planning Time: 0.339 ms
 Execution Time: 155.347 ms
(16 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=5a1e6df3b">&#167;</a></small></p>
<li>EXPLAIN ANALYZEで無効にされたプランノードタイプが出力されるようになりました。  (Robert Haas, David Rowley, Laurenz Albe) (18)</li>
<p>
以下のように設定で無効化されたプランノードタイプが、他に手段がないために選択された場合に「Disabled: true」が出力されます。
</p>
<pre>
db1=# CREATE TABLE t96 (id int);
db1=# SET enable_seqscan TO off;
db1=# explain SELECT id FROM t96;
                      QUERY PLAN
-------------------------------------------------------
 Seq Scan on t96  (cost=0.00..35.50 rows=2550 width=4)
   Disabled: true
(2 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c01743aa4">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=161320b4b">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=84b8fccbe">&#167;</a></small></p>
</ol>
<h4>データ型</h4>
<ol>
<li>Unicodeの完全な大文字小文字のマッピングと変換がサポートされました。  (Jeff Davis) (18)</li>
<p>
タイトルケースやその他の条件に応じたマッピング（文字の出現位置による違い）、単一文字から複数文字へマッピングへの対応が加わりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4e7f62bc3">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=286a365b9">&#167;</a></small></p>
<li>jsonbの「null」値を「NULL」としてスカラー型にキャストできるようになりました。  (Tom Lane) (18)</li>
<p>
これまではエラーになりました。
</p>
<pre>
（バージョン18の動作例）
db1=# SELECT 'null'::jsonb::int;
 int4
------

(1 row)

（バージョン17.xまでは以下のエラーになる）
ERROR:  cannot cast jsonb null to type integer
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a5579a90a">&#167;</a></small></p>
<li>json_strip_nulls()およびjsonb_strip_nulls()関数に、配列内のnull要素も削除できるオプションパラメータが追加されました。  (Florents Tselai) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4603903d2">&#167;</a></small></p>
<li>配列を最初の次元でソートする関数array_sort()が追加されました。  (Junwang Zhao, Jian He) (18)</li>
<pre>
（使用例）
db1=# SELECT array_sort('{{2,3,5},{1,2,3},{2,3,4},{1,10,5}}'::int[]);
             array_sort
------------------------------------
 {{1,2,3},{1,10,5},{2,3,4},{2,3,5}}
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6c12ae09f">&#167;</a></small></p>
<li>配列の第1次元を反転する関数array_reverse()が追加されました。  (Aleksander Alekseev) (18)</li>
<pre>
(実行例)
db1=# SELECT array_reverse(ARRAY[[1,2],[3,4],[5,6]]);
    array_reverse
---------------------
 {{5,6},{3,4},{1,2}}
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=49d6c7d8d">&#167;</a></small></p>
<li>bytea型のバイト列を反転する関数reverse()が追加されました。  (Aleksander Alekseev) (18)</li>
<p>
バイト列の順序を反転することで、ビッグエンディアンとリトルエンディアン変換を行うケースなどで役立ちます。
</p>
<pre>
(実行例)
db1=# SELECT reverse('\xA1B2C3'::bytea);
 reverse
----------
 \xc3b2a1
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0697b2390">&#167;</a></small></p>
<li>整数型とbytea型の間でのキャストを許可するようになりました。  (Aleksander Alekseev) (18)</li>
<p>
整数値は2の補数表現のbytea値として保存されます。
</p>
<pre>
(実行例)
db1=#  SELECT 1234::bytea;
   bytea
------------
 \x000004d2
(1 row)

db1=# SELECT '\x000004d2'::bytea::int4;
 int4
------
 1234
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6da469bad">&#167;</a></small></p>
<li>UnicodeデータのバージョンがUnicode 16.0.0に更新されました。  (Peter Eisentraut) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=82a46cca9">&#167;</a></small></p>
<li>エストニア語の全文検索におけるステミング機能が追加されました。  (Tom Lane) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=b464e51ab">&#167;</a></small></p>
<li>XMLのエラーコードがSQL標準により近づくよう改善されました。  (Tom Lane) (18)</li>
<p>
これらのエラーはSQLSTATEを通じて報告されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cd838e200">&#167;</a></small></p>
</ol>
<h4>関数</h4>
<ol>
<li>casefold()関数が追加され、より高度な大文字/小文字を区別しない照合が可能になりました。  (Jeff Davis) (18)</li>
<p>
これにより、1文字が複数の大文字/小文字に対応する場合や、変換によって文字数が変わる場合でも、より正確な比較ができるようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bfc599206">&#167;</a></small></p>
<li>配列型や複合型に対しても、MIN()/MAX()集約関数を使用できるようになりました。  (Aleksander Alekseev, Marat Buharov) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a0f1fce80">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2d24fd942">&#167;</a></small></p>
<li>EXTRACT()関数にWEEKオプションが追加されました。  (Tom Lane) (18)</li>
<pre>
(実行例)
db1=# SELECT EXTRACT(WEEK FROM interval '2 weeks'),
EXTRACT(WEEK FROM interval '-15 days'),
EXTRACT(WEEK FROM date '2025-1-27');
 extract | extract | extract
---------+---------+---------
       2 |      -2 |       5
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6be39d77a">&#167;</a></small></p>
<li>負の値に対するEXTRACT(QUARTER ...)の出力が改善されました。  (Tom Lane) (18)</li>
<p>
以前からQUARTERオプションはintervalでも使えていましたが、負のintervalに対しては奇妙な結果を返していました。
</p>
<pre>
(実行例)
db1=# SELECT EXTRACT(QUARTER FROM interval '10 months'),
EXTRACT(QUARTER FROM interval '-10 months');
 extract | extract
---------+---------
       4 |      -4
(1 row)
(PG17以前だと奇妙な結果が返ってくる)
db1=# SELECT EXTRACT(QUARTER FROM INTERVAL '10 months'),
EXTRACT(QUARTER FROM INTERVAL '-10 months');
 extract | extract
---------+---------
       4 |      -2
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6be39d77a">&#167;</a></small></p>
<li>関数to_number()でローマ数字がサポートされました。  (Hunaid Sohail) (18)</li>
<pre>
（使用例）
db1=# SELECT to_number('XVIII', 'RN');
 to_number
-----------
        18
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=172e6b3ad">&#167;</a></small></p>
<li>UUIDバージョン7を生成する関数uuidv7()が追加されました。  (Andrey Borodin) (18)</li>
<p>
このUUID値は時間的にソート可能で、生成順の並びになります。
</p>
<p>
また、UUIDバージョン4を生成する関数gen_random_uuid()の別名として、関数uuidv4()も追加されました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=78c5e141e">&#167;</a></small></p>
<li>CRC（巡回冗長検査）の値を計算する関数crc32()、crc32c()が追加されました。  (Aleksander Alekseev) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=760162fed">&#167;</a></small></p>
<li>算術関数としてガンマ関数gamma()、対数ガンマ関数lgamma()が追加されました。  (Dean Rasheed) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a3b6dfd41">&#167;</a></small></p>
<li>PL/pgSQLで、名前付きカーソル引数に「=>」構文が使用可能となりました。  (Pavel Stehule) (18)</li>
<p>
これまでは「:=」のみが使用可能でした。
</p>
<p>
「OPEN cur1 (p1 => 'A', p2 => 123);」や「FOR rec IN cur2(a1 => 't') LOOP」などと記述できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=246dedc5d">&#167;</a></small></p>
<li>正規表現関数で名前付き引数が使用可能になりました。  (Jian He) (18)</li>
<p>
対象は以下の関数です。
</p>
<pre>
regexp_match()
regexp_matches()
regexp_like()
regexp_replace()
regexp_count()
regexp_instr()
regexp_substr()
regexp_split_to_table()
regexp_split_to_array()
</pre>
<p>
以下のように使用できます。
</p>
<pre>
db1=# SELECT regexp_replace(string=>'hello world', pattern=>'o', replacement=>'0', flags=>'g');
 regexp_replace
----------------
 hell0 w0rld
(1 row)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=580f8727c">&#167;</a></small></p>
</ol>
<h4>libpq</h4>
<ol>
<li>マイナーバージョンを含む完全なプロトコルバージョン番号を報告する関数PQfullProtocolVersion()が追加されました。  (Jacob Champion, Jelte Fennema-Nio) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cdb6b0fdb">&#167;</a></small></p>
<li>接続で使用するプロトコルバージョンの範囲を指定する、libpqの接続パラメータと環境変数が追加されました。  (Jelte Fennema-Nio) (18)</li>
<p>
追加されたパラメータはmin_protocol_versionとmax_protocol_version、環境変数はPGMINPROTOCOLVERSIONとPGMAXPROTOCOLVERSIONです。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=285613c60">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=507034910">&#167;</a></small></p>
<li>search_pathの変更をクライアントに報告するようになりました。  (Alexander Kukushkin, Jelte Fennema-Nio, Tomas Vondra) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=28a1121fd">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0d06a7eac">&#167;</a></small></p>
<li>PQtrace()で認証処理を含む全てのメッセージタイプを出力するようになりました。  (Jelte Fennema-Nio) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ea92f3a0a">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a5c6b8f22">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=b8b3f861f">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e87c14b19">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7adec2d5f">&#167;</a></small></p>
<li>SSL鍵についてのログを出力させる、libpq接続パラメータsslkeylogfileが追加されました。  (Abhishek Chanda, Daniel Gustafsson) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2da74d8d6">&#167;</a></small></p>
<li>いくつかのlibpq関数をシグネチャにint64_tを使うように修正しました。  (Thomas Munro) (18)</li>
<p>
これらは非推奨となっているpg_int64を使っていました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3c86223c9">&#167;</a></small></p>
</ol>
<h4>psql</h4>
<ol>
<li>psqlで名前付きプリペアドステートメントのパース、バインド、クローズができるようになりました。  (Anthonin Bonnefoy, Michael Paquier) (18)</li>
<p>
新たなメタコマンド「\parse」「\bind_named」「\close_prepared」でこれを行うことができます。
</p>
<pre>
（実行例)
db1=# SELECT $1 + 1, $2 || 'X'  \parse ps1

db1=# \bind_named ps1 100 'ABC'  \g
 ?column? | ?column?
----------+----------
      101 | ABCX
(1 row)

db1=# \close_prepared ps1
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d55322b0d">&#167;</a></small></p>
<li>psql のメタコマンド（バックスラッシュコマンド）でパイプライン問合せの発行が可能になりました。  (Anthonin Bonnefoy) (18)</li>
<p>
そのために以下のメタコマンドが追加されました。
</p>
<pre>
\startpipeline
\syncpipeline
\sendpipeline
\endpipeline
\flushrequest
\flush
\getresults
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=41625ab8e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=17caf6644">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2cce0fe44">&#167;</a></small></p>
<li>パイプライン状態をpsqlのプロンプトに付加できるようになりました。また、新たな変数で状態を確認できるようになりました。  (Anthonin Bonnefoy) (18)</li>
<p>
新たなプロンプト文字は「%P」で、新たなpsql変数は「PIPELINE_SYNC_COUNT」、「PIPELINE_COMMAND_COUNT」、「PIPELINE_RESULT_COUNT」です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3ce357584">&#167;</a></small></p>
<li>接続サービス名をpsqlプロンプトに付加できるようになり、また、psql変数から参照可能になりました。  (Michael Banck) (18)</li>
<p>
新たなプロンプト文字は「%s」で、新たなpsql変数は「SERVICE」です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=477728b5d">&#167;</a></small></p>
<li>psqlの一覧出力する全てのメタコマンドに、拡張表示モードを使うようにするオプション「x」が追加されました。  (Dean Rasheed) (18)</li>
<p>
以下のように使用します。
</p>
<pre>
db1=# \du
                             List of roles
 Role name |                         Attributes
-----------+------------------------------------------------------------
 foo       |
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS

db1=# \dux
List of roles
-[ RECORD 1 ]----------------------------------------------------------
Role name  | foo
Attributes |
-[ RECORD 2 ]----------------------------------------------------------
Role name  | postgres
Attributes | Superuser, Create role, Create DB, Replication, Bypass RLS
</pre>
<p>
ただし、「\dx」は「インストールされている拡張一覧」の意味になるため、「\d」には付加できません。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=00f4c2959">&#167;</a></small></p>
<li>psqlのメタコマンド\conninfoの出力が、1行の文字列ではなく表形式になり、より多くの情報を含むようになりました。  (Alvaro Herrera, Maiquel Grassi, Hunaid Sohail) (18)</li>
<pre>
db1=# \conninfo
     Connection Information
      Parameter       |  Value
----------------------+----------
 Database             | db1
 Client User          | postgres
 Socket Directory     | /tmp
 Server Port          | 5432
 Options              |
 Protocol Version     | 3.0
 Password Used        | false
 GSSAPI Authenticated | false
 Backend PID          | 340367
 SSL Connection       | false
 Superuser            | on
 Hot Standby          | off
(12 rows)
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bba2fbc62">&#167;</a></small></p>
<li>psqlのメタコマンド\df+、\do+、\dAo+、\dC+で関数のLEAKPROOF属性を出力に含めるようになりました。  (Yugo Nagata) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2355e5111">&#167;</a></small></p>
<li>psqlのメタコマンド「\dP+」で、パーティションテーブルの詳細情報としてアクセスメソッドを出力するようになりました。  (Justin Pryzby) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=978f38c77">&#167;</a></small></p>
<li>psqlの拡張機能の一覧を出力するメタコマンドである\dxの出力にdefault_version列が追加されました。  (Magnus Hagander) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d696406a9">&#167;</a></small></p>
<li>\watchのデフォルトの待機時間を設定するためのpsql変数WATCH_INTERVALが追加されました。  (Daniel Gustafsson) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1a759c832">&#167;</a></small></p>
</ol>
<h4>サーバアプリケーション</h4>
<ol>
<li>initdbの動作が変更され、デフォルトでデータチェックサムが有効化されるようになりました。  (Greg Sabino Mullane) (18)</li>
<p>
新たに追加されたオプション--no-data-checksumsを指定することで、チェックサムを無効にすることができます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=983a588e0">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=04bec894a">&#167;</a></small></p>
<li>initdbに新たなオプション--no-sync-data-filesが追加され、ヒープファイルやインデックスファイルの同期（sync）を行わないようにすることが可能になりました。  (Nathan Bossart) (18)</li>
<p>
このオプションは、同期をinitdbとは別の処理で実施するPostgreSQLのツールの内部で利用することを想定して追加されています。従来の--no-syncオプションも引き続き使用可能で、こちらはすべてのファイルの同期を行わないようにします。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cf131fa94">&#167;</a></small></p>
<li>vacuumdbにオプション--missing-stats-onlyが追加され、統計情報のうち、まだ収集されていないものだけを収集することが可能になりました。  (Corey Huinker, Nathan Bossart) (18)</li>
<p>
このオプションはスーパーユーザーのみが実行でき、--analyze-onlyまたは--analyze-in-stagesオプションと併せて使用する必要があります。主にpg_upgrade実行後に不足している統計情報を補完する用途を想定して導入されました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=edba754f0">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=987910502">&#167;</a></small></p>
<li>pg_combinebackupにオプション-k/--linkが追加され、ハードリンクを有効にすることが可能になりました。  (Israel Barth Rubio, Robert Haas) (18)</li>
<p>
ただし、ハードリンクできるのは一部のファイルに限られており、生成されたバックアップをそれぞれ独立して使用する予定がある場合には、このオプションの使用は推奨されません。
</p>
<p>
このオプションは、入力ディレクトリが復元後に削除される一時的なステージング領域である場合に特に有効で、ファイルのコピーを省略して高速化が図れます。しかし、ハードリンクにより出力先の変更が入力ディレクトリにも影響するため、入力ディレクトリを再利用する可能性がある場合は危険であり、使用時には警告が表示されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=99aeb8470">&#167;</a></small></p>
<li>pg_verifybackupにtarフォーマットのバックアップを検証できる機能が追加されました。  (Amul Sul) (18)</li>
<p>
この機能は圧縮されたtarフォーマットのバックアップにも対応しています。ただし、WALの検証にはpg_waldumpを使用している関係で、WALがtarファイル内に格納されている場合はまだ検証できません。そのため、WALの検証をスキップする-nオプションを必ず指定する必要があります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8dfd31290">&#167;</a></small></p>
<li>pg_rewindの--source-serverオプションでデータベース名が指定されている場合、そのデータベース名が--write-recovery-confの出力に使用されるようになりました。  (Masahiko Sawada) (18)</li>
<p>
これにより、sync_replication_slotsが有効な環境でも、リワインド後のサーバが手動で設定ファイルを修正することなくプライマリサーバへ接続できるようになります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4ecdd4110">&#167;</a></small></p>
<li>pg_resetwalにオプション--char-signednessが追加され、デフォルトのcharの符号性を変更できるようになりました。  (Masahiko Sawada) (18)</li>
<p>
このオプションは、pg_upgrade内部での利用を想定しており、手動での操作は想定していません。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=30666d185">&#167;</a></small></p>
</ol>
<h4>pg_dump</h4>
<ol>
<li>pg_dumpに統計情報をダンプするための--statisticsオプションが追加されました。  (Jeff Davis) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bde2fb797">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a3e8dc143">&#167;</a></small></p>
<li>pg_dump、pg_dumpallにオプション--sequence-dataが追加されました。--no-dataなどシーケンスデータを除外するオプションが指定されている場合でも、シーケンスデータをダンプできます。  (Nathan Bossart) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9c49f0e8c">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=acea3fc49">&#167;</a></small></p>
<li>pg_dump、pg_dumpall、pg_restoreにオプション--statistics-only、--no-statistics、--no-data、--no-schemaが追加されました。  (Corey Huinker, Jeff Davis) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1fd1bd871">&#167;</a></small></p>
<li>pg_dump、pg_dumpall、pg_restoreにオプション--no-policiesが追加されました。このオプションで行レベルのセキュリティポリシー処理を無効にします。  (Nikolay Samokhvalov) (18)</li>
<p>
これは異なるポリシーを持つシステムに移行する場合に便利です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cd3c45125">&#167;</a></small></p>
</ol>
<h4>pg_upgrade</h4>
<ol>
<li>pg_upgrade でメジャーバージョンアップする際にプランナ統計情報を移行できるようになりました。ただし、拡張統計情報は移行されません。  (Corey Huinker, Jeff Davis, Nathan Bossart) (18)</li>
<p>
統計情報を移行しない場合は、--no-statistics オプションを指定します。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1fd1bd871">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c9d502eb6">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=d5f1b6a75">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1fd1bd871">&#167;</a></small></p>
<li>pg_upgradeの--jobsオプションで並列実行数を指定することで、複数のデータベースを同時に処理できるようになりました。  (Nathan Bossart) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=40e2e5e92">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6d3d2e8e5">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7baa36de5">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=46cad8b31">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6ab8f27bc">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=bbf83cab9">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9db3018cf">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c34eabfbb">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cf2f82a37">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f93f5f7b9">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c880cf258">&#167;</a></small></p>
<li>pg_upgradeにオプション--swapが追加されました。  (Nathan Bossart) (18)</li>
<p>
このオプションでディレクトリ全体を入れ替えるので、大量にDB オブジェクトがある環境では従来の--copyや--link、--cloneオプションを使うよりも高速になることがあります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=626d7236b">&#167;</a></small></p>
<li>pg_upgradeにオプション--set-char-signednessが追加されました。このオプションで新しいクラスタのデフォルトのchar型の符号つき/符号なし(signed/unsigned)を設定できます。  (Masahiko Sawada) (18)</li>
<p>
これはPostgreSQL 18より前のクラスタのデフォルトのCPU符号が新しいクラスタと一致しない場合に対応できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a8238f87f">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=1aab68059">&#167;</a></small></p>
</ol>
<h4>論理レプリケーション</h4>
<ol>
<li>pg_createsubscriberにオプション--allが追加されました。このオプションで全てのデータベースの論理レプリカが作成されます。  (Shubham Khanna) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fb2ea12f4">&#167;</a></small></p>
<li>pg_createsubscriberにオプション--cleanが追加されました。このオプションで現在はパブリケーションのみが削除できます。  (Shubham Khanna) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e5aeed4b8">&#167;</a></small></p>
<li>pg_createsubscriberにオプション--enable-two-phaseが追加されました。このオプションでサブスクリプションの二相コミットを有効にします。  (Shubham Khanna) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e117cfb2f">&#167;</a></small></p>
<li>pg_recvlogicalに--enable-failoverオプションが追加され、フェイルオーバースロットを指定できるようになりました。  (Hayato Kuroda) (18)</li>
<p>
これにより、pg_recvlogicalがフェイルオーバーオプションを有効にした状態で論理レプリケーションスロットを作成できるようになりました。本オプションは--create-slotオプションと一緒に使用します。
</p>
<p>
また、--two-phaseの同義語として--enable-two-phaseオプションが追加され、--two-phaseは非推奨となりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cf2655a90">&#167;</a></small></p>
<li>pg_recvlogicalの--drop-slotオプションが、--dbnameを指定しなくても動作するようになりました。  (Hayato Kuroda) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c68100aa4">&#167;</a></small></p>
</ol>
<h4>ソースコード</h4>
<ol>
<li>インジェクションポイントの読み込みと実行が分離されました。  (Michael Paquier, Heikki Linnakangas) (18)</li>
<p>
INJECTION_POINT_LOAD()マクロで、インジェクションポイントを作成するけれど実行しない、ということができるようになりました。作成したインジェクションポイントはINJECTION_POINT_CACHED()マクロで実行できます。
</p>
<p>
この分離は、メモリ割り当て不能なクリティカルセクションにインジェクションポイントを付加するときに有用です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4b211003e">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a0a5869a8">&#167;</a></small></p>
<li>インジェクションポイントで実行時引数がサポートされました。  (Michael Paquier) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=371f2db8b">&#167;</a></small></p>
<li>IS_INJECTION_POINT_ATTACHED()マクロが追加されました。  (Heikki Linnakangas) (18)</li>
<p>
これにより、通常のソースコード内でインジェクションポイントがアタッチされているかを検査するコードが書けます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=20e0e7da9">&#167;</a></small></p>
<li>SIMD(Single Instruction Multiple Data)を使用することで、長いJSON文字列の処理性能が向上しました。  (David Rowley) (18)</li>
<p>
特に、長いテキストプロパティを持つJSONオブジェクトで効果的です。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ca6fde922">&#167;</a></small></p>
<li>x86のAVX-512命令を使用することで、CRC32C計算が高速化されました。  (Raghuveer Devulapalli, Paul Amonson) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3c6e8c123">&#167;</a></small></p>
<li>popcount（整数のビットカウント）に対して、ARMのNeonおよびSVE CPU命令が追加されました。  (Chiranmoy Bhattacharya, Devanga Susmitha, Rama Malladi) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6be53c276">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=519338ace">&#167;</a></small></p>
<li>numeric型の乗算および除算の処理速度が向上しました。  (Joel Jacobson, Dean Rasheed) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ca481d3c9">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c4e44224c">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8dc28d7eb">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9428c001f">&#167;</a></small></p>
<li>configureオプションにNUMA対応を有効にする--with-libnumaが追加されました。  (Jakub Wartak, Bertrand Drouvot) (18)</li>
<p>
NUMA対応状況は関数pg_numa_available()で確認できます。NUMA対応が有効である場合、システムビューpg_shmem_allocations_numaとpg_buffercache_numaで共有メモリのNUMAノード間での分布状況を確認できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=65c298f61">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8cc139bec">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ba2a3c230">&#167;</a></small></p>
<li>非常に大きな式インデックスを可能にするために、システムテーブルpg_indexにTOASTテーブルが追加されました。  (Nathan Bossart) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=b52c4fc3c">&#167;</a></small></p>
<li>システムテーブルpg_attributeから、attcacheoff列が削除されました。  (David Rowley) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=02a8d0c45">&#167;</a></small></p>
<li>システムテーブルpg_classから、relallfrozen列が追加されました。  (Melanie Plageman) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=99f8f3fbb">&#167;</a></small></p>
<li>インデックスアクセスメソッドのAPIルーチンに、amgettreeheight、amconsistentequality、amconsistentorderingが追加されました。  (Mark Dilger) (18)</li>
<p>
amgettreeheightが新規追加で、amconsistentequalityとamconsistentorderingはamcancrosscompareを分割改名したものです。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=56fead44d">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=af4002b38">&#167;</a></small></p>
<li>GiSTのサポート関数stratnum()が追加されました。  (Paul A. Jungwirth) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7406ab623">&#167;</a></small></p>
<li>ビルドにおける「char」のデフォルトのCPU符号属性(signedかunsigned)が、コントロールデータに記録され、pg_controldataコマンドで出力されるようになりました。  (Masahiko Sawada) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=44fe30fda">&#167;</a></small></p>
<li>plpythonでPythonの「Limited API」のサポートが追加されました。  (Peter Eisentraut) (18)</li>
<p>
Python 3.x のバージョン不一致によって発生する問題の防止に役立ちます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=72a3d0462">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=0793ab810">&#167;</a></small></p>
<li>サポートされるPythonの最小バージョンが3.6.8に変更されました。  (Jacob Champion) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=45363fca6">&#167;</a></small></p>
<li>OpenSSL 1.1.1より古いバージョンがサポートされなくなりました。  (Daniel Gustafsson) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a70e01d43">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6c66b7443">&#167;</a></small></p>
<li>LLVMを有効するために、LLVMバージョン14以降が必要となりました。  (Thomas Munro) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=972c2cd28">&#167;</a></small></p>
<li>拡張が自分自身の名前とバージョンを報告できるように、PG_MODULE_MAGIC_EXTマクロが追加されました。  (Andrei Lepikhov) (18)</li>
<p>
この情報は新たなpg_get_loaded_modules()関数を介して参照できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9324c8c58">&#167;</a></small></p>
<li>SPI_connect()/SPI_connect_ext()は常に成功（SPI_OK_CONNECT）を返すことが、文書化されました。  (Stepan Neretin) (18)</li>
<p>
エラーは常にereport()を介して報告されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=218527d01">&#167;</a></small></p>
<li>APIおよびABI互換性に関するドキュメントのセクションが追加されました。  (David Wheeler, Peter Eisentraut) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e54a42ac9">&#167;</a></small></p>
<li>ドキュメントでWindows上のMesonビルドが実験的という扱いではなくなりました。  (Aleksander Alekseev) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=5afaba629">&#167;</a></small></p>
<li>configureオプションの「--disable-spinlocks」と「--disable-atomics」が削除されました。  (Thomas Munro) (18)</li>
<p>
32ビットのアトミック操作は必須となりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e25626677">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=813852613">&#167;</a></small></p>
<li>HPPA/PA-RISCアーキテクチャのサポートが削除されました。  (Tom Lane) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=edadeb071">&#167;</a></small></p>
</ol>
<h4>追加モジュール</h4>
<ol>
<li>論理スナップショットを検査するpg_logicalinspect拡張が追加されました。  (Bertrand Drouvot) (18)</li>
<p>
論理レプリケーション等で使われる$PGDATA/pg_logical/snapshots/以下の.snapファイルについて、情報を得る関数が提供されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7cdfeee32">&#167;</a></small></p>
<li>EXPLAIN出力に詳細デバッグ情報等を追加するpg_overexplain拡張が追加されました。  (Robert Haas) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=8d5ceb113">&#167;</a></small></p>
<li>postgres_fdwでpostgres_fdw_get_connections()関数の出力列が追加されました。  (Hayato Kuroda, Sagar Dilip Shedge) (18)</li>
<p>
新しい出力列は以下の4つです。
</p>
<pre>
used_in_xact       現在のトランザクションで使用されているか
closed             接続が閉じられているか
user_name          ユーザ名
remote_backend_pid リモートのバックエンドプロセスのPID
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c297a47c5">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=857df3cef">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4f08ab554">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=fe186bda7">&#167;</a></small></p>
<li>クライアントからのSCRAM認証をpostgres-fdwサーバに渡せるようになりました。  (Matheus Alcantara, Peter Eisentraut) (18)</li>
<p>
これにより、postgres_fdwの認証情報をデータベースに格納しなくて済みます。これはuse_scram_passthrough接続オプションで有効になります。このとき、libpqで新しい接続パラメータlibpq_connect_scram_client_keyおよびlibpq_connect_scram_server_keyが使用されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=761c79508">&#167;</a></small></p>
<li>クライアントからのSCRAM認証をdblinkに渡せるようになりました。  (Matheus Alcantara) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=3642df265">&#167;</a></small></p>
<li>file_fdwにon_errorオプションとlog_verbosityオプションが追加されました。  (Atsushi Torikoshi) (18)</li>
<p>
on_errorオプションにignoreを指定することで入力ファイルの不正な行をスキップしてクエリを実行可能になりました。またlog_verbosityオプションでエラーや警告のログ出力の詳細度を指定できるようになりました。いずれのオプションも外部テーブルに対するSELECT、ANALYZE操作に適用されます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=a1c4c8a9e">&#167;</a></small></p>
<li>file_fdwがスキップできるエラー行の上限数を制御するREJECT_LIMITオプションが追加されました。  (Atsushi Torikoshi) (18)</li>
<p>
このオプションはon_errorオプションがignoreの時のみ有効になります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6c8f67032">&#167;</a></small></p>
<li>passwordcheckモジュールにパスワードの最小の長さを指定できるmin_password_lengthパラメータが追加されました。  (Emanuele Musella, Maurizio Boriani) (18)</li>
<p>
ユーザーが事前に暗号化されたパスワードを入力した場合は、このパラメータは無効となります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=f7e1b3828">&#167;</a></small></p>
<li>pgbenchの結果出力で、失敗・試行・スキップしたトランザクションも報告するようになりました。  (Yugo Nagata) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cae0f3c40">&#167;</a></small></p>
<li>isn拡張に無効な検査数字の受け入れを制御するサーバ変数weakが追加されました。  (Viktor Holmberg) (18)</li>
<p>
以前のweakは静的変数で、関数isn_weak()でのみ制御されていました。weakをGUCパラメータとしたことで、トランザクション単位での変更やRESET文でデフォルト値に戻すことが可能になりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=448904423">&#167;</a></small></p>
<li>btree_gist拡張のソートサポートが有効になり、Gistインデックスの構築が高速に行えるようになりました。  (Bernd Helmle, Andrey Borodin) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=e4309f73f">&#167;</a></small></p>
<li>amcheckモジュールにGINインデックスの整合性を検証する関数gin_index_check()が追加され、親子関係の一貫性と木構造のバランスをチェックできるようになりました。  (Grigory Kryachko, Heikki Linnakangas, Andrey Borodin) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=14ffaece0">&#167;</a></small></p>
<li>未固定の共有バッファを追い出す関数pg_buffercache_evict_relation()と関数pg_buffercache_evict_all()が追加されました。  (Nazir Bilal Yavuz) (18)</li>
<p>
関数pg_buffercache_evict_relation()は指定したリレーションの共有バッファをすべて追い出し、関数pg_buffercache_evict_all()は全共有バッファを一括で追い出すことができます。既存の関数pg_buffercache_evict()は、バッファがフラッシュされたかどうかの状態を返すようになりました。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=dcf7e1697">&#167;</a></small></p>
<li>拡張モジュールが独自のEXPLAINオプションを登録・管理できるようにする機能が追加されました。  (Robert Haas, Sami Imseih) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=c65bc2e1d">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=4fd02bf7c">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=50ba65e73">&#167;</a></small></p>
<li>拡張機能がサーバの累積統計情報APIを利用できるようになりました。  (Michael Paquier) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=7949d9594">&#167;</a> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=2eff9e678">&#167;</a></small></p>
</ol>
<h4>pg_stat_statements</h4>
<ol>
<li>pg_stat_statementsでCREATE TABLE ASおよびDECLAREを追跡できるようになりました。  (Anthonin Bonnefoy) (18)</li>
<p>
これらの問合せに対してクエリIDが割り当てられるようになります。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=6b652e6ce">&#167;</a></small></p>
<li>pg_stat_statementsでSET文の値のパラメータ化が可能になりました。  (Greg Sabino Mullane, Michael Paquier) (18)</li>
<p>
これまで指定値が異なるだけで別エントリになっていたものを集約できるため、データ量の膨張を減らします。
</p>
<pre>
(実行例)
db1=# set enable_seqscan=false;
db1=# set enable_seqscan=true;
db1=# SELECT query, calls, rows FROM pg_stat_statements;
                       query                       | calls | rows
---------------------------------------------------+-------+------
 set enable_seqscan=$1                             |     2 |    0

(17.xでは以下)
db1=# SELECT query, calls, rows FROM pg_stat_statements;
                       query                       | calls | rows
---------------------------------------------------+-------+------
 set enable_seqscan=false                          |     1 |    0
 set enable_seqscan=true                           |     1 |    0
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=dc6851596">&#167;</a></small></p>
<li>pg_stat_statementsに並列処理の動作を報告する列が追加されました。  (Guillaume Lelarge) (18)</li>
<p>
追加された列は以下です。
</p>
<pre>
  parallel_workers_to_launch : 実行計画のパラレルワーカー数
  parallel_workers_launched  : 実際に起動されたワーカー数
</pre>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=cf54a2c00">&#167;</a></small></p>
<li>pg_stat_statementsにWALバッファが満杯になった回数を報告するwal_buffers_full列が追加されました。  (Bertrand Drouvot) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=ce5bcc4a9">&#167;</a></small></p>
</ol>
<h4>pgcrypto</h4>
<ol>
<li>pgcryptoにハッシュアルゴリズムsha256cryptおよびsha512cryptが追加されました。  (Bernd Helmle) (18)</li>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=749a9e20c">&#167;</a></small></p>
<li>pgcryptoのAES暗号化/復号化にCFB(Cipher Feedback)モードが追加されました。  (Umar Hayat) (18)</li>
<p>
暗号タイプに'aes-cfb'と指定して使用できます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=9ad1b3d01">&#167;</a></small></p>
<li>サーバのFIPSモードを報告する関数fips_mode()が追加されました。  (Daniel Gustafsson) (18)</li>
<p>
FIPSモードとは米国の連邦情報処理標準に準拠した暗号化方式のみを使用する構成です。本関数はPostgreSQLから使用されているOpenSSLがFIPSモードであるかを返します。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=924d89a35">&#167;</a></small></p>
<li>pgcryptoに設定パラメータpgcrypto.builtin_crypto_enabledが追加され、組み込みの非FIPSモードの暗号化関数を無効化できるようになりました。  (Daniel Gustafsson, Joe Conway) (18)</li>
<p>
これはFIPSモードの動作を保証するために役立ちます。
</p>
<p><small> <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;h=035f99cbe">&#167;</a></small></p>
</ol>

<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

<div>
<div style="background-color: #fffacd; padding: 20px; border-radius: 8px; text-align: center;">2026/10/27（火）「PostgreSQL 19 リリース記念セミナー」開催！<br />
コントリビューターが新機能をわかりやすく解説します。<br />
詳しくは<a href="https://www.sraoss.co.jp/event_seminar/detail/20261027-postgresql19-webinar/?utm_source=techblog&amp;utm_medium=email&amp;utm_campaign=pg19-seminar" target="_blank" rel="noopener"><strong style="color: #2581c4;">こちら</strong></a>をご覧ください。</div>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pacemaker のプロセス構成と状態遷移の仕組み</title>
		<link>https://www.sraoss.co.jp/tech-blog/pacemaker/pacemaker-processes/</link>
		
		<dc:creator><![CDATA[彭 博 (Bo Peng)]]></dc:creator>
		<pubDate>Wed, 24 Sep 2025 03:35:04 +0000</pubDate>
				<category><![CDATA[Pacemaker]]></category>
		<category><![CDATA[Corosync]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=18565</guid>

					<description><![CDATA[Pacemaker/Corosync は、Linux 環境で高可用性クラスタを構築するためのオープンソースのクラスタリングソフトウェアです。複数ノードにまたがるリソースの起動、停止、監視を自動的に行い、障害発生時にはフェ ...]]></description>
										<content:encoded><![CDATA[<p><a href="http://www.clusterlabs.org/pacemaker/" target="_blank" rel="noopener">Pacemaker/Corosync</a> は、Linux 環境で高可用性クラスタを構築するためのオープンソースのクラスタリングソフトウェアです。複数ノードにまたがるリソースの起動、停止、監視を自動的に行い、障害発生時にはフェイルオーバーを実施することで、システムの継続稼働を実現します。</p>
<p><span id="more-18565"></span></p>
<p>内部的には複数のデーモンプロセスがそれぞれ役割を担い、連携しながら動作しています。本記事では、Pacemaker/Corosync のプロセス構成とプロセス間のデータ処理の流れ、さらに状態遷移の仕組みについて解説します。</p>
<p>※バージョンによって挙動が異なる場合があるため、本記事では Pacemaker 2.1 を前提としています。</p>
<h2>Pacemaker/Corosync のプロセス構成</h2>
<p>Pacemaker の内部では、複数のデーモンプロセスが役割を分担し、クラスタ全体の監視、制御、リソース管理を行います。一方、Corosync はクラスタを構成するノード間の通信や死活監視、クォーラム管理を担当するプロセスです。両者が連携することで、障害が発生した場合でもサービスを継続できる、高可用性クラスタを実現できます。</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-18568" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-scaled.png" alt="" width="2560" height="1643" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-scaled.png 2560w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-300x192.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-1024x657.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-768x493.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-1536x986.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-2048x1314.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-304x195.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/09/processes-282x181.png 282w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /></p>
<p>&nbsp;</p>
<p>主要なプロセスの役割は以下のとおりです。</p>
<h3><strong>pacemakerd</strong></h3>
<p>Pacemaker クラスタ全体の管理を担う親デーモンであり、以下の各サブデーモンプロセスの起動・監視を行い、異常時は再起動します。</p>
<h3><strong>pacemaker-based</strong></h3>
<p>クラスタの設定や状態情報を保持する CIB (Cluster Information Base、詳細は後述) を管理するプロセスです。CIB は XML 形式で構造化されており、クラスタ設定やリソースの構成、ノードの状態などが記録されています。<code>pacemaker-based</code> は CIB の読み書きを行い、常に最新の情報を反映させるとともに、複数ノード間で内容が一致するよう同期処理を行い、クラスタ全体の一貫性を維持します。</p>
<h3><strong>pacemaker-attrd</strong></h3>
<p>クラスタノードやリソースに関する動的属性情報 (稼働状況、フェイルカウントなど) を管理するプロセスです。<code>pacemaker-attrd</code> は各ノードから収集した属性情報を保持し、必要に応じてクラスタ全体に伝達します。</p>
<h3><strong>pacemaker-schedulerd</strong></h3>
<p>CIB の情報をもとに、どのノードでどのリソースを動かすかを決定するプロセスです。フェイルオーバー時のリソース配置計画もここで決定されます。</p>
<h3><strong>pacemaker-controld</strong></h3>
<p>Pacemaker クラスタにおける「調整役」を担うプロセスです。このプロセスは <code>pacemaker-schedulerd</code> が決定した計画に基づき、各ノード上の <code>pacemaker-execd</code> に対してリソースの起動、停止、監視を指示します。</p>
<h3><strong>pacemaker-execd</strong></h3>
<p>ローカルノード上でリソースエージェントの起動、停止、監視を実行するプロセスです。操作結果は <code>pacemaker-controld</code> に報告され、クラスタ全体の判断材料として利用されます。</p>
<h3><strong>pacemaker-fenced</strong></h3>
<p>障害を起こしたノードを強制的にリブートまたはシャットダウンするフェンシングを担当するプロセスです。データ破壊や二重書き込みなどの重大な障害を防ぐため、STONITH デバイスを操作して信頼できないノードをクラスタから隔離します。</p>
<p>なお、Pacemaker 2.0 系ではプロセス名が変更されました。ただし、機能自体は従来と同じです。旧プロセス名との対応関係を以下の表に示します。</p>
<table>
<thead>
<tr>
<th width="300"><strong>旧プロセス名</strong></th>
<th width="300"><strong>新プロセス名</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>cib</td>
<td>pacemaker-based</td>
</tr>
<tr>
<td>attrd</td>
<td>pacemaker-attrd</td>
</tr>
<tr>
<td>pengine</td>
<td>pacemaker-schedulerd</td>
</tr>
<tr>
<td>crmd</td>
<td>pacemaker-controld</td>
</tr>
<tr>
<td>lrmd</td>
<td>pacemaker-execd</td>
</tr>
<tr>
<td>stonithd</td>
<td>pacemaker-fenced</td>
</tr>
</tbody>
</table>
<h2>CIB (Cluster Information Base) とは</h2>
<p>Pacemaker では、各プロセスが CIB を中心に情報を共有・同期することで、クラスタ全体の一貫性を保っています。</p>
<p>CIB は XML 形式で管理されるクラスタ情報のデータベースであり、クラスタの構成や各リソースの状態を記録します。CIB には、クラスタの状態変化に応じてリアルタイムで更新される動的な情報が保持されており、クラスタ全体の整合性を維持するうえで重要な役割を担っています。各ノード上の <code>pacemaker-based</code> プロセスが CIB を管理し、更新や同期を行うことで、<code>pacemaker-schedulerd</code> は常に最新の情報に基づいてリソースの配置やフェイルオーバーの判断を行うことができます。</p>
<p>CIB の構造は主に以下のセクションで構成されています。</p>
<pre>&lt;cib crm_feature_set="3.19.6" ...&gt;
  &lt;configuration&gt;
    &lt;!-- クラスタ設定（リソース定義、制約、ノード設定など） --&gt;
  &lt;/configuration&gt;
  &lt;status&gt;
    &lt;!-- 実行中のリソースの状態やノードの状態 --&gt;
  &lt;/status&gt;
&lt;/cib&gt;
</pre>
<h2>プロセス間データ処理の流れと状態遷移の仕組み</h2>
<p>Pacemaker では、複数のサブデーモンが連携してクラスタを制御します。その中心的役割を担う <strong data-start="367" data-end="389">pacemaker-controld</strong> は、クラスタの「頭脳」として動作し、ノードの参加・離脱、リソースの起動・停止、フェイルオーバーなど、クラスタ内で発生する各種イベントに応じて内部状態を遷移させつつ、クラスタ全体を制御します。</p>
<p>代表的な状態は次のとおりです。</p>
<table>
<thead>
<tr>
<th width="300"><strong>状態</strong></th>
<th width="300"><strong>説明</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>S_STARTING</td>
<td>初期化中</td>
</tr>
<tr>
<td>S_PENDING</td>
<td>クラスタ構成情報や他ノードの参加を待機中</td>
</tr>
<tr>
<td>S_ELECTION</td>
<td>DC を決定するための選挙中</td>
</tr>
<tr>
<td>S_INTEGRATION</td>
<td>他ノードの JOIN 要求を受け入れ、クラスタ統合を進める</td>
</tr>
<tr>
<td>S_FINALIZE_JOIN</td>
<td>JOIN を確定し、クラスタメンバーシップを確立</td>
</tr>
<tr>
<td>S_POLICY_ENGINE</td>
<td>リソース配置計算を実施中</td>
</tr>
<tr>
<td>S_TRANSITION_ENGINE</td>
<td>リソース操作を実行中</td>
</tr>
<tr>
<td>S_IDLE</td>
<td>安定状態</td>
</tr>
</tbody>
</table>
<p>次に、一例として 起動時および障害発生時における状態遷移の流れについて解説します。</p>
<h3>起動時の状態遷移</h3>
<p>クラスタの起動時、Pacemaker の各サブデーモンは協調しながら、ノード間でメンバーシップを確立し、リソース配置を決定します。このプロセスは段階的に進み、各状態で必要な初期化や情報収集、計算処理が行われた上で、最終的にクラスタは安定状態に到達します。</p>
<pre><strong>起動</strong>
│  
│  <span style="font-size: 12px;">親デーモン pacemakerd が起動し、各サブデーモンをを順次起動</span>
│  <span style="font-size: 12px;">(controld, schedulerd, execd, based, attrd, fenced)</span>
│
▼
<strong>S_STARTING (初期化開始)</strong>
│
│  <span style="font-size: 12px;">自ノード (node1) の状態を unknown → member に更新</span>
│  <span style="font-size: 12px;">CIB 読み込み、Corosync 接続</span>
│  <span style="font-size: 12px;">他ノードの参加を待機</span>
│
▼
<strong>S_PENDING (待機)</strong>
│
│  <span style="font-size: 12px;">node2 の参加を検知</span>
│  <span style="font-size: 12px;">DC 選挙開始</span>
│
▼
<strong>S_ELECTION (DC選挙)</strong>
│
│  <span style="font-size: 12px;">投票の結果、node1 が DC に選出</span>
│
▼
<strong>S_INTEGRATION (ノード統合)</strong>
│
│  <span style="font-size: 12px;">JOIN 要求を受け入れ、node2 をクラスタに統合</span>
|
▼
<strong>S_FINALIZE_JOIN (JOIN確定)</strong>
│ 
│  <span style="font-size: 12px;">クラスタメンバーシップを確定</span>
│  
│  <span style="font-size: 12px;">* pacemaker-based</span>
│     <span style="font-size: 12px;">JOIN が完了したノード情報を CIB に反映</span>
│  
▼
<strong>S_POLICY_ENGINE</strong>
│
│  <span style="font-size: 12px;">* pacemaker-schedulerd</span>
│     <span style="font-size: 12px;">DC (node1) が決定後、リソース配置計算を開始</span>
│     <span style="font-size: 12px;">クラスタ全体のリソースの起動／配置プランを生成</span>
│     <span style="font-size: 12px;">計算結果を pacemaker-controld に渡す</span>
│
▼
<strong>S_TRANSITION_ENGINE</strong>
│
│  <span style="font-size: 12px;">* pacemaker-execd</span>
│     <span style="font-size: 12px;">pacemaker-controld の指示に従って start/stop/monitor を実行</span>
│     <span style="font-size: 12px;">成否を pacemaker-controld にフィードバック</span>
│
│  <span style="font-size: 12px;">* pacemaker-controld</span>
│     <span style="font-size: 12px;">リソース操作の成功を確認</span>
│
▼
<strong>S_IDLE (安定状態)</strong>
│
│  <span style="font-size: 12px;">リソース操作がすべて正常終了</span>
│  <span style="font-size: 12px;">クラスタは安定状態に遷移</span>
│
</pre>
<h3>障害発生時の状態遷移</h3>
<p>クラスタ稼働中にリソース障害やノード障害が発生した場合、Pacemaker はそのイベントを検知し、自動的に回復処理を行います。障害発生時は、クラスタが持つ最新の CIB 情報に基づいて、フェイルオーバーや再起動などのアクションを決定し、適切に実行します。</p>
<pre><strong>S_IDLE (安定状態)</strong>
│
│  <span style="font-size: 12px;">クラスタは安定稼働中</span>
│  <span style="font-size: 12px;">* pacemaker-execd (node1)</span>
│     <span style="font-size: 12px;">VIP_monitor_10000 が定期的に実行される</span>
│     <span style="font-size: 12px;">結果: 失敗 (rc=7, not running)</span>
│     <span style="font-size: 12px;">この結果を pacemaker-controld に返却</span>
│  
│  <span style="font-size: 12px;">* pacemaker-controld (node1)</span>
│     <span style="font-size: 12px;">monitor 失敗を検知</span>
│     <span style="font-size: 12px;">CIB 更新要求を pacemaker-based に送信</span>
│  
│  <span style="font-size: 12px;">* pacemaker-based (node1)</span>
│     <span style="font-size: 12px;">CIB 更新要求を処理</span>
│     <span style="font-size: 12px;">CIB をディスクに書き込み</span>
│
│  <span style="font-size: 12px;">* pacemaker-attrd (node1)</span>
│     <span style="font-size: 12px;">属性を更新：</span>
│        <span style="font-size: 10px;">・last-failure-VIP#monitor_10000[node1] = 1756193718</span>
│        <span style="font-size: 10px;">・fail-count-VIP#monitor_10000[node1] = 1</span>
│     <span style="font-size: 12px;">CIB に反映</span>
│
▼
<strong>S_POLICY_ENGINE (リソース配置計算)</strong>
│
│  <span style="font-size: 12px;">* pacemaker-schedulerd (node1)</span>
│     <span style="font-size: 12px;">CIB の変更を検知し、リソース配置計算を再実行</span>
│     <span style="font-size: 12px;">migration-threshold=1 のため node1 での再起動不可と判断</span>
│     <span style="font-size: 12px;">VIP を node2 へ移動する決定</span>
│     <span style="font-size: 12px;">Transition 10（遷移グラフ）を生成：</span>
│       <span style="font-size: 10px;">・VIP_stop on node1</span>
│       <span style="font-size: 10px;">・VIP_start on node2</span>
│       <span style="font-size: 10px;">・VIP_monitor_10000 on node2 (recurring)</span>
│
▼
<strong>S_TRANSITION_ENGINE (アクション実行)</strong>
│
│  <span style="font-size: 12px;">* pacemaker-controld (node1)</span>
│     <span style="font-size: 12px;">pacemaker-schedulerd から受け取った Transition 10 を順次実行</span>
│     <span style="font-size: 12px;">まず pacemaker-execd (node1) に VIP_stop を要求</span>
│  
│  <span style="font-size: 12px;">* pacemaker-execd (node1)</span>
│     <span style="font-size: 12px;">VIP_stop を実行し、結果を pacemaker-controld に返却</span>
│
│  <span style="font-size: 12px;">* pacemaker-controld (node1)</span>
│     <span style="font-size: 12px;">次に node2 に VIP_start を指示</span>
│
│  <span style="font-size: 12px;">* pacemaker-execd (node2)</span>
│     <span style="font-size: 12px;">VIP_start を実行</span>
│     <span style="font-size: 12px;">VIP_monitor_10000 を開始</span>
│     <span style="font-size: 12px;">結果を pacemaker-controld (node2) に返却</span>
│
▼
<strong>S_IDLE (安定状態復帰)</strong>
│
│  <span style="font-size: 12px;">VIP が node2 上で正常稼働開始</span>
│  <span style="font-size: 12px;">monitor 監視も復帰</span>
│  <span style="font-size: 12px;">クラスタは再び安定状態へ移行</span>
│
</pre>
<h2>おわりに</h2>
<p data-start="48" data-end="134">今回は、Pacemaker/Corosync のプロセス構成と、<code>pacemaker-controld</code> を中心とした状態遷移の仕組みについて解説しました。</p>
<p data-start="136" data-end="286">Pacemaker は複数のデーモンプロセスが協調して動作しており、CIB を中心とした情報共有や状態遷移の制御を正しく理解することで、クラスタの挙動をより深く把握できます。これにより、トラブルシューティングやクラスタ構成の最適化を行う際に大いに役立つでしょう。</p>
<p data-start="136" data-end="286"><div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>
</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
