オブジェクト・ストレージでのHDFSコネクタ
Hadoop Distributed File System (HDFS)のコネクタを使用すると、Oracle Cloud Infrastructure Object Storageサービスに対してApache Hadoopアプリケーションによってデータの読取りと書込みが可能になります。
このSDKおよびサンプルは、Universal Permissive License 1.0およびApache License 2.0でデュアルライセンスされています。サードパーティ・コンテンツはコード内の記述に従って別途ライセンスされます。
- サポートされているサービス:オブジェクト・ストレージ
- ダウンロード: GitHubまたはMaven
- APIドキュメント: HDFSコネクタのAPIリファレンス
要件
HDFSコネクタを使用するには、次が必要です:
- Oracle Cloud Infrastructureアカウント。
- そのアカウントで作成され、使用するすべてのバケットで必要な権限を付与するポリシーがあるグループに含まれるユーザー。これに該当するのは、APIをコールする必要がある、ユーザー自身または別の人物/システムです。新しいユーザー、グループ、コンパートメントおよびポリシーの設定方法の例は、ユーザーの追加を参照してください。オブジェクト・ストレージの基本的なポリシーは、オブジェクト・ストレージ管理者によるバケットおよびオブジェクトの管理を参照してください。
- Java 8
- 値が60のTTL。詳細は、DNS名前参照のためのJVM TTLの構成を参照してください。
資格証明とパスワード
暗号化されたPEMファイルを資格証明に使用する場合、getPassword
Hadoop構成メソッドを使用して構成からパスフレーズを読み取ります。getPassword
オプションは、登録されたセキュリティ・プロバイダでパスワードをチェックします。セキュリティ・プロバイダが、要求されたキーを含んでいない場合、かわりに構成ファイルからプレーン・テキスト・パスフレーズを直接読み取ります。
DNS名前参照のためのJVM TTLの構成 🔗
Java Virtual Machine (JVM)は、参照に対するDNS応答を一定時間キャッシュしますが、この時間はtime-to-live (TTL)と呼ばれます。これにより、頻繁に名前を解決する必要があるコードでの応答時間が短縮されます。
JVMは、networkaddress.cache.ttlプロパティを使用して、DNS名前参照のキャッシュ・ポリシーを指定します。値は、成功した参照をキャッシュする秒数を表す整数です。多くのJVMのデフォルト値は-1
ですが、これは参照が永久にキャッシュされることを指定します。
Oracle Cloud Infrastructureのリソースが使用するDNS名は変わる可能性があるため、TTL値を60秒に変更することをお薦めします。こうすると、次のDNS問合せでリソースの新しいIPアドレスが返されるようになります。この値はグローバルに変更することも、ご使用のアプリケーションについてのみ変更することもできます:
-
JVMを使用してグローバルにすべてのアプリケーションのTTLを設定するには、
$JAVA_HOME/jre/lib/security/java.security
ファイルに次を追加します:networkaddress.cache.ttl=60
-
ご使用のアプリケーションのみのTTLを設定するには、アプリケーションの初期化コードに次を設定します:
java.security.Security.setProperty("networkaddress.cache.ttl" , "60");
インストール 🔗
バンドルされたjarをlibおよびthird-party/libからHadoopクラスタの各ノードにコピーして、HadoopのCLASSPATHに含まれるようにします。
SDK for JavaおよびMavenアーティファクト
HDFSコネクタの構築は、Oracle Cloud Infrastructure SDK for Javaで提供されるMavenアーティファクトに依存します。アーティファクトを取得するには、SDK for Javaをダウンロードし、ローカルで構築する必要があります。その後、HDFSコネクタを構築できます。
Oracleリリース・ページからダウンロードしたSDK for Javaファイルのバージョンは、HDFSコネクタのバージョンと一致する必要があります。これは、
hdfs-connector/pom.xml
ファイルのgroupId
属性を含む依存関係タグ・ブロックで確認できます。HDFSコネクタおよびMavenアーティファクト
HDFSコネクタは、Maven CentralおよびJCenterから入手できます。
プロジェクトでHDFSコネクタを使用するには、次のプロジェクト依存関係をインポートします。例:
<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-hdfs-connector</artifactId>
<!-- Replace the version below with your required version -->
<version>2.9.2.0</version>
</dependency>
プロパティ 🔗
HDFSコネクタの次のプロパティをcore-site.xml
ファイルに設定できます。BmcPropertiesのページには、オブジェクト・ストレージへの接続に関して構成できる追加のプロパティがリストされています。
プロパティ | 説明 | タイプ | 必須 |
---|---|---|---|
fs.oci.client.hostname
|
ホスト・エンドポイントのURL。 たとえば、 |
文字列 | はい |
fs.oci.client.auth.tenantId
|
テナンシのOCID。 この値を取得するには、必要なキーとOCIDを参照してください。 |
文字列 | はい |
fs.oci.client.auth.userId
|
APIをコールするユーザーのOCID。 この値を取得するには、必要なキーとOCIDを参照してください。 |
文字列 | はい |
fs.oci.client.auth.fingerprint
|
使用されているキー・ペアのフィンガープリント。 この値を取得するには、必要なキーとOCIDを参照してください。 |
文字列 |
はい(カスタム・オーセンティケータを指定しない場合のみ)。 |
fs.oci.client.auth.pemfilepath
|
認証で使用される秘密キーのフルパスとファイル名。このファイルはローカル・ファイル・システム上にある必要があります。 | 文字列 | はい(カスタム・オーセンティケータを指定しない場合のみ)。 |
fs.oci.client.auth.passphrase
|
キーに使用されるパスフレーズ(キーが暗号化されている場合)。 | 文字列 | キーが暗号化されている場合のみ |
fs.oci.client.regionCodeOrId
|
オブジェクト・ストレージ・エンドポイント名の作成に使用されるリージョン・コードまたはリージョン識別子。 | 文字列 | いいえ |
プロパティ名の後に
.<bucket_name>.<namespace_name>
を付けることで、プロパティ値が特定のバケットに適用されるよう指定できます。リージョン・エンドポイントの設定
HDFSコネクタのリージョン・エンドポイントは、いくつかの方法で設定できます:
core-site.xml
でhostnameプロパティを指定core-site.xml
でリージョン・コードまたはリージョン識別子プロパティを指定- ObjectStorageクライアントが、インスタンス・メタデータ・サービスを介してエンドポイントを取得できるようにする
core-site.xmlを使用したプロパティの構成
この例は、core-site.xml
ファイルでプロパティを構成する方法を示します(OCIDは一部省略)。
<configuration>
...
<property>
<name>fs.oci.client.hostname</name>
<value>https://objectstorage.us-ashburn-1.oraclecloud.com</value>
</property>
<property>
<name>fs.oci.client.hostname.myBucket.myNamespace</name>
<value>https://objectstorage.us-phoenix-1.oraclecloud.com</value><!-- Use Phoenix for myBucket@myNamespace -->
</property>
<property>
<name>fs.oci.client.auth.tenantId</name>
<value>ocid1.tenancy.oc1..exampleuniqueID</value>
</property>
<property>
<name>fs.oci.client.auth.userId</name>
<value>ocid1.user.oc1..exampleuniqueID</value>
</property>
<property>
<name>fs.oci.client.auth.fingerprint</name>
<value>20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34</value>
</property>
<property>
<name>fs.oci.client.auth.pemfilepath</name>
<value>~/.oci/oci_api_key.pem</value>
</property>
...
</configuration>
認証でのインスタンス・プリンシパルの使用 🔗
Oracleではインスタンス・プリンシパルが用意されており、インスタンスで実行されているサービスに対して、ユーザー資格証明を構成したりPEMファイルを指定したりする必要がなくなります。これらの各インスタンスには独自のアイデンティティがあり、インスタンス・プリンシパルによってインスタンスに追加された証明書を使用して認証されます。
HDFSコネクタでインスタンス・プリンシパル認証を使用するには、プロパティfs.oci.client.custom.authenticator
を指定して、値をcom.oracle.bmc.hdfs.auth.InstancePrincipalsCustomAuthenticator
に設定するだけです。
インスタンス・プリンシパルを使用すると、コネクタにカスタム・オーセンティケータが提供されるため、次のプロパティを構成する必要はなくなりました。
fs.oci.client.auth.tenantId
fs.oci.client.auth.userId
fs.oci.client.auth.fingerprint
fs.oci.client.auth.pemfilepath
fs.oci.client.auth.passphrase
次のコード例は、HDFSコネクタでの認証にインスタンス・プリンシパルを使用する方法を示しています:
<?xml version="1.0"?>
<configuration>
<property>
<name>fs.oci.client.hostname</name>
<value>https://objectstorage.us-phoenix-1.oraclecloud.com</value>
</property>
<property>
<name>fs.oci.client.custom.authenticator</name>
<value>com.oracle.bmc.hdfs.auth.InstancePrincipalsCustomAuthenticator</value>
</property>
</configuration>
インスタンス・プリンシパルの詳細は、Identity and Access Managementのためのインスタンス・プリンシパルのお知らせを参照してください。
認証でのリソース・プリンシパルの使用 🔗
Oracleでは、インスタンス・プリンシパルと同様に、インスタンスではないリソース(jupyterノートブックなど)を認証するためのリソース・プリンシパルを提供しています。各リソースには、それぞれのアイデンティティがあり、追加された証明書を使用して認証を行います。
HDFSコネクタでは、プロパティfs.oci.client.custom.authenticator
を指定して、値をcom.oracle.bmc.hdfs.auth.ResourcePrincipalsCustomAuthenticator
に設定するだけで、リソース・プリンシパル認証を使用できます。
リソース・プリンシパルを使用すると、コネクタにカスタム・オーセンティケータが提供されるため、次のプロパティを構成する必要はありません。
fs.oci.client.auth.tenantId
fs.oci.client.auth.userId
fs.oci.client.auth.fingerprint
fs.oci.client.auth.pemfilepath
fs.oci.client.auth.passphrase
次のサンプル・コードでは、HDFSコネクタでの認証にリソース・プリンシパルを使用する方法を示しています:
<?xml version="1.0"?>
<configuration>
<property>
<name>fs.oci.client.hostname</name>
<value>https://objectstorage.us-phoenix-1.oraclecloud.com</value>
</property>
<property>
<name>fs.oci.client.custom.authenticator</name>
<value>com.oracle.bmc.hdfs.auth.ResourcePrincipalsCustomAuthenticator</value>
</property>
</configuration>
インスタンス・プリンシパルの詳細は、データ・サイエンス・サービスでのリソース・プリンシパルの使用を参照してください。
Kerberos認証の使用 🔗
Oracleでは、HDFS Connectorを使用してオブジェクト・ストレージに接続するためのKerberos認証がサポートされています。
core-site.xml
で、fs.oci.client.custom.authenticator
プロパティをcom.oracle.bmc.hdfs.auth.spnego.UPSTAuthenticationCustomAuthenticator
に設定します。core-site.xml
で、次のプロパティを設定します。fs.oci.client.upst.domainUrl
-
fs.oci.client.upst.clientId
-
fs.oci.client.upst.clientSecret
-
fs.oci.client.upst.tokenExchangeServicePrincipal
-
fs.oci.client.upst.userPrincipal
fs.oci.client.upst.issuer
fs.oci.client.keytab.path
fs.oci.client.kinit.internal.mode
次のcore-site.xml
ファイルの例は、HDFS ConnectorでのSPNEGOトークン認証でのKerberosの使用を示しています。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.oci.client.hostname</name>
<value>https://objectstorage.us-phoenix-1.oraclecloud.com</value>
</property>
<property>
<name>fs.oci.client.auth.tenantId</name>
<value></value>
</property>
<property>
<name>fs.oci.client.auth.userId</name>
<value></value>
</property>
<property>
<name>fs.oci.client.custom.authenticator</name>
<value>com.oracle.bmc.hdfs.auth.spnego.UPSTAuthenticationCustomAuthenticator</value>
</property>
<property>
<name>fs.oci.client.upst.tokenExchangeServicePrincipal</name>
<value><!-- Service Principal for generating SPNEGO token --></value>
</property>
<property>
<name>fs.oci.client.upst.userPrincipal</name>
<value><!-- User Principal for generating SPNEGO token --></value>
</property>
<property>
<name>fs.oci.client.upst.issuer</name>
<value><!-- Issuer for generating SPNEGO token --></value>
</property>
<property>
<name>fs.oci.client.upst.domainUrl</name>
<value><!-- Domain application client ID for IAM token exchange --></value>
</property>
<property>
<name>fs.oci.client.upst.clientId</name>
<value><!-- Domain application client ID for IAM token exchange --></value>
</property>
<property>
<name>fs.oci.client.upst.clientSecret</name>
<value><!-- Domain application client secret for IAM token exchange --></value>
</property>
<property>
<name>fs.oci.client.keytab.path</name>
<value><!-- File path to the keytab used for token exchange --></value>
</property>
</configuration>
Kerberosの詳細は、Kerberosプロトコルのチュートリアルを参照してください。
SPNEGOの詳細は、RFC 4178を参照してください。
JerseyのデフォルトであるHttpUrlConnectorProviderの使用 🔗
バージョン3.3.0.7.0.0以降、HDFSでは、OCIサービス・コールを実行するために、デフォルトでApacheクライアントの使用がサポートされています。これは、HDFSコネクタがSDK for Javaに依存してサーバーにリクエストを送信するためです。SDK for Javaでは、Jersey HttpUrlConnectorProvider
ではなく、Jersey ApacheConnectorProvider
の使用がデフォルトでサポートされており、Apache HttpClientによるOCIサービス・コールの実行が可能になっています。
Jerseyの以前のデフォルト・クライアントに切り替えるには、core-site.xml
ファイルのプロパティfs.oci.client.jersey.default.connector.enabled
をtrue
に設定します。デフォルトでは、この値はfalse
に設定されています。
HDFS用のApacheコネクタを使用したパフォーマンスの最適化 🔗
Apacheコネクタでは、ApacheConnectionClosingStrategy.GracefulClosingStrategy
とApacheConnectionClosingStrategy.ImmediateClosingStrategy
の2つ戦略で接続を切断できます。
ApacheConnectionClosingStrategy.GracefulClosingStrategy
を使用すると、レスポンスから返されたストリームは、ストリームを終了するときにストリームの最後まで読み取られます。このため、残りのストリームの大きさによっては、部分読取りが行われるストリームを終了するときに、別途時間がかかる可能性があります。この遅延を回避するため、部分読取りが行われる大規模ファイルでは、ApacheConnectionClosingStrategy.ImmediateClosingStrategy
の使用を検討してください。ApacheConnectionClosingStrategy.ImmediateClosingStrategy
では、ストリームを終了するときにストリームは最後まで読み取られないため、パフォーマンスが向上します。小規模なストリーム・サイズ(1MB未満のストリーム)で部分読取りを使用する場合は、ApacheConnectionClosingStrategy.ImmediateClosingStrategy
に時間がかかることに注意してください。
接続の切断戦略の設定
接続の切断戦略を設定するには、core-site.xml
ファイルのfs.oci.client.apache.connection.closing.strategy
プロパティを設定します:
ApacheConnectionClosingStrategy.GracefulClosingStrategy
を使用するには、fs.oci.client.apache.connection.closing.strategy
をgraceful
に設定します。ApacheConnectionClosingStrategy.ImmediateClosingStrategy
を使用するには、fs.oci.client.apache.connection.closing.strategy
をimmediate
に設定します。
これらの切断方法は、HDFS用のApacheコネクタでのみ機能し、Jerseyのデフォルト・コネクタを使用する場合は無視されます。
Jerseyのデフォルト・コネクタへの切替え
Jerseyのデフォルト・コネクタでは、ストリームを最後まで読み取って再利用するため、一部のシナリオでは、HDFS用のApacheコネクタよりもパフォーマンスが向上します。Apache接続のこれらの切断方法で、お客様のユース・ケースが最適な結果にならない場合は、JerseyのデフォルトであるHttpUrlConnectorProviderに切り替えられます。Jerseyの以前のデフォルト・クライアントに切り替えるには、core-site.xml
ファイルのfs.oci.client.jersey.default.connector.enabled
プロパティをtrue
に設定します。デフォルトでは、この値はfalse
に設定されています。
詳細は、https://github.com/oracle/oci-java-sdk/blob/master/ApacheConnector-README.mdを参照してください。
HDFSでの接続プーリング 🔗
HDFSコネクタ接続プールの最大接続数を設定できます。
これを行うには、core-site.xml
ファイルのプロパティfs.oci.client.apache.max.connection.pool.size
を、プールする接続数を指定する正の整数に変更します。
このプロパティは、HDFS用の
ApacheConnector
を使用している場合にのみサポートされ、それ以外の場合は無視されます。専用エンドポイント 🔗
core-site.xml
でホスト名fs.oci.client.hostname
またはエンドポイント・テンプレート・フラグfs.oci.realmspecific.endpoint.template.enabled
プロパティを設定することで、これらのレルム固有のエンドポイント・テンプレートの使用を有効にできます。 エンドポイント・テンプレート・プロパティを設定する場合は、
core-site.xml
でfs.oci.client.regionCodeOrId
も設定する必要があります。core-site.xml
のホスト名を使用して設定された値は、core-site.xml
のエンドポイント・テンプレート・プロパティを使用して設定された値よりも優先されます。fs.oci.client.hostname
プロパティを設定してレルム固有のエンドポイント・テンプレート機能を有効にする方法を示しています。<property>
<name>fs.oci.client.hostname</name>
<value>https://my-namespace.objectstorage.me-dubai-1.oci.customer-oci.com</value>
</property>
fs.oci.realmspecific.endpoint.template.enabled
プロパティを設定してレルム固有のエンドポイント・テンプレート機能を有効にする方法を示しています。<property>
<name>fs.oci.client.regionCodeOrId</name>
<value>me-dubai-1</value>
</property>
<property>
<name>fs.oci.realmspecific.endpoint.template.enabled</name>
<value>true</value>
</property>
HTTPプロキシの構成 🔗
core-site.xml
ファイルに次のオプションのプロパティを設定して、HTTPプロキシを構成できます:
プロパティ | 説明 | タイプ | 必須 |
---|---|---|---|
fs.oci.client.proxy.uri
|
プロキシ・エンドポイントのURI。 たとえば、 |
文字列 | いいえ |
fs.oci.client.proxy.username
|
プロキシで認証するユーザー名。 | 文字列 | いいえ |
fs.oci.client.proxy.password
|
プロキシで認証するパスワード。 | 文字列 | いいえ |
fs.oci.client.multipart.allowed
|
アップロード・マネージャがマルチパート・アップロードをサポートできるようになります | ブール型 | いいえ |
fs.oci.client.multipart.minobjectsize.mb
|
アップロード・マネージャを使用するための最小オブジェクト・サイズ(MB)を指定します。 |
整数 | いいえ |
fs.oci.client.multipart.partsize.mb
|
アップロード・マネージャのパート・サイズ(MB)を指定します。 | 整数 | いいえ |
プロキシを構成すると、オブジェクト・ストレージに接続するときに
ApacheConnectorProvider
を使用できるようになります。これはリクエストをメモリーにバッファするため、ラージ・オブジェクトをアップロードする際のメモリー使用率に影響が生じることがあります。マルチパート・アップロードを有効にし、マルチパートのプロパティを調整して、メモリー消費を管理することをお薦めします。ラージ・オブジェクトのアップロード 🔗
ラージ・オブジェクトは、マルチパート・アップロードを使用してオブジェクト・ストレージにアップロードされます。ファイルが小さなパートに分割されて、並列でアップロードされるため、アップロード時間が短縮されます。このため、HDFSコネクタでは、アップロード全体が失敗することがなくなり、失敗したパートのアップロードを再試行することもできます。ただし、アップロードが一時的に失敗する場合があり、コネクタは部分的にアップロードされたファイルを中止しようとします。このようなファイルは蓄積(また、格納に対して課金)されるため、定期的にアップロードをリスト表示し、一定の日数が経過したものはSDK for Javaを使用して手動で中止します。
マルチパート・アップロードを管理するためのオブジェクト・ストレージAPIの使用の方の詳細は、マルチパート・アップロードの使用を参照してください。
マルチパート・ロードの使用を望まない場合は、
fs.oci.client.multipart.allowed
プロパティをfalse
に設定して無効にすることができます。ベスト・プラクティス 🔗
次の各項では、使用状況とパフォーマンスを最適化するベスト・プラクティスについて説明します。
ディレクトリ名
オブジェクト・ストレージに実際のディレクトリはありません。ディレクトリのグループ分けは命名規則として機能し、オブジェクトの名前で/
デリミタが使用されます。たとえば、オブジェクト名がa/example.json
であれば、a
という名前のディレクトリがあることを意味します。ただし、このオブジェクトを削除すると、a
ディレクトリも暗黙的に削除されます。ファイル・システムのセマンティクス(ファイルがまったく存在しなくてもディレクトリが存在できる)を維持するため、HDFSコネクタは、パスがそのディレクトリを表し、名前が/
で終わる実際のオブジェクトを作成します(つまり、a/
という名前のオブジェクトを作成します)。これで、a/example.json
を削除してもa
ディレクトリの存在には影響しません。a/
オブジェクトの存在は維持されているためです。ただし、誰かが下位のファイル/ディレクトリを削除せずにa/
オブジェクトを削除する可能性は大いにあります。HDFSコネクタによって、フォルダ・オブジェクトが削除されるのは、そのパスの下位にオブジェクトがない場合のみです。フォルダ・オブジェクト自体は0バイトです。
整合性のないファイル・システム
ディレクトリの削除とは、そのディレクトリを表す接頭辞で始まるすべてのオブジェクトを削除することを意味します。HDFSでは、ファイルまたはディレクトリのファイル・ステータスを問い合せることができます。ディレクトリのファイル・ステータスは、そのディレクトリのフォルダ・オブジェクトが存在するかどうかを確認することで実装されます。ただし、フォルダ・オブジェクトが削除されても、その接頭辞が付いたいくつかのオブジェクトがまだ存在している可能性があります。たとえば、次のようなオブジェクトがある状況です:
a/b/example.json
a/b/file.json
a/b/
HDFSは、ディレクトリ/a/b/
が存在し、それがディレクトリであることを認識しています。このディレクトリをスキャンすると、example.json
とfile.json
が見つかります。ただし、オブジェクトa/b/
が削除された場合、ファイル・システムが整合性のない状態になります。ディレクトリ/a/b/
内のすべてのファイルを問い合せると、2つのエントリが見つかりますが、実際の/a/b/
ディレクトリのステータスを問い合せると例外が発生します。このディレクトリは存在していないためです。HDFSコネクタが、ファイル・システムのこの状態を修正しようとすることはありません。
ファイルの作成
オブジェクト・ストレージでは、サイズがギガバイトのオブジェクトがサポートされます。通常、ファイルの作成は、一時ファイルに書き込んでから、ストリームが終了したときにファイルの内容をアップロードすることで行われます。一時領域は、複数のアップロードを処理できるだけの大きさにする必要があります。使用される一時ディレクトリは、hadoop.tmp.dir
構成プロパティによって制御されます。
読取り/シークのサポート
インメモリー・バッファが有効の場合(fs.oci.io.read.inmemory
)、ファイル全体がバイト配列にバッファリングされるため、シークが完全にサポートされます。インメモリー・バッファが使用可能でない場合(オブジェクト・サイズが大きい場合など)、ストリームを終了し、指定されたオフセットで始まる新しい範囲リクエストを作成することで、シークが実装されます。
ディレクトリのリスト表示
ディレクトリのリスト表示は、基本的には、接頭辞とデリミタを指定したバケットのリスト表示操作です。各キーのHDFS FileStatusインスタンスを作成するには、コネクタが追加のHEADリクエストを実行し、個々のキーのObjectMetadataを取得します。これは、オブジェクト・ストレージによってより豊富なリスト操作データがサポートされるようになるまです。
ファイル・システムおよびファイルのURIフォーマット 🔗
HDFSのファイル・システムおよびファイルは、URIを介して参照されます。スキームによりファイル・システムのタイプが指定されます。URIのその他の部分は、ファイル・システムの実装が必要に応じて自由に解釈できます。
オブジェクト・ストレージはオブジェクト・ストアであるため、オブジェクトがファイルシステム内のファイルであるかのように命名する機能を利用して、実際のファイル・システムの模倣できます。
ルート
オブジェクト・ストレージのファイル・システムのルートは、次に示すとおり、オーソリティ構成要素のバケット名とネームスペース名が含まれるパスで示されます:
この例では、
MyBucket
とMyNamespace
はプレースホルダです。適切な値で置き換える必要があります。
oci://MyBucket@MyNamespace/
これは常にファイル・システムのルートです。バケットとネームスペースの両方に対してオーソリティを使用する理由は、HDFSでは、オーソリティ部分しかファイル・システムの場所を決定できないためです。パス部分には、リソースのパスのみが示されます(つまり「oci//MyNamespace/MyBucket」は機能しません)。@
文字はバケットまたはネームスペースで有効な文字ではないため、オーソリティが正しく解析されることに注意してください。
サブディレクトリ
サブディレクトリは実際には存在しませんが、/
文字を含むオブジェクトを作成することで模倣できます。たとえば、a/b/c/example.json
およびa/b/d/path.json
という名前の2つのファイルは、共通のディレクトリa/b
に存在するかのように見えます。これは、オブジェクト・ストレージの接頭辞とデリミタに基づいた問合せを使用して実現します。例で、URIとしてサブディレクトリを参照すると、次のようになります:
oci://MyBucket@MyNamespace/a/b/
オブジェクト/ ファイル
a/b/c/example.json
という名前のオブジェクトは、次のように参照されます:
oci://MyBucket@MyNamespace/a/b/c/example.json
ロギング 🔗
コネクタのロギングは、SLF4Jを使用して行われます。SLF4Jは、ユーザー指定のロギング・ライブラリ(log4jなど)を使用できるするロギング抽象化機能です。詳細は、SLF4Jのマニュアルを参照してください。
次の例では、標準出力への基本ロギングを有効にする方法を示します。
- SLF4J Simple Binding jarをダウンロードします: SLF4J Simple Binding
- jarをクラス・パスに追加します
- 次のVM引数を追加して、debugレベル・ロギングを有効にします(デフォルトではinfoレベルが使用されます):
-Dorg.slf4j.simpleLogger.defaultLogLevel=debug
log4jバインディングを使用すると、より高度なロギング・オプションを構成できます。
モニタリング・フレームワークの使用 🔗
HDFS Connector for Object Storageには、コネクタを使用して実行される操作に関するメトリックを提供する監視フレームワークが含まれています。モニタリング・フレームワークは、コネクタによって生成されたメトリックを消費/リスニングするために実装できるインタフェースを提供します。このインタフェースのカスタム実装を提供することも、このフレームワークに付属するOCIパブリック・テレメトリ実装を使用することもできます。
はじめに
HDFS Connectorモニタリング・フレームワークの使用を開始するには、次のプロパティを設定する必要があります。これらのプロパティをOCIMonitoring
に設定したら、OCIコンソールのメトリック・エクスプローラ・ビューを使用して、HDFSコネクタから生成されたメトリックを確認できます。
fs.oci.mon.consumer.plugins
fs.oci.mon.consumer.plugins
は、モニタリング・インタフェースの実装の完全修飾クラス名のカンマ区切りリストを取得します。メトリックをOCIパブリック・テレメトリに出力する場合は、リスト内でcom.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
を使用する必要があります。<property>
<name>fs.oci.mon.consumer.plugins</name>
<value>com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin,com.your.new.plugin.PluginImpl1</value>
</property>
fs.oci.mon.grouping.cluster.id
fs.oci.mon.grouping.cluster.id
プロパティは、HDFSクラスタの識別子、またはメトリックをグループ化するその他のIDを指定します。これは必須プロパティであり、メトリックにタグ付けするためにOCIMonitorPlugin
でも使用されます。このプロパティは、OCIパブリック・テレメトリ・ユーザー・インタフェースおよびAPIでディメンションとして表示されます。<property>
<name>fs.oci.mon.grouping.cluster.id</name>
<value>hdfs-sample-cluster-id</value>
</property>
com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
プロパティ
com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
プロパティが有効になっている場合、次のプロパティを適用できます。
fs.oci.mon.telemetry.ingestion.endpoint
fs.oci.mon.telemetry.ingestion.endpoint
プロパティは、OCIモニタリングのテレメトリ取込みエンドポイントの構成に役立ちます。詳細は、使用可能なポイントのリストを参照してください。
<property>
<name>fs.oci.mon.telemetry.ingestion.endpoint</name>
<value>https://telemetry-ingestion.us-ashburn-1.oraclecloud.com</value>
</property>
fs.oci.mon.compartment.ocid
fs.oci.mon.compartment.ocid
プロパティは、メトリックがアタッチされるOCIコンパートメントを構成するために使用されます。これは通常、バケットが属するコンパートメントです。<property>
<name>fs.oci.mon.compartment.ocid</name>
<value>ocid1.compartment.oc1..sample.compartment.id</value>
</property>
fs.oci.mon.bucket.level.enabled
fs.oci.mon.bucket.level.enabled
プロパティは、バケット名をディメンションとして発行済メトリックに添付するかどうかを決定します。<property>
<name>fs.oci.mon.bucket.level.enabled</name>
<value>true</value>
</property>
fs.oci.mon.ns.name
fs.oci.mon.ns.name
プロパティは、HDFSコネクタによって生成されるメトリックに使用されるネームスペースを制御します。ネームスペースの例として、"hdfsconnector"があります。これは、パブリック・テレメトリ内のoci_objectstorage
などの他の事前定義済ネームスペースとともに存在します。<property>
<name>fs.oci.mon.ns.name</name>
<value>name.of.namespace.on.oci.telemetry</value>
</property>
fs.oci.mon.rg.name
fs.oci.mon.rg.name
プロパティは、メトリックの格納に使用されるリソース・グループ名を設定します。これは、一緒にモニターされるグループ化リソースの任意の論理名です。このリソース・グループ名は、OCIパブリック・テレメトリで以前に選択されたネームスペースの下に表示されます。<property>
<name>fs.oci.mon.rg.name</name>
<value>name.of.resource.group.on.oci.telemetry</value>
</property>
メトリック用の独自のコンシューマの作成
com.oracle.bmc.hdfs.monitoring.OCIMonitorConsumerPlugin
インタフェースを使用するには、次の2つのメソッドを定義する必要があります。accept
shutdown
拡張クラスには、OCIMonitorConsumerPlugin
クラスと同じシグネチャを持つコンストラクタが必要です。
public OCIMonitorConsumerPlugin(BmcPropertyAccessor propertyAccessor, String bucketName, String monitoringGroupingID, String namespaceName);
/**
* This class that has to be extended by any plugin, that wants to consume the metrics emitted by OCI HDFS connector.
*/
public abstract class OCIMonitorConsumerPlugin {
/**
* This method will be called on each plugin, by the OCI monitoring framework, whenever it wants to emit out a metric.
* This method should finish as quickly as possible, so the consumer of this should ideally handover the
* ocimetric and stage it elsewhere for processing, instead of trying to deal with it in the accept call itself.
* @param ociMetric The metric that is being emitted by the OCI HDFS connector
*/
public void accept(OCIMetric ociMetric);
/**
* This shutdown method will be called on the implementing plugins, whenever the JVM is shutting down.
* It could be used to cleanup, finish pending tasks before exit.
*/
public void shutdown();
}
OCIMetric
クラスは、次の3つの方法で実装できます。
OCIMetric
オブジェクト:public class OCIMetric {
/**
* The time in milliseconds (epoch) when the metric was recorded.
*/
private final long recordedTime;
/**
* The overall time taken by the operation to complete/error-out in milliseconds.
*/
private final double overallTime;
/**
* The operation key. This will be one of {"LIST", "HEAD", "WRITE", "READ", "DELETE", "RENAME"}
*/
private final String key;
/**
* The boolean error indicates whether the operation errored out.
*/
private final boolean error;
/**
* The target OCI bucket where the operation was attempted to.
*/
private final String bucketName;
}
OCIMetric
を拡張し、スループットおよび転送バイトの追加フィールドを持つOCIMetricWithThroughput
オブジェクトの実装。これは、READおよびWRITE操作に適用されます。public class OCIMetricWithThroughput extends OCIMetric {
/**
* The throughput that was recorded for the operation in bytes/second
*/
private final double throughput;
/**
* The total count of bytes that were transferred in or out.
*/
private final double bytesTransferred;
}
OCIMetricWithThroughput
を拡張するOCIMetricWithFBLatency
オブジェクトで、最初のバイト・レイテンシ・フィールドへの時間が追加されます。これはREAD操作にのみ適用されます。public class OCIMetricWithFBLatency extends OCIMetricWithThroughput {
/**
* The time to first byte when a read operation was performed in milliseconds.
*/
private final double ttfb;
}
Hadoopのサンプル・ジョブ 🔗
package com.oracle.oci.hadoop.example;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.oracle.oci.hdfs.BmcFilesystem;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class SampleOracleBmcHadoopJob
{
private static final String SAMPLE_JOB_PATH = "/samplehadoopjob";
private static final String INPUT_FILE = SAMPLE_JOB_PATH + "/input.dat";
private static final String OUTPUT_DIR = SAMPLE_JOB_PATH + "/output";
// non-static since this is the runner class it needs to initialize after we set the properties
private final Logger log = LoggerFactory.getLogger(SampleOracleBmcHadoopJob.class);
/**
* Runner for sample hadoop job. This expects 3 args: path to configuration file, Object Store namespace, Object
* Store bucket. To run this, you must:
*{@code
*
Create a standard hadoop configuration file
*
Create the bucket ahead of time.
*}
* This runner will create a test input file in a file '/samplehadoopjob/input.dat', and job results will be written
* to '/samplehadoopjob/output'.
*
* @param args
* 1) path to configuration file, 2) namespace, 3) bucket
* @throws Exception
*/
public static void main(final String[] args) throws Exception
{
if (args.length != 3)
{
throw new IllegalArgumentException(
"Must have 3 args: 1) path to config file, 2) object storage namespace, 3) object storage bucket");
}
// redirect all logs to sysout
System.setProperty("org.slf4j.simpleLogger.logFile", "System.out");
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");
final SampleOracleBmcHadoopJob job = new SampleOracleBmcHadoopJob(args[0], args[1], args[2]);
System.exit(job.execute());
}
private final String configurationFilePath;
private final String namespace;
private final String bucket;
public int execute() throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException
{
log.info("Creating hadoop configuration");
final Configuration configuration = this.createConfiguration(this.configurationFilePath);
final String authority = this.bucket + "@" + this.namespace;
final String uri = "oci://" + authority;
log.info("Using uri: {}", uri);
log.info("Creating job inputs");
this.setup(uri, configuration);
log.info("Creating job");
final Job job = this.createJob(configuration);
final String in = uri + INPUT_FILE;
final String out = uri + OUTPUT_DIR;
log.info("Using input: {}", in);
log.info("Using output: {}", out);
FileInputFormat.addInputPath(job, new Path(in));
FileOutputFormat.setOutputPath(job, new Path(out));
log.info("Executing job...");
final int response = job.waitForCompletion(true) ? 0 : 1;
log.info("Attempting to read job results");
this.tryReadResult(uri, configuration);
return response;
}
private Configuration createConfiguration(final String configFilePath)
{
final Configuration configuration = new Configuration();
configuration.addResource(new Path(configFilePath));
return configuration;
}
private void setup(final String uri, final Configuration configuration) throws IOException, URISyntaxException
{
try (final BmcFilesystem fs = new BmcFilesystem())
{
fs.initialize(new URI(uri), configuration);
fs.delete(new Path(SAMPLE_JOB_PATH), true);
final FSDataOutputStream output = fs.create(new Path(INPUT_FILE));
output.writeChars("example\npath\ngak\ntest\nexample\ngak\n\ngak");
output.close();
}
}
private Job createJob(final Configuration configuration) throws IOException
{
final Job job = Job.getInstance(configuration, "word count");
job.setJarByClass(SampleOracleBmcHadoopJob.class);
job.setMapperClass(SimpleMapper.class);
job.setCombinerClass(SimpleReducer.class);
job.setReducerClass(SimpleReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
return job;
}
private void tryReadResult(final String uri, final Configuration configuration)
throws IOException, URISyntaxException
{
try (final BmcFilesystem fs = new BmcFilesystem())
{
fs.initialize(new URI(uri), configuration);
// this should be the output file name, but that could change
final FSDataInputStream input = fs.open(new Path(OUTPUT_DIR + "/part-r-00000"));
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(input, baos);
log.info("\n=====\n" + baos.toString() + "=====");
input.close();
}
}
}
package com.oracle.oci.hadoop.example;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class SimpleMapper extends Mapper
{
private final static IntWritable one = new IntWritable(1);
private final Text word = new Text();
@Override
public void map(final Object key, final Text value, final Context context) throws IOException, InterruptedException
{
final StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens())
{
this.word.set(itr.nextToken());
context.write(this.word, one);
}
}
}
package com.oracle.oci.hadoop.example;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class SimpleReducer extends Reducer
{
private final IntWritable result = new IntWritable();
@Override
public void reduce(final Text key, final Iterable values, final Context context)
throws IOException, InterruptedException
{
int sum = 0;
for (final IntWritable val : values)
{
sum += val.get();
}
this.result.set(sum);
context.write(key, this.result);
}
}
トラブルシューティング 🔗
この項には、HDFSコネクタのトラブルシューティング情報が含まれています。
サービス・エラーのトラブルシューティング
サービス・エラーを引き起こすすべての操作は、HDFSコネクタによって例外タイプcom.oracle.bmc.model.BmcExceptionがスローされる原因となります。OCIから返される一般的なサービス・エラーの詳細は、APIエラーを参照してください。
Java暗号化キーのサイズ・エラー
HDFSコネクタで処理できるのは、キー長が128ビット以下のキーのみです。AES256などサイズが大きいキーを使用すると、「Invalid Key Exception」や「Illegal key size」のエアーを受け取ります。この問題を修正するには、次のいずれかの回避策を使用します:
- AES128など、128ビット・キーを使用します。
-
次の場所からJava Cryptography Extension (JCE) Unlimited Strength Jurisdictionをインストールします: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
コントリビューション 🔗
コントリビュートするバグの修正または新しい機能がありますか。SDKはオープン・ソースであり、GitHubでプル・リクエストを受け入れています。
通知 🔗
HDFSコネクタの新しいバージョンがリリースされたときに通知を受け取るには、Atomフィードをサブスクライブします。
質問またはフィードバック 🔗
連絡方法:
- GitHub Issues: バグの報告および機能リクエストの作成
- Stack Overflow: oracle-cloud-infrastructureタグとoci-hdfs-connectorタグを使用して投稿します
- Oracle Cloudフォーラムの「開発者ツール」セクション
- My Oracle Support