プロンプトとスコープ
チームはテーブルデータをオブジェクトストレージに保存しており、計算基盤はSparkからTrinoや社内サービスへと拡張されています。従来のHive Metastoreのアプローチではクライアントごとの複数実装が必要となり、メタデータの同時更新によって互いに上書きされてしまうリスクがあります。担当領域、スナップショットのコミット、認証と認可、障害からの復旧を網羅したApache Iceberg REST Catalogを設計してください。
Apache Iceberg REST Catalogの仕様は、言語に依存しないHTTP APIを通じてカタログ操作を公開し、変更ベースのコミットを使用してサーバーが同時更新やリトライの競合を解消できるようにします。これはネームスペース、テーブルメタデータ、スナップショット参照を管理します。データファイルは基盤となるオブジェクトストレージに残ります。この面接で問われているのはメタデータのコントロールプレーンであり、クエリエンジンやオブジェクトストレージの再構築ではありません。
面接官が見ているポイント
優れた回答では、データプレーンとメタデータコントロールプレーンを分離した上で、クライアントの互換性、コミットの並行性、認可の境界、および復旧から各コンポーネントを論理的に導出します。面接官は、設定の検出、テーブルの読み込み、更新、楽観的並行制御、スナップショットのキャッシュ、および認証情報の払い出しがどのように連携しているかの説明を求めています。
不十分な回答は、単に「RESTサービス」を追加するだけで、2つのライターがスナップショットの上書きを回避する方法や、カタログが発行するデータ認証情報、エンジン間認証、古いクライアントへの対処法について説明しません。
最初に確認すべき明確化のための質問
アクセスパターンと整合性の目標
テーブルサイズ、ネームスペース数、読み取り/書き込みの比率、スナップショットのコミット頻度、およびマルチテーブルのアトミックコミットが必要かどうかを尋ねます。低頻度のバッチワークロードであれば、シンプルなメタデータデータベースだけで十分な場合があります。多数のエンジンが同時にコミットする場合は、明示的な競合検出、リトライのバジェット、コミットレイテンシの目標値が必要になります。
ストレージとカタログの境界
オブジェクトストレージ、FileIO、カタログデータベース、およびコンピュートエンジンの所有権を確認します。REST Catalogはメタデータと設定を返しますが、カタログサービスを経由して大きなデータファイルをプロキシするべきではありません。データ認証情報は、限定された権限と短い有効期間を持つテーブルまたは場所に対して払い出すことができます。
認証とガバナンス
クライアントがOAuth2、クラウドのリクエスト署名、またはサービスアカウントのどれを使用しているか、またテナント分離、監査、列/行レベルのポリシーが必要かどうかを質問します。カタログ認可は検出、読み取り、コミットを制御します。カタログが唯一のセキュリティ境界にならないよう、オブジェクトストレージ側でも最小権限を適用する必要があります。
30秒の回答フレームワーク
「私はREST Catalogをステートレスなメタデータコントロールプレーンとして構築します。クライアントはまず設定エンドポイントを呼び出し、次にネームスペースとテーブルのAPIを使用してメタデータを読み込みます。カタログデータベースは、現在のメタデータロケーション、スナップショット参照、およびコミットバージョンを保存します。ライターが期待されるバージョンに対して変更を送信すると、サーバーは競合を検出してリトライ可能な結果を返します。認証にはOAuth2またはクラウド署名を使用し、カタログ権限とオブジェクトストレージの認証情報は分離します。メタデータは短時間キャッシュできますが、バージョンまたはETagで検証する必要があります。カタログが利用できない場合、読み取りは検証済みの古いスナップショットを使用できますが、書き込みはコミットプロトコルをバイパスしてルートメタデータを直接編集してはなりません。」
ステップごとの解決策
ステップ1:コントロールプレーンのモデルを定義する
カタログには、少なくともネームスペース、テーブル識別子、現在のメタデータロケーション、スナップショット参照、バージョン、および監査フィールドが必要です。テーブルメタデータファイルはオブジェクトストレージに保持され、カタログはそのロケーションとコミットバージョンを記録します。クライアントはオンデマンドでスナップショットを読み込むことができ、カタログが大容量ファイルの転送経路になることはありません。
ステップ2:最小限で実用的なAPIを設計する
設定エンドポイントは、サーバーのデフォルト値、オーバーライド、およびサポートされているエンドポイントを返します。ネームスペースAPIは、プロパティの作成、一覧表示、管理を行います。テーブルAPIは、テーブルの作成、読み込み、更新、コミット、削除、名前変更を行います。ロードレスポンスにはテーブルとデータアクセスの設定を含めることができ、その後クライアントはオブジェクトストレージと直接通信します。コミックレスポンスは新しいバージョンを返し、クライアントがキャッシュを更新できるようにします。
ステップ3:楽観的並行制御でコミットを保護する
ライターはバージョンVを読み取り、新しいメタデータを書き込み、『私はVに基づいており、ロケーションMに切り替えたい』と送信します。サーバーは、現在のバージョンがまだVである場合にのみ、カタログをアトミックに更新します。別のライターが先にコミットした場合、サーバーは競合を返します。クライアントは再読み込みし、変更をマージしてリトライします。複数のエンジンによって1つの競合がコミットストームに発展しないよう、リトライには上限とジッター(揺らぎ)が必要です。
ステップ4:キャッシュと読み取り整合性を処理する
クライアントはテーブル設定とスナップショット参照をキャッシュできますが、キーには完全なテーブル識別子とサーバー識別情報を含める必要があります。有効期間(TTL)単独よりも、ETag、バージョン、またはスナップショット参照の検証を優先します。読み取りは、明示的な許容ステールネス(鮮度低下の許容範囲)内であればコミット済みスナップショットを使用できます。最新のブランチ、権限変更、またはRead-After-Writeを必要とするリクエストは、カタログバージョンを再検証しなければなりません。
ステップ5:認証、認可、および認証情報の払い出しを分離する
カタログAPIは、OAuth2、クラウド署名、またはエンタープライズサービスアカウントで認証します。認可は、ネームスペース、テーブル、操作を区別します。カタログがオブジェクトストレージの一時認証情報を払い出す場合は、必要なロケーションとアクションのみを対象とし、短いTTLを設定し、失効パスを備えた監査ログに関連付ける必要があります。クライアントは、それらの認証情報を永続キーとしてログや共有設定に書き込んではなりません。
ステップ6:障害パスと復旧パスを設計する
カタログデータベースが利用できない場合、検証済みのキャッシュされたスナップショットが可視化されたステールネスタイムスタンプとともに読み取りを処理できます。作成、コミット、削除の操作は失敗させて後でリトライする必要があり、オブジェクトストレージのルートメタデータを直接編集してはなりません。オブジェクトストレージが一時的に利用できない場合、カタログは存在しないファイルを指す新しいカタログバージョンで成功を返してはなりません。復旧時は、書き込みを再開する前に、メタデータロケーション、スナップショット参照、およびファイルマニフェストを検証します。
ステップ7:オブザーバビリティと互換性の発展性を追加する
リクエストID、クライアントエンジン、テーブル識別子、期待されるバージョンと実際のバージョン、競合数、リトライ回数、認証情報のスコープを記録しますが、トークンやキーは絶対に記録しません。API、ネームスペース、エンジンごとに、コミットレイテンシ、競合率、キャッシュヒット率、ステールリード比率を追跡します。新しいエンドポイントやフィールドは、機能検出と下位互換性のあるデフォルト値を使用する必要があります。未知のフィールドによって古いクライアントの既存のコミットセマンティクスが変更されてはなりません。
高品質な回答例
私はIceberg REST Catalogをメタデータのコントロールプレーンとして定義します。オブジェクトストレージはデータファイルとテーブルメタデータファイルを保持します。カタログデータベースは、テーブル識別子、現在のメタデータロケーション、スナップショット参照、バージョン、および認可監査データを保存します。Spark、Trino、その他の言語のクライアントは、単一のHTTPプロトコルを実装します。
クライアントは設定を読み取り、テーブルを読み込みます。ライターはバージョンVを読み取り、新しいメタデータを書き込み、期待されるバージョンVを送信します。サーバーはトランザクション内でそのバージョンを確認し、まだVであれば新しいロケーションへアトミックに切り替えます。そうでなければ競合を返します。クライアントは再読み込みしてマージし、指数バックオフと制限付きのバジェットでリトライします。これは、別のライターのスキーマ変更やスナップショット変更を暗黙のうちに失う可能性があるLast-Writer-Winsよりも安全です。
認証にはOAuth2またはクラウド署名を使用できます。カタログ認可は、検出、読み取り、コミットを制御します。カタログがオブジェクトストレージの認証情報を払い出す場合は、ロケーションをスコープとし、短いTTLを設定します。メタデータキャッシュにはETagまたはバージョンを使用し、権限変更やRead-After-Writeが未検証の古いエントリに依存しないようにします。カタログ停止中は、明示的なステールネスマーカーが付いた読み取りのみを許可し、書き込みは失敗させます。復旧後は、メタデータロケーション、スナップショット参照、およびファイルの存在を確認します。最後に、同時コミット、重複リトライ、カタログ障害、期限切れの認証情報、古いキャッシュ、古いクライアントのリクエストに対する互換性テストを実施します。
よくある間違い
- 間違い: すべてのデータファイルをカタログ経由でプロキシする。 → 失敗の理由: メタデータコントロールプレーンが高帯域幅のボトルネックになり、認可がデータ転送と密結合してしまう。 → 修正方法: メタデータとスコープ付きアクセス設定を返し、クライアントがオブジェクトストレージを直接読み取るようにする。
- 間違い: 同時コミットにLast-Writer-Winsを使用する。 → 失敗の理由: 後からのライターが、別のライターのスキーマやスナップショットを気付かずに上書きしてしまう可能性がある。 → 修正方法: 期待されるバージョンを送信し、アトミックな条件付き更新で競合を検出し、バジェット内でリトライする。
- 間違い: 鮮度の担保を固定TTLのみに依存する。 → 失敗の理由: TTLが切れる前に、Read-After-Writeや権限変更が誤ったビューを参照してしまう可能性がある。 → 修正方法: ETag、バージョン、またはスナップショット参照で検証し、リクエストのリスクに応じて強制的に更新する。
- 間違い: カタログ停止時にルートメタデータを直接編集する。 → 失敗の理由: コミットプロトコルがバイパスされ、カタログインデックスとファイル状態の整合性が崩れる。 → 修正方法: 書き込みを失敗させてリトライさせ、復旧時にロケーション、スナップショット、マニフェストを検証する。
フォローアップの質問と回答
フォローアップ1:2つのライターがバージョンVに基づいています。スキーマ変更をどのようにマージしますか?
サーバーは推測で処理するのではなく、2番目のコミットを拒否します。クライアントは現在のメタデータを再読み込みし、自身のスキーマ、パーティション、またはプロパティの変更が新しい状態と競合しないかを確認します。安全にマージできる場合のみ、新しいメタデータを作成して送信します。自動マージできない変更は、オペレーターまたはジョブレベルで判断すべき明示的な競合となります。
フォローアップ2:カタログキャッシュとオブジェクトストレージが一致しない場合はどうなりますか?
カタログバージョンをコミットの確定事実(fact)として扱い、オブジェクトストレージのメタデータロケーションを検証可能なコピーとして扱います。バックグラウンドチェッカーが、ロケーションが読み取り可能か、スナップショット参照が完全か、マニフェストが解決可能かを検証します。カタログが存在しないロケーションを指している場合は、以降の書き込みを凍結し、検証可能な最新バージョンを復元して、監査ログを保持します。キャッシュTTLを延ばしても障害が隠蔽されるだけです。
フォローアップ3:すべてのエンジンがHive Metastoreと直接通信してはいけないのはなぜですか?
複数の言語クライアントが認証、競合処理、機能拡張を重複して実装することになり、エンジンが追加されるたびにコストが増大します。REST Catalogは単一のプロトコルと機能検出を提供し、サーバーが競合解消、キャッシュ、および認証情報の払い出しを一元管理します。組織に安定したHive環境がありエンジンが1つだけの場合は、それを維持する方がシンプルな場合もあります。移行は、エンジン間の互換性とガバナンスのメリットによって正当化されるべきです。
フォローアップ4:クライアントがオブジェクトストレージの認証情報をログに出力してしまった場合はどうしますか?
認証情報は短期間有効で最小権限とし、リクエストIDに関連付ける必要があります。マスキング処理はクライアントとカタログサービスの両方で実行します。漏洩が発生した場合は、セッションを失効させるか有効期限を短縮し、アクセス監査ログを調査して、代替の認証情報を発行します。極めて機密性の高いデータについては、直接読み取りのパフォーマンスを犠牲にしてでも、サーバープロキシやリモート署名を採用して認証情報の露出を抑えることができます。