Connettore HDFS per lo storage degli oggetti

Il connettore HDFS (Hadoop Distributed File System) consente all'applicazione Apache Hadoop di leggere e scrivere i dati nel e dal servizio Oracle Cloud Infrastructure Object Storage.

Questo SDK e questo esempio hanno una doppia licenza in base alla Universal Permissive License 1.0 e alla Apache License 2.0; i contenuti di terze parti sono concessi in licenza separatamente come descritto nel codice.

Requisiti

Per utilizzare il connettore HDFS, è necessario disporre dei seguenti elementi:

Credenziali e password

Se si utilizza un file PEM cifrato per le credenziali, la passphrase verrà letta dalla configurazione utilizzando il metodo di configurazione Hadoop getPassword. L'opzione getPassword verifica la presenza di una password in un provider di sicurezza registrato. Se il provider della sicurezza non contiene la chiave richiesta, verrà eseguito il fallback alla lettura della passphrase di testo normale direttamente dal file di configurazione.

Configurazione del TTL JVM per le ricerche dei nomi DNS

Java Virtual Machine (JVM) memorizza nella cache le risposte DNS dalle ricerche per un determinato periodo di tempo, denominato time-to-live (TTL). Ciò garantisce tempi di risposta più rapidi nel codice che richiede una frequente risoluzione del nome.

JVM utilizza la proprietà networkaddress.cache.ttl per specificare il criterio di inserimento nella cache per le ricerche dei nomi DNS. Il valore è un numero intero che rappresenta il numero di secondi per memorizzare nella cache la ricerca riuscita. Il valore predefinito per molte JVM, -1, indica che la ricerca deve essere inserita nella cache per sempre.

Poiché le risorse in Oracle Cloud Infrastructure utilizzano nomi DNS che possono cambiare, si consiglia di modificare il valore TTL in 60 secondi. Ciò garantisce che il nuovo indirizzo IP per la risorsa venga restituito nella query DNS successiva. È possibile modificare questo valore a livello globale o specifico per l'applicazione:

  • Per impostare TTL a livello globale per tutte le applicazioni che utilizzano JVM, aggiungere quanto segue nel file $JAVA_HOME/jre/lib/security/java.security:

    networkaddress.cache.ttl=60
  • Per impostare il TTL solo per l'applicazione, impostare quanto segue nel codice di inizializzazione dell'applicazione:

    java.security.Security.setProperty("networkaddress.cache.ttl" , "60");

Installazione

Copiare i file jar in bundle da lib e da terze parti/lib in ogni nodo del cluster Hadoop in modo che siano inclusi nel CLASSPATH di Hadoop.

SDK per gli artifact Java e Maven

La creazione di un connettore HDFS si basa sugli artifact Maven forniti da Oracle Cloud Infrastructure SDK per Java. Per ottenere gli artifact, è necessario scaricare l'SDK per Java e crearlo localmente. È quindi possibile creare il connettore HDFS.

Importante

La versione del file SDK per Java scaricata dalla pagina delle release di Oracle deve corrispondere alla versione del connettore HDFS, che è possibile trovare nel file hdfs-connector/pom.xml nel blocco dei tag di dipendenza con l'attributo groupId.

Connettore HDFS e artifact Maven

Il connettore HDFS è disponibile in Maven Central e JCenter.

Per utilizzare il connettore HDFS nel progetto, importare la dipendenza del progetto seguente. Ad esempio:

<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>

Proprietà

È possibile impostare le seguenti proprietà del connettore HDFS nel file core-site.xml. La pagina BmcProperties elenca le proprietà aggiuntive che è possibile configurare per una connessione allo storage degli oggetti.

Property Descrizione Tipo Obbligatorio
fs.oci.client.hostname

L'URL dell'endpoint host.

Ad esempio, https://www.example.com.

Stringa
fs.oci.client.auth.tenantId

OCID della tenancy.

Per ottenere il valore, vedere Chiavi e OCID obbligatori.

Stringa
fs.oci.client.auth.userId

OCID dell'utente che chiama l'API.

Per ottenere il valore, vedere Chiavi e OCID obbligatori.

Stringa
fs.oci.client.auth.fingerprint

L'impronta digitale della coppia di chiavi in uso.

Per ottenere il valore, vedere Chiavi e OCID obbligatori.

Stringa

Sì, a meno che non si fornisca un autenticatore personalizzato.

fs.oci.client.auth.pemfilepath Il percorso completo e il nome file della chiave privata utilizzata per l'autenticazione. Il file deve trovarsi nel file system locale. Stringa Sì, a meno che non si fornisca un autenticatore personalizzato.
fs.oci.client.auth.passphrase Passphrase utilizzata per la chiave, se cifrata. Stringa Solo se la chiave è crittata.
fs.oci.client.regionCodeOrId Codice area o identificativo area utilizzato per stabilire il nome dell'endpoint dello storage degli oggetti. Stringa N
Nota

È possibile specificare che un valore di proprietà si applica a un bucket specifico aggiungendo .<bucket_name>.<namespace_name> al nome della proprietà.

Impostazione dell'endpoint area

Per impostare l'endpoint dell'area per il connettore HDFS è possibile utilizzare diversi metodi:

  • Specifica della proprietà hostname in core-site.xml
  • Specifica della proprietà codice area o identificativo area in core-site.xml
  • Consentire al client ObjectStorage di selezionare l'endpoint tramite il servizio di metadati dell'istanza

Configurazione delle proprietà con core-site.xml

Questo esempio mostra come configurare le proprietà in un file core-site.xml (gli OCID vengono abbreviati per brevità):

<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>

Uso dei principal istanza per l'autenticazione

Oracle fornisce principali istanza in modo da non dover più configurare le credenziali utente o fornire file PEM sui servizi in esecuzione sulle istanze. Ognuna di queste istanze ha la propria identità e si esegue l'autenticazione utilizzando i certificati aggiunti all'istanza dai principal dell'istanza.

Per utilizzare l'autenticazione dei principal dell'istanza con il connettore HDFS, fornire semplicemente la proprietà fs.oci.client.custom.authenticator e impostare il valore su com.oracle.bmc.hdfs.auth.InstancePrincipalsCustomAuthenticator.

Poiché l'uso dei principal dell'istanza fornisce al connettore un autenticatore personalizzato, non è più necessario configurare le proprietà riportate di seguito.

  • 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

Il seguente codice di esempio illustra l'uso dei principal dell'istanza per l'autenticazione con il connettore 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>

Per ulteriori informazioni sui principal delle istanze, vedere Annuncio dei principal delle istanze per Identity and Access Management.

Uso dei principal risorsa per l'autenticazione

Analogamente ai principal delle istanze, Oracle fornisce principali risorse per autenticare le risorse che non sono istanze, ad esempio un notebook jupyter. Ogni risorsa ha la propria identità ed esegue l'autenticazione utilizzando i certificati aggiunti.

Per utilizzare l'autenticazione dei principal risorsa con il connettore HDFS, fornire semplicemente la proprietà fs.oci.client.custom.authenticator e impostare il valore su com.oracle.bmc.hdfs.auth.ResourcePrincipalsCustomAuthenticator.

Poiché l'utilizzo dei principal risorsa fornisce al connettore un autenticatore personalizzato, non è necessario configurare a lungo le seguenti proprietà:

  • 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

Il seguente codice di esempio illustra l'uso dei principal risorsa per l'autenticazione con il connettore 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>

Per ulteriori informazioni sui principal delle istanze, vedere Utilizzo dei principal delle risorse nel servizio Data Science.

Uso dell'autenticazione Kerberos

Oracle supporta l'autenticazione Kerberos per connettersi allo storage degli oggetti utilizzando il connettore HDFS.

Per utilizzare l'autenticazione Kerberos con il connettore HDFS:
  1. In core-site.xml, impostare la proprietà fs.oci.client.custom.authenticator su com.oracle.bmc.hdfs.auth.spnego.UPSTAuthenticationCustomAuthenticator.
  2. In core-site.xml impostare le proprietà riportate di seguito.
    • 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

Il file core-site.xml di esempio seguente illustra l'uso di Kerberos con l'autenticazione del token SPNEGO con il connettore HDFS.

<?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>

Per ulteriori informazioni su Kerberos, vedere Esercitazione sul protocollo Kerberos.

Per ulteriori informazioni su SPNEGO, vedere RFC 4178.

Utilizzo del valore predefinito Jersey HttpUrlConnectorProvider

A partire dalla versione 3.3.0.7.0.0, HDFS supporta l'uso del client Apache per impostazione predefinita per effettuare chiamate di servizio OCI. Questo perché HDFS Connector si basa sull'SDK per Java per inviare richieste al server. L'SDK per Java supporta l'uso di Jersey ApacheConnectorProvider per impostazione predefinita anziché Jersey HttpUrlConnectorProvider per consentire a Apache HttpClient di effettuare chiamate ai servizi OCI.

Per tornare al vecchio client predefinito di Jersey, impostare la proprietà fs.oci.client.jersey.default.connector.enabled nel file core-site.xml su true. Per impostazione predefinita, questo valore viene impostato su false.

Ottimizzazione delle prestazioni con il connettore Apache per HDFS

Il connettore Apache supporta due strategie di chiusura delle connessioni: ApacheConnectionClosingStrategy.GracefulClosingStrategy e ApacheConnectionClosingStrategy.ImmediateClosingStrategy.

Quando si utilizza ApacheConnectionClosingStrategy.GracefulClosingStrategy, i flussi restituiti da una risposta vengono letti fino alla fine del flusso quando si chiude il flusso. Questo può introdurre ulteriore tempo quando si chiude il flusso con una lettura parziale, a seconda della dimensione del flusso rimanente. Per evitare questo ritardo, si consiglia di utilizzare ApacheConnectionClosingStrategy.ImmediateClosingStrategy per file di grandi dimensioni con letture parziali. Con ApacheConnectionClosingStrategy.ImmediateClosingStrategy, i flussi vengono letti solo alla fine quando si chiude il flusso, il che può migliorare le prestazioni. Si noti che ApacheConnectionClosingStrategy.ImmediateClosingStrategy richiede più tempo quando si utilizza la lettura parziale per dimensioni di flusso inferiori (flussi inferiori a 1 MB).

Impostazione della strategia di chiusura della connessione

Impostare la strategia di chiusura della connessione impostando la proprietà fs.oci.client.apache.connection.closing.strategy nel file core-site.xml:

  • Per utilizzare ApacheConnectionClosingStrategy.GracefulClosingStrategy, impostare fs.oci.client.apache.connection.closing.strategy su graceful.
  • Per utilizzare ApacheConnectionClosingStrategy.ImmediateClosingStrategy, impostare fs.oci.client.apache.connection.closing.strategy su immediate.
Nota

Queste strategie di chiusura funzionano solo con Apache Connector for HDFS e vengono ignorate quando si utilizza il connettore predefinito di Jersey.

Ripristino del connettore predefinito di Jersey

Il connettore predefinito di Jersey legge i flussi fino alla fine e quindi riutilizza il flusso, il che può portare a prestazioni migliori rispetto al connettore Apache per HDFS in alcuni scenari. Se queste strategie di chiusura di Apache Connection non forniscono risultati ottimali per i casi d'uso, è possibile tornare a Jersey Default `HttpUrlConnectorProvider` È possibile tornare al vecchio client predefinito di Jersey impostando la proprietà fs.oci.client.jersey.default.connector.enabled nel file core-site.xml su true. Per impostazione predefinita, questo valore viene impostato su false.

Per ulteriori informazioni, vedere https://github.com/oracle/oci-java-sdk/blob/master/ApacheConnector-README.md.

Connection pooling in HDFS

È possibile impostare il numero massimo di connessioni nel connection pool del connettore HDFS.

A tale scopo, modificare la proprietà fs.oci.client.apache.max.connection.pool.size nel file core-site.xml in un numero intero positivo che specifica il numero di connessioni al pool.

Nota

Questa proprietà è supportata solo se si utilizza ApacheConnector per HDFS; in caso contrario viene ignorata.

Endpoint dedicati

Gli endpoint dedicati sono i modelli di endpoint definiti da un servizio per un realm specifico a livello di client. Il connettore HDFS OCI consente di abilitare l'uso di questi modelli di endpoint specifici del realm impostando il nome host fs.oci.client.hostname o la proprietà fs.oci.realmspecific.endpoint.template.enabled del flag del modello di endpoint in core-site.xml.
Nota

Se si imposta la proprietà del modello di endpoint, è necessario impostare anche fs.oci.client.regionCodeOrId in core-site.xml.
Nota

Il valore impostato tramite il nome host in core-site.xml ha la precedenza sul set di valori utilizzando la proprietà del modello di endpoint in core-site.xml.
Questo esempio mostra come abilitare la funzione dei modelli di endpoint specifici del realm impostando la proprietà 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>
In questo esempio viene illustrato come abilitare la funzione dei modelli di endpoint specifici del realm impostando la proprietà 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>

Configurazione di un proxy HTTP

È possibile impostare le seguenti proprietà opzionali nel file core-site.xml per configurare un proxy HTTP:

Property Descrizione Tipo Obbligatorio
fs.oci.client.proxy.uri

URI dell'endpoint proxy.

Ad esempio, http://proxy.mydomain.com:80.

Stringa N
fs.oci.client.proxy.username Il nome utente da autenticare con il proxy. Stringa N
fs.oci.client.proxy.password La password per autenticare con il proxy. Stringa N
fs.oci.client.multipart.allowed Consente al gestore caricamenti di supportare i caricamenti multiparte Boolean N
fs.oci.client.multipart.minobjectsize.mb

Specifica la dimensione minima dell'oggetto in mebibyte per utilizzare il gestore caricamenti.

Numero intero N
fs.oci.client.multipart.partsize.mb Specifica la dimensione della parte in mebibyte per il gestore caricamenti. Numero intero N
Nota

La configurazione di un proxy consente di utilizzare ApacheConnectorProvider quando si effettuano connessioni allo storage degli oggetti. Esegue il buffer delle richieste nella memoria e può influire sull'utilizzo della memoria durante il caricamento di oggetti di grandi dimensioni. Si consiglia di abilitare i caricamenti multiparte e modificare le proprietà multiparte per gestire il consumo di memoria.

Caricamento LOB (Large Object)

Gli oggetti di grandi dimensioni vengono caricati nello storage degli oggetti utilizzando caricamenti multiparte. Il file viene diviso in parti più piccole che vengono caricate in parallelo, riducendo così i tempi di caricamento. Ciò consente inoltre al connettore HDFS di riprovare a eseguire il caricamento delle parti non riuscite invece di non riuscire nell'intero caricamento. Tuttavia, i caricamenti potrebbero non riuscire in modo temporaneo e il connettore tenterà di interrompere i file caricati parzialmente. Poiché questi file si accumulano (e ti verrà addebitato il costo per lo storage), elencare i caricamenti periodicamente e quindi dopo un certo numero di giorni interromperli manualmente utilizzando l'SDK per Java.

Le informazioni sull'uso dell'API di storage degli oggetti per la gestione dei caricamenti multiparte sono disponibili in Utilizzo dei caricamenti multiparte.

Nota

Se si preferisce non utilizzare i caricamenti multiparte, è possibile disabilitarli impostando la proprietà fs.oci.client.multipart.allowed su false.

Procedure ottimali

Le sezioni seguenti contengono procedure ottimali per ottimizzare l'uso e le prestazioni.

Nomi directory

Nessuna directory effettiva nello storage degli oggetti. Il raggruppamento delle directory è una funzione della convenzione di denominazione, in cui gli oggetti utilizzano i delimitatori / nei rispettivi nomi. Ad esempio, un oggetto denominato a/example.json implica che esiste una directory denominata a. Tuttavia, se tale oggetto viene eliminato, anche la directory a viene eliminata in modo implicito. Per preservare la semantica del file system in cui la directory può esistere senza la presenza di file, il connettore HDFS crea un oggetto effettivo il cui nome termina in / con un percorso che rappresenta la directory, ovvero crea un oggetto denominato a/. Ora, l'eliminazione di a/example.json non influisce sull'esistenza della directory a, poiché l'oggetto a/ mantiene la sua presenza. Tuttavia, è del tutto possibile che qualcuno possa eliminare quell'oggetto a/ senza eliminare i file / directory sottostanti. Il connettore HDFS eliminerà l'oggetto cartella solo se non sono presenti oggetti sotto tale percorso. L'oggetto cartella è pari a zero byte.

File system non coerente

L'eliminazione di una directory significa l'eliminazione di tutti gli oggetti che iniziano con il prefisso che rappresenta tale directory. HDFS consente di eseguire query sullo stato di un file o di una directory. Lo stato del file di una directory viene implementato verificando che l'oggetto cartella per tale directory esista. Tuttavia, è possibile che l'oggetto cartella sia stato eliminato, ma alcuni degli oggetti con tale prefisso esistono ancora. Ad esempio, in una situazione con questi oggetti:

  • a/b/example.json
  • a/b/file.json
  • a/b/

HDFS sa che la directory /a/b/ esiste ed è una directory e la sua scansione produrrebbe example.json e file.json. Tuttavia, se l'oggetto a/b/ è stato eliminato, il file system sembrerebbe essere in uno stato incoerente. È possibile eseguire una query per tutti i file nella directory /a/b/ e trovare le due voci, ma l'esecuzione di una query per lo stato della directory /a/b/ effettiva comporterebbe un'eccezione poiché la directory non esiste. Il connettore HDFS non tenta di riparare lo stato del file system.

Creazione file

Lo storage degli oggetti supporta oggetti che possono avere una dimensione di molti gigabyte. La creazione di file verrà normalmente eseguita scrivendo in un file temporaneo e quindi caricando il contenuto del file quando il flusso viene chiuso. Lo spazio temporaneo deve essere abbastanza grande da gestire più caricamenti. La directory temporanea utilizzata è controllata dalla proprietà di configurazione hadoop.tmp.dir.

Supporto lettura/ricerca

Quando i buffer in-memory sono abilitati (fs.oci.io.read.inmemory), la ricerca è completamente supportata perché l'intero file è inserito nel buffer in un array di byte. Quando il buffer in-memory non è abilitato (probabilmente perché le dimensioni degli oggetti sono grandi), la ricerca viene implementata chiudendo il flusso e creando una nuova richiesta di intervallo a partire dall'offset specificato.

Elenco directory

La lista di una directory è essenzialmente un'operazione del bucket di lista con un prefisso e un delimitatore specificati. Per creare un'istanza HDFS FileStatus per ogni chiave, il connettore esegue una richiesta HEAD aggiuntiva per ottenere ObjectMetadata per ogni singola chiave. Questa operazione sarà necessaria finché lo storage degli oggetti non supporta i dati delle operazioni di lista più avanzata.

Formato URI per file system e file

Si fa riferimento ai file system e ai file HDFS tramite gli URI. Lo schema specifica il tipo di file system e la parte rimanente dell'URI è in gran parte libera per l'implementazione del file system da interpretare come vuole.

Poiché lo storage degli oggetti è un'area di memorizzazione degli oggetti, la relativa capacità di assegnare un nome agli oggetti come se fossero file in un file system viene utilizzata per imitare un file system effettivo.

Radice

La radice del file system di storage degli oggetti è indicata da un percorso in cui il componente Authority include il nome del bucket e il nome dello spazio di nomi, come mostrato di seguito.

Nota

Negli esempi, "MyBucket" e "MyNamespace" sono segnaposto e devono essere sostituiti con valori appropriati.

oci://MyBucket@MyNamespace/
		

Questa è sempre la radice del file system. Il motivo per cui si utilizza l'autorità sia per il bucket che per lo spazio dei nomi è che HDFS consente solo alla parte dell'autorità di determinare dove si trova il file system; la parte del percorso indica solo il percorso della risorsa (quindi "oci//MyNamespace/MyBucket" non funzionerà, ad esempio). Si noti che il carattere @ non è un carattere valido per i bucket o gli spazi di nomi e deve consentire l'analisi corretta dell'autorità.

Sottodirectory

Le sottodirectory in realtà non esistono, ma possono essere modificate creando oggetti con caratteri /. Ad esempio, due file denominati a/b/c/example.json e a/b/d/path.json vengono visualizzati come se si trovassero in una directory comune a/b. Ciò si ottiene utilizzando l'esecuzione di query basata su prefissi e delimitatori dello storage degli oggetti. Nell'esempio riportato di seguito, fare riferimento a una sottodirectory come URI.


oci://MyBucket@MyNamespace/a/b/
		

Oggetti/file

A un oggetto denominato a/b/c/example.json viene fatto riferimento come:


oci://MyBucket@MyNamespace/a/b/c/example.json
		

Registrazione

Il login al connettore viene eseguito tramite SLF4J. SLF4J è un'astrazione di log che consente l'uso di una libreria di log fornita dall'utente (ad esempio, log4j). Per ulteriori informazioni, vedere il manuale SLF4J.

L'esempio seguente mostra come abilitare il log di base all'output standard.

  1. Scaricare il file jar di associazione semplice SLF4J: SLF4J Simple Binding
  2. Aggiungi il file jar al classpath
  3. Aggiungere l'argomento VM seguente per abilitare il log del livello di debug (per impostazione predefinita, viene utilizzato il livello di informazioni): -Dorg.slf4j.simpleLogger.defaultLogLevel=debug

È possibile configurare opzioni di log più avanzate utilizzando l'associazione log4j.

Uso del framework di monitoraggio

Il connettore HDFS per lo storage degli oggetti include un framework di monitoraggio che fornisce metriche sulle operazioni eseguite utilizzando il connettore. Il framework di monitoraggio fornisce un'interfaccia che può essere implementata per utilizzare/ascoltare le metriche generate dal connettore. È possibile fornire un'implementazione personalizzata di questa interfaccia oppure utilizzare l'implementazione della telemetria pubblica OCI inclusa in questo framework.

Guida introduttiva

Per iniziare a utilizzare il framework di monitoraggio del connettore HDFS, sarà necessario impostare le seguenti proprietà. Una volta impostate queste proprietà per OCIMonitoring, è possibile utilizzare la vista Explorer metriche nella console OCI per osservare le metriche emesse dal connettore HDFS.

fs.oci.mon.consumer.plugins

fs.oci.mon.consumer.plugins accetta una lista separata da virgole di nomi di classe completamente qualificati delle implementazioni dell'interfaccia di monitoraggio. com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin deve essere utilizzato nella lista se si desidera che le metriche vengano emesse nella telemetria pubblica OCI.
<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

La proprietà fs.oci.mon.grouping.cluster.id specifica l'identificativo per il cluster HDFS o qualsiasi altro ID in cui si desidera raggruppare le metriche. Questa è una proprietà obbligatoria, utilizzata anche da OCIMonitorPlugin per contrassegnare le metriche. Questa proprietà è visibile come dimensione nell'interfaccia utente e nell'API della telemetria pubblica OCI.
<property>
    <name>fs.oci.mon.grouping.cluster.id</name>
    <value>hdfs-sample-cluster-id</value>
</property>

Proprietà com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin

Se la proprietà com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin è abilitata, sono applicabili le proprietà riportate di seguito.

fs.oci.mon.telemetry.ingestion.endpoint

La proprietà fs.oci.mon.telemetry.ingestion.endpoint consente di configurare l'endpoint di inclusione della telemetria del monitoraggio OCI. Per ulteriori informazioni, vedere l'elenco dei punti disponibili.
<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

La proprietà fs.oci.mon.compartment.ocid viene utilizzata per configurare il compartimento OCI al quale verranno collegate le metriche. In genere si tratta del compartimento a cui appartengono i bucket.
<property>
    <name>fs.oci.mon.compartment.ocid</name>
    <value>ocid1.compartment.oc1..sample.compartment.id</value>
</property>

fs.oci.mon.bucket.level.enabled

La proprietà fs.oci.mon.bucket.level.enabled determina se collegare il nome del bucket come dimensione alle metriche emesse.
<property>
    <name>fs.oci.mon.bucket.level.enabled</name>
    <value>true</value>
</property>

fs.oci.mon.ns.name

La proprietà fs.oci.mon.ns.name controlla lo spazio di nomi utilizzato per le metriche emesse dal connettore HDFS. Uno spazio di nomi di esempio potrebbe essere "hdfsconnector". Questo risiederà insieme ad altri spazi di nomi predefiniti come oci_objectstorage nella telemetria pubblica.
<property>
    <name>fs.oci.mon.ns.name</name>
    <value>name.of.namespace.on.oci.telemetry</value>
</property>

fs.oci.mon.rg.name

La proprietà fs.oci.mon.rg.name imposta il nome del gruppo di risorse utilizzato per contenere le metriche. Questo può essere qualsiasi nome logico per il raggruppamento delle risorse che verranno monitorate insieme. Questo nome di gruppo di risorse verrà visualizzato nello spazio di nomi scelto in precedenza nella telemetria pubblica OCI.
<property>
    <name>fs.oci.mon.rg.name</name>
    <value>name.of.resource.group.on.oci.telemetry</value>
</property>

Creazione del proprio consumer per le metriche

Per utilizzare l'interfaccia com.oracle.bmc.hdfs.monitoring.OCIMonitorConsumerPlugin, è necessario definire due metodi:
  • accept
  • shutdown

L'estensione delle classi deve avere un costruttore con la stessa firma della classe OCIMonitorConsumerPlugin.

Ad esempio:
public OCIMonitorConsumerPlugin(BmcPropertyAccessor propertyAccessor, String bucketName, String monitoringGroupingID, String namespaceName);
Questo esempio mostra ogni metodo che deve essere implementato da un plugin consumer:
/**
 * 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();
}

La classe OCIMetric può essere implementata in tre modi:

Un semplice oggetto OCIMetric con i seguenti campi:
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;
}
Implementazione dell'oggetto OCIMetricWithThroughput che estende OCIMetric e dispone di campi aggiuntivi per il throughput e i byte trasferiti. Questo è applicabile alle operazioni di lettura e scrittura:
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;
}
Oggetto OCIMetricWithFBLatency che estende OCIMetricWithThroughput, con un tempo aggiuntivo al campo di latenza del primo byte. Questa opzione è valida solo per le operazioni READ:
public class OCIMetricWithFBLatency extends OCIMetricWithThroughput {
    /**
     * The time to first byte when a read operation was performed in milliseconds.
     */
    private final double ttfb;
}

Job Hadoop di esempio

hadoop_sample_hdfs:


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);
    }
}

Risoluzione dei problemi

Questa sezione contiene informazioni sulla risoluzione dei problemi per il connettore HDFS.

Risoluzione dei problemi relativi agli errori dei servizi

Qualsiasi operazione che causa un errore del servizio causerà un'eccezione di tipo com.oracle.bmc.model.BmcException restituita dal connettore HDFS. Per informazioni sugli errori di servizio comuni restituiti da OCI, vedere Errori API.

Errori dimensione chiave di cifratura Java

Il connettore HDFS può gestire solo chiavi di lunghezza inferiore o uguale a 128 bit. Gli utenti ricevono gli errori "Eccezione chiave non valida" e "Dimensione chiave non valida" quando utilizzano chiavi più lunghe, ad esempio AES256. Utilizzare una delle soluzioni indicate di seguito per risolvere il problema.

Contributi

Hai trovato una soluzione per un bug o una nuova funzionalità a cui vorresti contribuire? L'SDK è open source e accetta le richieste Pull su GitHub.

Notifiche

Se si desidera ricevere una notifica quando viene rilasciata una nuova versione del connettore HDFS, effettuare la sottoscrizione al feed Atom.