HDFS-Connector für Object Storage
Mit dem Connector für Hadoop Distributed File System-(HDFS-)Connector können die Apache Hadoop-Anwendung Daten im und aus dem Oracle Cloud Infrastructure Object Storage-Service lesen und schreiben.
Dieses SDK und das Beispiel sind im Rahmen der Universal Permissive License 1.0 und der Apache License 2.0 doppelt lizenziert. Drittanbieterinhalte werden separat lizenziert, wie im Code beschrieben.
- Unterstützte Services: Object Storage
- Herunterladen: GitHub oder Maven
- API-Dokumentation: HDFS-Connector-API-Referenz
Anforderungen
Zur Verwendung des HDFS-Connectors ist Folgendes erforderlich:
- Ein Oracle Cloud Infrastructure-Account.
- Ein in diesem Account erstellter Benutzer in einer Gruppe mit einer Policy, die die gewünschten Berechtigungen für jeden zu verwendenden Bucket erteilt. Dies kann ein Benutzer für Sie selbst oder eine andere Person/ein anderes System sein, die/das die API aufrufen muss. Ein Beispiel für die Einrichtung eines neuen Benutzers, einer neuen Gruppe, eines neuen Compartments und einer neuen Policy finden Sie unter Benutzer hinzufügen. Informationen zu einer allgemeinen Object Storage-Policy finden Sie unter Verwalten von Buckets und Objekten durch Object Storage-Administratoren zulässig.
- Java 8
- Ein TTL-Wert von 60. Weitere Informationen finden Sie unter JVM-TTL für DNS-Namen-Lookups konfigurieren.
Zugangsdaten und Kennwörter
Wenn Sie eine verschlüsselte PEM-Datei für Zugangsdaten verwenden, wird die Passphrase mit der Hadoop-Konfigurationsmethode getPassword
aus der Konfiguration gelesen. Die Option getPassword
sucht nach einem Kennwort in einem registrierten Sicherheitsprovider. Wenn der Sicherheitsprovider nicht den angeforderten Schlüssel enthält, wird die Klartext-Passphrase direkt aus der Konfigurationsdatei gelesen.
JVM-TTL für DNS-Namen-Lookups konfigurieren
Java Virtual Machine (JVM) cacht DNS-Antworten aus Lookups für einen festgelegten Zeitraum, der als Gültigkeitsdauer (Time to Live; TTL) bezeichnet wird. Dadurch wird eine kürzere Antwortzeit in Code gewährleistet, der häufige Namensauflösungen erfordert.
Die JVM verwendet die Eigenschaft networkaddress.cache.ttl zur Angabe der Caching-Policy für DNS-Namen-Lookups. Der Wert ist eine Ganzzahl, die angibt, wie viele Sekunden der erfolgreiche Lookup im Cache gespeichert wird. Der Standardwert für viele JVMs, -1
, gibt an, dass der Lookup unbegrenzt gecacht werden soll.
Da Ressourcen in Oracle Cloud Infrastructure DNS-Namen verwenden, die sich ändern können, wird empfohlen, den TTL-Wert in 60 Sekunden zu ändern. Dadurch wird sichergestellt, dass die neue IP-Adresse für die Ressource bei der nächsten DNS-Abfrage zurückgegeben wird. Sie können diesen Wert global oder speziell für Ihre Anwendung ändern:
-
Um TTL für alle Anwendungen global mit der JVM festzulegen, fügen Sie Folgendes in der Datei
$JAVA_HOME/jre/lib/security/java.security
hinzu:networkaddress.cache.ttl=60
-
Um TTL nur für Ihre Anwendung festzulegen, legen Sie Folgendes im Initialisierungscode Ihrer Anwendung fest:
java.security.Security.setProperty("networkaddress.cache.ttl" , "60");
Installation
Kopieren Sie die gebündelten JAR-Dateien aus lib und third-party/lib in jeden Knoten des Hadoop-Clusters, damit sie im Classpath von Hadoop enthalten sind.
SDK für Java und Maven-Artefakte
Das Erstellen eines HDFS-Connectors basiert auf Maven-Artefakten, die vom Oracle Cloud Infrastructure-SDK für Java bereitgestellt werden. Um die Artefakte zu beziehen, müssen Sie das SDK für Java herunterladen und lokal erstellen. Dann können Sie den HDFS-Connector erstellen.
Die Dateiversion des SDK für Java, die Sie von der Seite mit Oracle-Releases herunterladen, muss mit der Version des HDFS-Connectors übereinstimmen. Diese finden Sie in der Datei
hdfs-connector/pom.xml
im Abhängigkeitstagblock mit dem Attribut groupId
.HDFS-Connector und Maven-Artefakte
Der HDFS-Connector ist unter Maven Central und JCenter verfügbar.
Um den HDFS-Connector in Ihrem Projekt zu verwenden, importieren Sie die folgende Projektabhängigkeit. Beispiel:
<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>
Eigenschaften
Sie können die folgenden HDFS-Connector-Eigenschaften in der Datei core-site.xml
festlegen. Auf der Seite BmcProperties werden zusätzliche Eigenschaften aufgeführt, die Sie für eine Verbindung zu Object Storage konfigurieren können.
Eigenschaft | Beschreibung | Typ | Erforderlich |
---|---|---|---|
fs.oci.client.hostname
|
Die URL des Hostendpunkts. Beispiel: |
Zeichenfolge | Ja |
fs.oci.client.auth.tenantId
|
Die OCID Ihres Mandanten. Die Werte finden Sie unter Erforderliche Schlüssel und OCIDs. |
Zeichenfolge | Ja |
fs.oci.client.auth.userId
|
Die OCID des Benutzers, der die API aufruft. Die Werte finden Sie unter Erforderliche Schlüssel und OCIDs. |
Zeichenfolge | Ja |
fs.oci.client.auth.fingerprint
|
Der Fingerprint für das verwendete Schlüsselpaar. Die Werte finden Sie unter Erforderliche Schlüssel und OCIDs. |
Zeichenfolge |
Ja, es sei denn, Sie stellen einen benutzerdefinierten Authentikator bereit |
fs.oci.client.auth.pemfilepath
|
Vollständiger Pfad und Dateiname des Private Keys für die Authentifizierung. Die Datei muss sich im lokalen Dateisystem befinden. | Zeichenfolge | Ja, es sei denn, Sie stellen einen benutzerdefinierten Authentikator bereit |
fs.oci.client.auth.passphrase
|
Die Passphrase für den Schlüssel, sofern er verschlüsselt ist. | Zeichenfolge | Nur wenn der Schlüssel verschlüsselt ist. |
fs.oci.client.regionCodeOrId
|
Der Regionscode oder die Regions-ID zum Einrichten des Object Storage-Endpunktnamens. | Zeichenfolge | Nein |
Sie können angeben, dass ein Eigenschaftswert auf einen bestimmten Bucket angewendet wird, indem Sie
.<bucket_name>.<namespace_name>
an den Eigenschaftsnamen anhängen.Regionsendpunkt festlegen
Es gibt verschiedene Methoden, mit denen Sie den Regionsendpunkt für den HDFS-Connector festlegen können:
- Hostnamenseigenschaft in
core-site.xml
angeben - Regionscode oder Regions-ID-Eigenschaft in
core-site.xml
angeben - Zulassen, dass der ObjectStorage-Client den Endpunkt über den Instance Metadata Service abruft
Eigenschaften mit core-site.xml konfigurieren
Dieses Beispiel zeigt, wie Eigenschaften in einer core-site.xml
-Datei konfiguriert werden können (OCIDs sind aus Gründen der Einfachheit gekürzt):
<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>
Instanz-Principals für Authentifizierung verwenden
Oracle stellt Instanz-Principals bereit, damit Sie keine Benutzerzugangsdaten mehr konfigurieren oder PEM-Dateien auf Services angeben müssen, die auf Instanzen ausgeführt werden. Jede dieser Instanzen hat eine eigene Identität und authentifiziert sich durch Verwendung von Zertifikaten, die der Instanz von Instanz-Principals hinzugefügt wurden.
Um die Authentifizierung durch Instanz-Principals mit dem HDFS-Connector zu verwenden, geben Sie die Eigenschaft fs.oci.client.custom.authenticator
an, und setzen Sie den Wert auf com.oracle.bmc.hdfs.auth.InstancePrincipalsCustomAuthenticator
.
Da die Verwendung von Instanz-Principals dem Connector einen benutzerdefinierten Authentifizierer bereitstellt, müssen die folgenden Eigenschaften nicht mehr konfiguriert werden:
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
Der folgende Beispielcode zeigt, wie Instanz-Principals zur Authentifizierung mit dem HDFS-Connector verwendet werden:
<?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>
Weitere Informationen zu Instanz-Principals finden Sie unter Instanz-Principals für Identity and Access Management ankündigen.
Resource Principals für die Authentifizierung verwenden
Ähnlich wie Instanz-Principals stellt Oracle Resource Principals zur Authentifizierung der Ressourcen zur Verfügung, die keine Instanzen sind (wie ein Jupyter-Notizbuch). Jede Ressource hat eine eigene Identität und authentifiziert sich mit den ihr hinzugefügten Zertifikaten.
Um die Authentifizierung durch Resource Principals mit dem HDFS-Connector zu verwenden, geben Sie die Eigenschaft fs.oci.client.custom.authenticator
an, und setzen Sie den Wert auf com.oracle.bmc.hdfs.auth.ResourcePrincipalsCustomAuthenticator
.
Da die Verwendung von Resource Principals dem Connector einen benutzerdefinierten Authentifizierer bereitstellt, ist es nicht lange erforderlich, die folgenden Eigenschaften zu konfigurieren:
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
Der folgende Beispielcode zeigt, wie Resource Principals zur Authentifizierung mit dem HDFS-Connector verwendet werden:
<?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>
Weitere Informationen zu Instanz-Principals finden Sie unter Resource Principals im Data Science-Service verwenden.
Kerberos-Authentifizierung verwenden
Oracle unterstützt die Kerberos-Authentifizierung für die Verbindung mit Object Storage über den HDFS-Connector.
- Setzen Sie in
core-site.xml
die Eigenschaftfs.oci.client.custom.authenticator
aufcom.oracle.bmc.hdfs.auth.spnego.UPSTAuthenticationCustomAuthenticator
. - Legen Sie in
core-site.xml
die folgenden Eigenschaften fest: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
Die folgende Beispieldatei core-site.xml
veranschaulicht die Verwendung von Kerberos mit SPNEGO-Tokenauthentifizierung mit dem HDFS-Connector:
<?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>
Weitere Informationen zu Kerberos finden Sie im Kerberos-Protokoll-Tutorial.
Weitere Informationen zu SPNEGO finden Sie unter RFC 4178.
Jersey-Standardwert HttpUrlConnectorProvider verwenden
Ab Version 3.3.0.7.0.0 unterstützt HDFS standardmäßig die Verwendung des Apache-Clients zum Ausführen von OCI-Serviceaufrufen. Der Grund ist, dass sich der HDFS-Connector auf das SDK für Java verlässt, um Anforderungen an den Server zu senden. Das SDK für Java unterstützt standardmäßig die Verwendung von Jersey ApacheConnectorProvider
anstelle von Jersey HttpUrlConnectorProvider
, damit Apache HttpClient OCI-Serviceaufrufe ausführen kann.
Um zum alten Jersey-Standardclient zurückzukehren, setzen Sie die Eigenschaft fs.oci.client.jersey.default.connector.enabled
in der Datei core-site.xml
auf true
. Standardmäßig ist dieser Wert auf false
gesetzt.
Performanceoptimierung mit dem Apache-Connector für HDFS
Der Apache-Connector unterstützt zwei Verbindungsschließungsstrategien: ApacheConnectionClosingStrategy.GracefulClosingStrategy
und ApacheConnectionClosingStrategy.ImmediateClosingStrategy
.
Wenn Sie ApacheConnectionClosingStrategy.GracefulClosingStrategy
verwenden, werden die von einer Antwort zurückgegebenen Streams bis zum Ende gelesen, bevor der Stream geschlossen wird. Dies kann je nach Größe des restlichen Streams beim Schließen des Streams mit einem partiellen Lesevorgang zusätzliche Zeit erfordern. Um diese Verzögerung zu vermeiden, können Sie ApacheConnectionClosingStrategy.ImmediateClosingStrategy
für große Dateien mit partiellen Lesevorgängen verwenden. Mit ApacheConnectionClosingStrategy.ImmediateClosingStrategy
werden Streams nicht bis zum Ende gelesen, bevor der Stream geschlossen wird, was die Performance verbessern kann. Beachten Sie, dass ApacheConnectionClosingStrategy.ImmediateClosingStrategy
länger dauert, wenn partielle Lesevorgänge für kleinere Streamgrößen (unter 1 MB) verwendet werden.
Verbindungsschließungsstrategie festlegen
Legen Sie die Verbindungsschließungsstrategie fest, indem Sie die Eigenschaft fs.oci.client.apache.connection.closing.strategy
in der Datei core-site.xml
festlegen:
- Um
ApacheConnectionClosingStrategy.GracefulClosingStrategy
zu verwenden, setzen Siefs.oci.client.apache.connection.closing.strategy
aufgraceful
. - Um
ApacheConnectionClosingStrategy.ImmediateClosingStrategy
zu verwenden, setzen Siefs.oci.client.apache.connection.closing.strategy
aufimmediate
.
Diese Schließungsstrategien funktionieren nur mit dem Apache-Connector für HDFS und werden bei Verwendung des Jersey-Standard-Connectors ignoriert.
Zurück zum Jersey-Standard-Connector wechseln
Der Jersey-Standard-Connector liest Streams bis zum Ende und verwendet den Stream dann wieder, was in einigen Szenarios zu einer besseren Performance als beim Apache-Connector für HDFS führen kann. Wenn diese Apache-Verbindungsschließungsstrategien keine optimalen Ergebnisse für Ihre Anwendungsfälle liefern, können Sie den Jersey-Standardwert HttpUrlConnectorProvider verwenden. Um zurück zum alten Jersey-Standardclient zu wechseln, setzen Sie die Eigenschaft fs.oci.client.jersey.default.connector.enabled
in der Datei core-site.xml
auf true
. Standardmäßig ist dieser Wert auf false
gesetzt.
Weitere Informationen finden Sie unter: https://github.com/oracle/oci-java-sdk/blob/master/ApacheConnector-README.md.
Verbindungspooling in HDFS
Sie können die maximale Anzahl von Verbindungen im HDFS-Connector-Verbindungspool festlegen.
Ändern Sie dazu die Eigenschaft fs.oci.client.apache.max.connection.pool.size
in der Datei core-site.xml
in eine positive Ganzzahl, mit der Sie die Anzahl der Verbindungen im Pool angeben.
Diese Eigenschaft wird nur bei Verwendung von
ApacheConnector
für HDFS unterstützt. Andernfalls wird sie ignoriert.Dedizierte Endpunkte
fs.oci.client.hostname
oder die Eigenschaft fs.oci.realmspecific.endpoint.template.enabled
des Endpunktvorlagen-Flags in core-site.xml
festlegen. Wenn Sie die Endpunktvorlageneigenschaft festlegen, müssen Sie auch
fs.oci.client.regionCodeOrId
in core-site.xml
festlegen.Der über den Hostnamen in
core-site.xml
festgelegte Wert hat Vorrang vor dem Wert, der mit der Endpunktvorlageneigenschaft in core-site.xml
festgelegt wurde.fs.oci.client.hostname
festlegen:<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
festlegen:<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-Proxy konfigurieren
Sie können die folgenden optionalen Eigenschaften in der Datei core-site.xml
festlegen, um einen HTTP-Proxy zu konfigurieren:
Eigenschaft | Beschreibung | Typ | Erforderlich |
---|---|---|---|
fs.oci.client.proxy.uri
|
Die URI des Proxyendpunkts. Beispiel: |
Zeichenfolge | Nein |
fs.oci.client.proxy.username
|
Der Benutzername zur Authentifizierung beim Proxy. | Zeichenfolge | Nein |
fs.oci.client.proxy.password
|
Das Kennwort für die Authentifizierung beim Proxy. | Zeichenfolge | Nein |
fs.oci.client.multipart.allowed
|
Ermöglicht, dass der Uploadmanager Multipart-Uploads unterstützt. | Boolescher Wert | Nein |
fs.oci.client.multipart.minobjectsize.mb
|
Gibt die minimale Objektgröße für die Verwendung des Uploadmanagers in Mebibyte an. |
Ganzzahl | Nein |
fs.oci.client.multipart.partsize.mb
|
Gibt die Teilgröße für den Uploadmanager in Mebibyte an. | Ganzzahl | Nein |
Die Konfiguration eines Proxys ermöglicht die Verwendung von
ApacheConnectorProvider
beim Herstellen von Verbindungen zu Object Storage. Anforderungen werden im Arbeitsspeicher gepuffert. Dies kann sich beim Hochladen von Large Objects auf die Speicherauslastung auswirken. Es wird empfohlen, Multipart-Uploads zu aktivieren und die Eigenschaften für mehrteilige Vorgänge anzupassen, um den Speicherverbrauch zu verwalten.Large-Object-Uploads
Large Objects werden mithilfe von Multipart-Uploads in Object Storage hochgeladen. Die Datei wird in kleinere Teile aufgeteilt, die parallel hochgeladen werden, wodurch die Uploadzeiten reduziert werden. Dadurch kann der HDFS-Connector zudem den Upload nicht erfolgreicher Teile wiederholen, statt dass der gesamte Upload nicht erfolgreich verläuft. Uploads können jedoch vorübergehend nicht erfolgreich sein, und der Connector versucht, teilweise hochgeladene Dateien abzubrechen. Da sich diese Dateien ansammeln (und Sie für die Speicherung bezahlen müssen), listen Sie die Uploads regelmäßig und danach nach einer bestimmten Anzahl von Tagen manuell mit dem SDK für Java auf.
Informationen zur Verwendung der Object Storage-API zur Verwaltung von mehrteiligen Uploads finden Sie unter Multipart-Uploads verwenden.
Wenn Sie keine Multipart-Uploads verwenden möchten, können Sie sie deaktivieren, indem Sie die Eigenschaft
fs.oci.client.multipart.allowed
auf false
setzen.Best Practices
Die folgenden Abschnitte enthalten Best Practices zur Optimierung von Nutzung und Performance.
Verzeichnisnamen
Es sind keine eigentlichen Verzeichnisse in Object Storage. Die Verzeichnisgruppierung ist eine Funktion der Benennungskonvention, bei der Objekte /
-Begrenzungszeichen in ihren Namen verwenden. Beispiel: Ein Objekt mit dem Namen a/example.json
impliziert ein Verzeichnis mit dem Namen a
. Wenn dieses Objekt jedoch gelöscht wird, wird das Verzeichnis a
implizit ebenfalls gelöscht. Um die Dateisystemsemantik beizubehalten, bei der das Verzeichnis ohne Vorliegen von Dateien vorhanden sein kann, erstellt der HDFS-Connector ein tatsächliches Objekt, dessen Name mit /
endet, mit einem Pfad, der das Verzeichnis darstellt (d.h. ein Objekt mit dem Namen a/
). Wenn Sie a/example.json
löschen, wirkt sich dies nicht auf das Vorhandensein des Verzeichnisses a
aus, da das Objekt a/
weiterhin bestehen bleibt. Dennoch ist es möglich, dass ein Benutzer das Objekt a/
löscht, ohne die Dateien/Verzeichnisse darunter zu löschen. Der HDFS-Connector löscht das Ordnerobjekt nur, wenn unter diesem Pfad keine Objekte vorhanden sind. Das Ordnerobjekt selbst hat null Byte.
Inkonsistentes Dateisystem
Wenn ein Verzeichnis gelöscht wird, werden alle Objekte gelöscht, die mit dem Präfix beginnen, das dieses Verzeichnis darstellt. Mit HDFS können Sie den Dateistatus einer Datei oder eines Verzeichnisses abfragen. Der Dateistatus eines Verzeichnisses wird implementiert, indem geprüft wird, ob das Ordnerobjekt für dieses Verzeichnis vorhanden ist. Es ist jedoch möglich, dass das Ordnerobjekt gelöscht wurde, einige Objekte mit diesem Präfix jedoch noch vorhanden sind. Beispielsweise in einer Situation mit den folgenden Objekten:
a/b/example.json
a/b/file.json
a/b/
HDFS weiß, dass das Verzeichnis /a/b/
vorhanden und ein Verzeichnis ist. Das Scannen würde example.json
und file.json
zurückgeben. Wenn das Objekt a/b/
jedoch gelöscht wurde, weist das Dateisystem einen inkonsistenten Status auf. Sie können diese Abfrage für alle Dateien im Verzeichnis /a/b/
ausführen und die beiden Einträge suchen. Eine Abfrage des Status des tatsächlichen Verzeichnisses /a/b/
würde jedoch zu einer Ausnahme führen, weil das Verzeichnis nicht vorhanden ist. Der HDFS-Connector versucht nicht, den Status des Dateisystems zu reparieren.
Dateierstellung
Object Storage unterstützt Objekte mit einer Größe von vielen GB. Das Erstellen von Dateien erfolgt normalerweise, indem Sie in eine temporäre Datei schreiben und dann den Inhalt der Datei hochladen, wenn der Stream geschlossen wird. Der temporäre Speicherplatz muss ausreichend sein, um mehrere Uploads verarbeiten zu können. Das verwendete temporäre Verzeichnis wird von der Konfigurationseigenschaft hadoop.tmp.dir
gesteuert.
Support für Lesen/Suchen
Wenn In-Memory-Puffer aktiviert sind (fs.oci.io.read.inmemory
), wird das Suchen vollständig unterstützt, weil die gesamte Datei in einem Bytearray gepuffert wird. Wenn der In-Memory-Puffer nicht aktiviert ist (wahrscheinlich weil die Objektgrößen groß sind), wird die Suche implementiert, indem der Stream geschlossen und eine neue Bereichsanforderung ab dem angegebenen Offset gestellt wird.
Verzeichnisliste
Das Auflisten eines Verzeichnisses ist im Wesentlichen ein Listen-Bucket-Vorgang mit einem angegebenen Präfix und Begrenzungszeichen. Um eine HDFS-FileStatus-Instanz für jeden Schlüssel zu erstellen, führt der Connector eine zusätzliche HEAD-Anforderung aus, um ObjectMetadata für jeden einzelnen Schlüssel abzurufen. Dies ist erforderlich, bis Object Storage umfassendere Listenvorgangsdaten unterstützt.
URI-Format für Dateisysteme und Dateien
HDFS-Dateisysteme und -Dateien werden über URIs referenziert. Das Schema gibt den Dateisystemtyp an, und der verbleibende Teil der URI ist größtenteils frei, sodass die Dateisystemimplementierung ihn je nach Bedarf interpretieren kann.
Da Object Storage ein Objektspeicher ist, wird dessen Fähigkeit, Objekte so zu benennen, als wären es Dateien in einem Dateisystem, verwendet, um ein tatsächliches Dateisystem nachgeahmt.
Root
Die Root des Object Storage-Dateisystems wird durch einen Pfad angegeben, in dem die Berechtigungskomponente den Bucket-Namen und den Namespace-Namen enthält, wie dargestellt:
In den Beispielen sind "
MyBucket
" und "MyNamespace
" Platzhalter und müssen durch die entsprechenden Werte ersetzt werden.
oci://MyBucket@MyNamespace/
Dies ist immer der Root des Dateisystems. Der Grund für die Verwendung der Berechtigung für Bucket und Namespace besteht darin, dass bei HDFS nur anhand des Berechtigungsteils der Ort des Dateisystems bestimmt werden kann. Der Pfadteil bezeichnet lediglich den Pfad zur Ressource (daher würde z.B. "oci//MyNamespace/MyBucket" nicht funktionieren). Beachten Sie, dass das Zeichen @
kein gültiges Zeichen für Buckets oder Namespaces ist und die Berechtigung korrekt geparst werden muss.
Unterverzeichnisse
Unterverzeichnisse sind zwar nicht vorhanden, können jedoch durch das Erstellen von Objekten mit dem Zeichen /
imitiert werden. Beispiel: Zwei Dateien mit dem Namen a/b/c/example.json
und a/b/d/path.json
werden so angezeigt, als befänden sie sich in einem gemeinsamen Verzeichnis a/b
. Dies wird durch die Object Storage-Abfrage mithilfe von Präfix und Begrenzungszeichen erreicht. Im angegebenen Beispiel würde das Referenzieren eines Unterverzeichnisses als URI wie folgt aussehen:
oci://MyBucket@MyNamespace/a/b/
Objekte/Dateien
Ein Objekt mit dem Namen a/b/c/example.json
wird referenziert als:
oci://MyBucket@MyNamespace/a/b/c/example.json
Logging
Das Logging im Connector erfolgt über SLF4J. SLF4J ist eine Loggingabstraktion, die die Verwendung einer vom Benutzer angegebenen Logging-Library (z.B. log4j) ermöglicht. Weitere Informationen finden Sie im SLF4J-Handbuch.
Das folgende Beispiel zeigt, wie das allgemeine Logging für die Standardausgabe aktiviert wird.
- Laden Sie die SLF4J-JAR-Datei für einfaches Binding herunter: SLF4J für einfaches Binding
- Fügen Sie die JAR-Datei dem Classpath hinzu.
- Fügen Sie das folgende VM-Argument hinzu, um das Logging auf Debugebene zu aktivieren (standardmäßig wird die Informationsebene verwendet):
-Dorg.slf4j.simpleLogger.defaultLogLevel=debug
Mit dem log4j-Binding können Sie erweiterte Loggingoptionen konfigurieren.
Monitoring Framework verwenden
Der HDFS-Connector für Object Storage umfasst ein Monitoring-Framework, das Metriken für Vorgänge bereitstellt, die mit dem Connector ausgeführt werden. Das Monitoring-Framework bietet eine Schnittstelle, die implementiert werden kann, um vom Connector generierte Metriken zu konsumieren/zuhören. Sie können eine benutzerdefinierte Implementierung dieser Schnittstelle bereitstellen oder die öffentliche OCI-Telemetrieimplementierung verwenden, die in diesem Framework enthalten ist.
Erste Schritte
Um das HDFS Connector-Überwachungs-Framework zu verwenden, müssen Sie die folgenden Eigenschaften festlegen. Nachdem diese Eigenschaften für OCIMonitoring
festgelegt wurden, können Sie die Metriken, die vom HDFS-Connector ausgegeben werden, in der Ansicht "Metrik-Explorer" in der OCI-Konsole beobachten.
fs.oci.mon.consumer.plugins
fs.oci.mon.consumer.plugins
verwendet eine durch Komma getrennte Liste vollqualifizierter Klassennamen von Implementierungen der Monitoringschnittstelle. com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
muss in der Liste verwendet werden, wenn die Metriken an die öffentliche OCI-Telemetrie ausgegeben werden sollen.<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
gibt die ID für das HDFS-Cluster oder eine andere ID an, in der die Metriken gruppiert werden sollen. Dies ist eine obligatorische Eigenschaft, die auch von der OCIMonitorPlugin
zum Taggen von Metriken verwendet wird. Diese Eigenschaft ist als Dimension in der öffentlichen OCI-Telemetriebenutzeroberfläche und -API sichtbar.<property>
<name>fs.oci.mon.grouping.cluster.id</name>
<value>hdfs-sample-cluster-id</value>
</property>
com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
-Eigenschaften
Wenn die Eigenschaft com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
aktiviert ist, gelten die folgenden Eigenschaften:
fs.oci.mon.telemetry.ingestion.endpoint
fs.oci.mon.telemetry.ingestion.endpoint
kann der Telemetrieaufnahmeendpunkt des OCI-Monitoring konfiguriert werden. Weitere Informationen finden Sie in der Liste der verfügbaren Punkte.
<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
wird das OCI-Compartment konfiguriert, an das die Metriken angehängt werden. Dies ist in der Regel das Compartment, zu dem die Buckets gehören.<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
bestimmt, ob der Bucket-Name als Dimension an die ausgegebenen Metriken angehängt wird.<property>
<name>fs.oci.mon.bucket.level.enabled</name>
<value>true</value>
</property>
fs.oci.mon.ns.name
fs.oci.mon.ns.name
steuert den Namespace, der für die Metriken verwendet wird, die vom HDFS-Connector ausgegeben werden. Ein Beispiel-Namespace könnte "hdfsconnector" sein. Dies wird neben anderen vordefinierten Namespaces wie oci_objectstorage
in der öffentlichen Telemetrie gespeichert.<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
legt den Namen der Ressourcengruppe fest, der für die Metriken verwendet wird. Dies kann ein beliebiger logischer Name für die Gruppierung von Ressourcen sein, die gemeinsam überwacht werden. Dieser Ressourcengruppenname wird unter dem Namespace angezeigt, der zuvor in der öffentlichen OCI-Telemetrie ausgewählt wurde.<property>
<name>fs.oci.mon.rg.name</name>
<value>name.of.resource.group.on.oci.telemetry</value>
</property>
Eigenen Consumer für Metriken erstellen
com.oracle.bmc.hdfs.monitoring.OCIMonitorConsumerPlugin
zu verwenden, müssen Sie zwei Methoden definieren:accept
shutdown
Erweiterungsklassen sollten einen Konstruktor mit derselben Signatur wie die Klasse OCIMonitorConsumerPlugin
haben.
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();
}
Die Klasse OCIMetric
kann auf drei Arten implementiert werden:
OCIMetric
-Objekt mit den folgenden Feldern: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;
}
OCIMetricWithThroughput
-Objekts, das OCIMetric
erweitert und zusätzliche Felder für Durchsatz und übertragene Byte enthält. Dies gilt für READ- und WRITE-Vorgänge: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;
}
OCIMetricWithFBLatency
-Objekt, das OCIMetricWithThroughput
um ein zusätzliches Zeitfeld für die erste Byte-Latenz erweitert. Dies gilt nur für READ-Vorgänge:public class OCIMetricWithFBLatency extends OCIMetricWithThroughput {
/**
* The time to first byte when a read operation was performed in milliseconds.
*/
private final double ttfb;
}
Hadoop-Beispieljob
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);
}
}
Fehlerbehebung
Dieser Abschnitt enthält Informationen zur Fehlerbehebung für den HDFS-Connector.
Servicefehler beheben
Jeder Vorgang, der einen Servicefehler verursacht, führt zu einer Ausnahme vom Typ com.oracle.bmc.model.BmcException, die vom HDFS-Connector ausgelöst wird. Informationen zu häufigen Servicefehlern, die von OCI zurückgegeben werden, finden Sie unter API-Fehler.
Fehler mit Java-Verschlüsselungsschlüsselgröße
Der HDFS-Connector kann nur Schlüssel mit höchstens 128 Bit verarbeiten. Benutzer erhalten die Fehler "Ausnahme: Ungültiger Schlüssel" und "Unzulässige Schlüsselgröße", wenn sie längere Schlüssel wie AES256 verwenden. Um dieses Problem zu beheben, verwenden Sie einen der folgenden Workarounds:
- Verwenden Sie einen 128-Bit-Schlüssel, z.B. AES128.
-
Installieren Sie Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction von folgendem Speicherort: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
Beiträge
Sie haben einen Bugfix oder ein neues Feature, das Sie beitragen möchten? Das SDK ist Open Source und akzeptiert Pull-Anforderungen auf GitHub.
Benachrichtigungen
Wenn Sie benachrichtigt werden möchten, wenn eine neue Version des HDFS-Connectors veröffentlicht wird, abonnieren Sie den Atom-Feed.
Fragen oder Feedback
Kontaktmöglichkeiten:
- GitHub-Probleme: Zum Einreichen von Bugs und Featureanfragen
- Stack Overflow: Verwenden Sie die Tags oracle-cloud-infrastructure und oci-hdfs-connector in Ihrem Post.
- Abschnitt "Entwicklertools" der Oracle Cloud-Foren
- My Oracle Support