hdfs_fdwの機能的評価
はじめに
前回はビッグデータ向けのFDWを紹介し、Hadoop(HDFS)用のFDWであるhdfs_fdwの概要と使い方のノウハウを解説してきました。今回と次回は、hdfs_fdwの実装を確認して機能的な評価を行うとともに、業務的な面からコストや性能を評価し、利用場面等を検討していきたいと思います。
PostgreSQLでのFDWの仕組み
PostgreSQLはFDWのインタフェースをC言語の関数インタフェースとして規定しており、FDW開発者はその規定に従って実装します。
PostgreSQLはSQL実行の過程で、FDWによる外部データアクセスが必要な場合にその関数を呼びます。
関数インタフェースの詳細についてはマニュアルの「PostgreSQL 10.4文書 - 56.1. 外部データラッパ関数」を参照してください。
hdfs_fdwの機能的評価
FDWの機能範囲は、マニュアルなどの仕様を記載したドキュメントがあれば簡単に確認できます。一方hdfs_fdwは簡単な説明ドキュメント(readme.md)しかなく、機能範囲が良くわかりません。そこで、hdfs_fdwで実装されている関数の実装を確認し、機能を評価してみたいと思います。
外部テーブルスキャンのための関数(必須)
表1の関数は外部テーブルをスキャンしデータを取得するという基本的な処理を行うものです。FDWの作成に必須の関数のため、hdfs_fdwにおいても全て対応しています。
関数 | 概要 | 対応状況 | |
---|---|---|---|
プランナ | GetForeignRelSize | 外部テーブルのリレーションサイズ見積もりを取得します。 | ○(対応) |
GetForeignPaths | 外部テーブルに対するスキャンとして可能なアクセスパスを作成します。 | ○(対応) | |
GetForeignPlan | 選択された外部アクセスパスからForeignScanプランノードを作成します。 | ○(対応) | |
エグゼキュータ | BeginForeignScan | 外部テーブルスキャンの実行を開始します。 | ○(対応) |
IterateForeignScan | 外部ソースから一行を取り出して、それをタプルテーブルスロットに入れて返します。 | ○(対応) | |
ReScanForeignScan | 先頭からスキャンを再開します。 | ○(対応) | |
EndForeignScan | スキャンを終了しリソースを解放します。 | ○(対応) |
以降の機能は、オプションになります。
外部テーブルの結合をスキャンするための関数
表2に、FDWが外部テーブルをリモートで結合することをサポートする関数を記載しましたが、未対応の状況です。Hadoopは一般的に複数ノード構成のため、外部テーブルをHadoop側で結合しようとすると、中間データのディスク書き込みやノード間のデータ転送が発生し遅くなります。本機能が未対応なのは、結合したデータをあらかじめ作っておくことが推奨されていて、Hadoopではテーブルを結合しない前提であるからと想像します。
ただし、RDBMS側の業務データと連携する場合には、分析などのために結合や集計等の処理を行うと考えられ、そのたびにサーバ側のリソースやネットワーク帯域を圧迫するといった問題が発生します。そのため対応が望まれる機能の一つといえます。
関数 | 概要 | 対応状況 |
---|---|---|
GetForeignJoinPaths | 同じ外部サーバにある2つ以上の外部テーブルのためのアクセスパスを作成します。 | ×(未対応) |
スキャン/結合後の処理をプラン生成するための関数
表3に、グルーピングや集約のような処理のリモート実行をサポートする関数を記載しました。やはり未対応なのは、本機能もHadoop側で処理しようとすると非常にコストがかかるためであると想像します。なお、上記の結合処理に比べると対応の優先度は低いといえます。
関数 | 概要 | 対応状況 |
---|---|---|
GetForeignUpperPaths | 上位リレーション(ウィンドウ関数、ソート、テーブル更新など、全てのスキャン/結合後の問い合わせ)処理のための、ありうるアクセスパスを作成します。 | ×(未対応) |
外部テーブルを更新するための関数
表4にまとめましたが、更新関数については未サポートと表記があり、利用はできません(TODOリストには、対応したいとの記載がありました)。ただし、HDFSをFDW経由で使用するのは分析・整理などの参照を主とする業務が多いと考えられますので、更新系の機能に対応していなくても、業務への影響は少ないと考えます。
関数 | 概要 | 対応状況 |
---|---|---|
AddForeignUpdateTargets | 更新や削除の対象行を厳密に識別できるように、UPDATEやDELETEの間に外部テーブルから取得される列のリストに追加の隠された(または「ジャンクの」)ターゲット列を追加します。 | ×(未対応) |
PlanForeignModify | 外部テーブルに対する挿入、更新、削除に必要となる、追加のプラン生成アクションを実行します。 | ×(未対応) |
BeginForeignModify | 外部テーブルへの変更操作の実行を開始します。 | ×(未対応) |
ExecForeignInsert | 外部テーブルにタプルを一つ挿入します。 | ×(未対応) |
ExecForeignUpdate | 外部テーブル内のタプルを一つ更新します。 | ×(未対応) |
ExecForeignDelete | 外部テーブルからタプルを一つ削除します。 | ×(未対応) |
EndForeignModify | テーブル更新を終えてリソースを解放します。 | ×(未対応) |
IsForeignRelUpdatable | 指定された外部テーブルがどの更新処理をサポートしているかを報告します。 | ×(未対応) |
PlanDirectModify | リモートサーバ上で直接変更を実行することが安全かを判断します。 | ×(未対応) |
BeginDirectModify | リモートサーバでの直接変更を実行する準備をします。 | ×(未対応) |
IterateDirectModify | リモートサーバでの直接変更を実行します。 | ×(未対応) |
EndDirectModify | リモートサーバでの直接変更の後、クリーンアップします。 | ×(未対応) |
行ロックのための関数
表5に行ロックの関数をまとめました。行ロックは基本的に更新処理で使用されるため、更新する関数が未対応の現状では、これらの関数も未対応で問題ないといえます。
関数 | 概要 | 対応状況 |
---|---|---|
GetForeignRowMarkType | 遅延行ロックをサポートするため、行の印付けでどのオプションを外部テーブルに使うかを報告します。 | ×(未対応) |
RefetchForeignRow | ロックした後で、外部テーブルから1つのタプルを再フェッチします。 | ×(未対応) |
RecheckForeignScan | 以前に戻されたタプルが、関連するスキャンおよび結合の制約とまだ一致しているか再検査します。 | ×(未対応) |
EXPLAINのための関数
表6にEXPLAIN関数の対応状況をまとめました。参照系のEXPLAINは対応、更新系のEXPLAINは未対応と、今までの関数の対応状況とマッチしています。
関数 | 概要 | 対応状況 |
---|---|---|
ExplainForeignScan | 外部テーブルスキャンの追加のEXPLAIN出力を表示します。 | ○(対応) |
ExplainForeignModify | 外部テーブル更新の追加のEXPLAIN出力を表示します。 | ×(未対応) |
ExplainDirectModify | リモートサーバでの直接変更について追加EXPLAIN出力を表示します。 | ×(未対応) |
ANALYZEのための関数
表7にANALYZEの関数を記載しました。サンプル収集関数は対応していませんが、ANALYZE自体には対応しています。
関数 | 概要 | 対応状況 |
---|---|---|
AnalyzeForeignTable | ANALYZEが外部テーブルに対して実行されたときに呼び出されます。 | ○(対応) |
AcquireSampleRowsFunc | サンプル収集関数 | ×(未対応) |
IMPORT FOREIGN SCHEMAのための関数
表8にIMPORT FOREIGN SCHEMAの関数を記載しました。現時点では未対応ですが、データ型の対応に手間がかかるため、対応が望まれる機能の1つといえます。
関数 | 概要 | 対応状況 |
---|---|---|
ImportForeignSchema | IMPORT FOREIGN SCHEMAを実行する時に呼び出され、外部テーブル作成コマンドのリストを取得します。 | ×(未対応) |
パラレル実行のための関数
表9にパラレル実行の関数をまとめましたが、現時点では未対応でした。この辺りは、性能向上のためには必要な機能ですが、まず使う上で必要な機能から優先的に対応してほしいと思います。
関数 | 概要 | 対応状況 |
---|---|---|
IsForeignScanParallelSafe | スキャンがパラレルワーカーで実行できるかテストします。 | ×(未対応) |
EstimateDSMForeignScan | 並列操作に必要とされるであろう動的共有メモリ量を推定します。 | ×(未対応) |
InitializeDSMForeignScan | 並列処理で必要とされる動的共有メモリを初期化します。 | ×(未対応) |
ReInitializeDSMForeignScan | 外部スキャンプランノードが再スキャンされようとしているときに、並列操作に必要な動的共有メモリーを再初期化します。 | ×(未対応) |
InitializeWorkerForeignScan | InitializeDSMForeignScanでリーダーがセットアップした共有状態に基づくパラレルワーカーのローカル状態を初期化します。 | ×(未対応) |
ShutdownForeignScan | ノードが完了するまで実行されないことが予想されるときにリソースを解放します。 | ×(未対応) |
以上が、FDWの関数を調査した結果です。機能的な評価としては、最低限の機能は有しており、利用にあたって問題はないと思います。一方、エンタープライズ用途を考えた場合には、現在は未対応ですが以下の点を拡張して運用面を改善することで、利用の促進を図れるのではないかと考えており、そこを期待しています。
- IMPORT FOREIGN SCHEMAの対応
- リモート側で結合やソート、集約関数等のpushdownの対応
次回は、hdfs_fdwを実機で利用する際の評価を行いたいと思います。
今回の記事の内容については、NTT OSSセンタの澤田雅彦様にレビューをしていただきました。ありがとうございました。