Connecteur HDFS pour Object Storage
Le connecteur HDFS (Hadoop Distributed File System) permet l'application Apache Hadoop de lire et d'écrire les données depuis et vers le service Oracle Cloud Infrastructure Object Storage.
Ce kit SDK et cet exemple sont concédés sous double licence : Universal Permissive License 1.0 et Apache 2.0. Le contenu tiers fait l'objet d'une licence distincte comme décrit dans le code.
- Services pris en charge : Object Storage
- Téléchargement : GitHub ou Maven
- Documentation d'API : Référence d'API du connecteur HDFS
Exigences
Pour utiliser le connecteur HDFS, vous devez disposer des éléments suivants :
- Un compte Oracle Cloud Infrastructure.
- Un utilisateur créé dans ce compte, dans un groupe avec une stratégie qui octroie les droits d'accès souhaités sur les buckets à utiliser. Il peut s'agir d'un utilisateur pour vous-même ou d'une autre personne/un autre système devant appeler l'API. Pour obtenir un exemple de configuration d'un nouvel utilisateur, d'un nouveau groupe, d'un nouveau compartiment et d'une nouvelle stratégie, reportez-vous à Ajout d'utilisateurs. Pour obtenir une stratégie Object Storage de base, reportez-vous à Autoriser l'administration Object Storage à gérer les buckets et les objets.
- Java 8
- Une valeur de durée de vie de 60. Pour plus d'informations, reportez-vous à Configuration de la durée de vie de la JVM pour les recherches de noms DNS.
Informations d'identification et mots de passe
Si vous utilisez un fichier PEM crypté pour les informations d'identification, la phrase de passe est lue à partir de la configuration à l'aide de la méthode de configuration Hadoop getPassword. L'option getPassword recherche un mot de passe dans un fournisseur de sécurité inscrit. Si le fournisseur de sécurité ne contient pas la clé demandée, il lit la phrase de passe en texte brut directement à partir du fichier de configuration.
Configuration d'une durée de vie de JVM pour les recherches de nom DNS
La JVM (Java Virtual Machine) met en mémoire cache les réponses DNS des recherches pendant une durée définie, appelée durée de vie. Cela permet de garantir un temps de réponse plus rapide dans le code nécessitant une résolution fréquente des noms.
La JVM utilise la propriété networkaddress.cache.ttl pour définir la stratégie de mise en mémoire cache des recherches de noms DNS. La valeur est un entier qui représente le nombre de secondes nécessaires à la mise en mémoire cache de la recherche effectuée. La valeur par défaut pour de nombreuses JVM, -1, indique que la recherche doit être mise en mémoire cache de manière permanente.
Etant donné que les ressources dans Oracle Cloud Infrastructure utilisent des noms DNS qui peuvent changer, nous vous recommandons de modifier la valeur de la période de temps sur 60 secondes. Cela garantit que la nouvelle adresse IP pour la ressource soit renvoyée lors de la prochaine requête DNS. Vous pouvez modifier cette valeur de manière globale ou spécifiquement pour votre application :
-
Afin de définir la durée de vie de manière globale pour toutes les applications utilisant la JVM, ajoutez ce qui suit au fichier
$JAVA_HOME/jre/lib/security/java.security:networkaddress.cache.ttl=60 -
Afin de définir la durée de vie uniquement pour votre application, définissez ce qui suit dans le code d'initialisation de votre application :
java.security.Security.setProperty("networkaddress.cache.ttl" , "60");
Installation
Copiez les fichiers JAR regroupés à partir de lib et de third-party/lib vers chaque noeud du cluster Hadoop afin qu'ils soient inclus dans la variable d'environnement CLASSPATH de Hadoop.
Kit SDK pour Java et artefacts Maven
La création d'un connecteur HDFS repose sur des artefacts Maven fournis par le kit SDK Oracle Cloud Infrastructure pour Java. Pour obtenir les artefacts, vous devez télécharger le kit SDK pour Java et le créer en local. Vous pouvez ensuite créer le connecteur HDFS.
La version d'un fichier SDK pour Java que vous téléchargez à partir de la page des versions Oracle doit correspondre à la version d'un connecteur HDFS, que vous pouvez trouver dans le fichier
hdfs-connector/pom.xml dans le bloc d'étiquettes de dépendance possédant l'attribut groupId.Connecteur HDFS et artefacts Maven
Le connecteur HDFS est disponible sur Maven Central et JCenter .
Pour utiliser le connecteur HDFS dans votre projet, importez la dépendance de projet suivante. Par exemple :
<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>
Propriétés
Vous pouvez définir les propriétés de connecteur HDFS suivantes dans le fichier core-site.xml. La page BmcProperties répertorie des propriétés supplémentaires que vous pouvez configurer pour une connexion à Object Storage.
| Propriété | Description | Type | Requise |
|---|---|---|---|
fs.oci.client.hostname
|
URL de l'adresse hôte. Par exemple, |
Chaîne | Oui |
fs.oci.client.auth.tenantId
|
OCID de votre location. Pour obtenir la valeur, reportez-vous à Clés et OCID requis. |
Chaîne | Oui |
fs.oci.client.auth.userId
|
OCID de l'utilisateur appelant l'API. Pour obtenir la valeur, reportez-vous à Clés et OCID requis. |
Chaîne | Oui |
fs.oci.client.auth.fingerprint
|
Empreinte de la paire de clés utilisée. Pour obtenir la valeur, reportez-vous à Clés et OCID requis. |
Chaîne |
Oui, sauf si vous fournissez un authentificateur personnalisé. |
fs.oci.client.auth.pemfilepath
|
Nom de fichier et chemin complet de la clé privée utilisée pour l'authentification. Le fichier doit se trouver sur le système de fichiers local. | Chaîne | Oui, sauf si vous fournissez un authentificateur personnalisé. |
fs.oci.client.auth.passphrase
|
Phrase de passe utilisée pour la clé, si elle est cryptée. | Chaîne | Uniquement si votre clé est cryptée. |
fs.oci.client.regionCodeOrId
|
Code ou identificateur de région utilisé pour établir le nom d'adresse Object Storage. | Chaîne | Non |
Vous pouvez indiquer que la valeur d'une propriété s'applique à un bucket spécifique en ajoutant
.<bucket_name>.<namespace_name> au nom de la propriété.Définition de l'adresse de région
Vous pouvez utiliser plusieurs méthodes afin de définir l'adresse de région pour le connecteur HDFS :
- Spécification de la propriété de nom d'hôte dans
core-site.xml - Spécification de la propriété de code de région ou d'identificateur de région dans
core-site.xml - Autorisation de récupération de l'adresse via le service de métadonnées d'instance par le client ObjectStorage
Configuration de propriétés avec core-site.xml
Cet exemple montre comment les propriétés peuvent être configurées dans un fichier core-site.xml (les OCID sont abrégés dans un souci de concision) :
<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>
Utilisation de principaux d'instance pour l'authentification
Oracle fournit des principaux d'instance afin que vous n'ayez plus à configurer des informations d'identification utilisateur ou à fournir des fichiers PEM sur les services exécutés sur des instances. Chacune de ces instances possède sa propre identité et s'authentifie à l'aide de certificats ajoutés à l'instance par les principaux d'instance.
Pour utiliser l'authentification via un principal d'instance avec le connecteur HDFS, indiquez simplement la propriété fs.oci.client.custom.authenticator et définissez la valeur sur com.oracle.bmc.hdfs.auth.InstancePrincipalsCustomAuthenticator.
Etant donné que l'utilisation de principaux d'instance fournit au connecteur un authentificateur personnalisé, il n'est plus nécessaire de configurer les propriétés suivantes :
-
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
L'exemple de code suivant illustre l'utilisation de principaux d'instance pour l'authentification auprès du connecteur 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>Pour plus d'informations sur les principaux d'instance, reportez-vous à Annonce des principaux d'instance pour Identity and Access Management.
Utilisation de principaux de ressource pour l'authentification
A l'instar des principaux d'instance, Oracle fournit desprincipaux de ressources pour authentifier les ressources qui ne sont pas une instance (comme un bloc-notes jupyter). Chaque ressource possède sa propre identité et est authentifiée à l'aide des certificats qui lui sont ajoutés.
Pour utiliser l'authentification via un principal de ressource avec le connecteur HDFS, indiquez simplement la propriété fs.oci.client.custom.authenticator et définissez la valeur sur com.oracle.bmc.hdfs.auth.ResourcePrincipalsCustomAuthenticator.
Etant donné que l'utilisation de principaux de ressource fournit au connecteur un authentificateur personnalisé, il n'est pas nécessaire de configurer les propriétés suivantes :
-
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
L'exemple de code suivant illustre l'utilisation de principaux de ressource pour l'authentification auprès du connecteur 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>Pour plus d'informations sur les principaux d'instance, reportez-vous à Utilisation de principaux de ressource dans le service Data Science.
Utilisation de l'authentification Kerberos
Oracle prend en charge l'authentification Kerberos pour la connexion à Object Storage à l'aide du connecteur HDFS.
- Dans
core-site.xml, définissez la propriétéfs.oci.client.custom.authenticatorsurcom.oracle.bmc.hdfs.auth.spnego.UPSTAuthenticationCustomAuthenticator. - Dans
core-site.xml, définissez les propriétés suivantes :-
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
-
L'exemple de fichier core-site.xml suivant illustre l'utilisation de Kerberos avec l'authentification par jeton SPNEGO avec le connecteur 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>Pour plus d'informations sur Kerberos, reportez-vous au Tutoriel sur le protocole Kerberos.
Pour plus d'informations sur SPNEGO, reportez-vous à la norme RFC 4178.
Utilisation du connecteur par défaut Jersey HttpUrlConnectorProvider
A partir de la version 3.3.0.7.0.0, HDFS prend en charge l'utilisation par défaut du client Apache pour effectuer des appels de service OCI. En effet, le connecteur HDFS s'appuie sur le kit SDK pour Java afin d'envoyer des demandes au serveur. Le kit SDK pour Java prend en charge l'utilisation du connecteur Jersey ApacheConnectorProvider par défaut au lieu du connecteur Jersey HttpUrlConnectorProvider pour permettre au client Apache HttpClient d'effectuer des appels de service OCI.
Pour revenir à l'ancien client Jersey par défaut, définissez la propriété fs.oci.client.jersey.default.connector.enabled dans le fichier core-site.xml sur true. Par défaut, cette valeur est définie sur false.
Optimisation des performances avec le connecteur Apache pour HDFS
Le connecteur Apache prend en charge deux stratégies de fermeture de connexion : ApacheConnectionClosingStrategy.GracefulClosingStrategy et ApacheConnectionClosingStrategy.ImmediateClosingStrategy.
Avec ApacheConnectionClosingStrategy.GracefulClosingStrategy, les flux de données renvoyés à partir d'une réponse sont lus jusqu'à la fin du flux lors de sa fermeture. Cela peut entraîner un délai supplémentaire lors de la fermeture du flux de données avec une lecture partielle, en fonction de la taille du flux restant. Pour éviter ce délai, envisagez d'utiliser ApacheConnectionClosingStrategy.ImmediateClosingStrategy pour les fichiers volumineux avec des lectures partielles. Avec ApacheConnectionClosingStrategy.ImmediateClosingStrategy, les flux de données ne sont lus qu'à la fin lors de leur fermeture, ce qui peut améliorer les performances. ApacheConnectionClosingStrategy.ImmediateClosingStrategy prend plus de temps lors de l'utilisation de la lecture partielle pour des flux de données de plus petite taille (inférieurs à 1 Mo).
Définition de la stratégie de fermeture de connexion
Définissez la stratégie de fermeture de connexion en définissant la propriété fs.oci.client.apache.connection.closing.strategy dans le fichier core-site.xml :
- Pour utiliser
ApacheConnectionClosingStrategy.GracefulClosingStrategy, définissezfs.oci.client.apache.connection.closing.strategysurgraceful. - Pour utiliser
ApacheConnectionClosingStrategy.ImmediateClosingStrategy, définissezfs.oci.client.apache.connection.closing.strategysurimmediate.
Ces stratégies de fermeture fonctionnent uniquement avec le connecteur Apache pour HDFS et sont ignorées lors de l'utilisation du connecteur par défaut Jersey.
Retour au connecteur par défaut Jersey
Le connecteur par défaut Jersey lit les flux de données jusqu'à la fin, puis les réutilise, ce qui peut améliorer les performances par rapport au connecteur Apache pour HDFS dans certains scénarios. Si ces stratégies de fermeture de connexion Apache ne vous donnent pas des résultats optimaux pour vos cas d'emploi, vous pouvez revenir au connecteur par défaut Jersey 'HttpUrlConnectorProvider'. Vous pouvez revenir à l'ancien client par défaut Jersey en définissant la propriété fs.oci.client.jersey.default.connector.enabled dans le fichier core-site.xml sur true. Par défaut, cette valeur est définie sur false.
Pour plus d'informations, reportez-vous à : https://github.com/oracle/oci-java-sdk/blob/master/ApacheConnector-README.md.
Regroupement de connexions en pool dans HDFS
Vous pouvez définir le nombre maximal de connexions dans le pool de connexions du connecteur HDFS.
Pour ce faire, remplacez la propriété fs.oci.client.apache.max.connection.pool.size dans le fichier core-site.xml par un entier positif qui indique le nombre de connexions à regrouper dans le pool.
Cette propriété est uniquement prise en charge lors de l'utilisation de
ApacheConnector pour HDFS. Sinon, elle est ignorée.Adresses dédiées
fs.oci.client.hostname ou la propriété fs.oci.realmspecific.endpoint.template.enabled de l'indicateur de modèle d'adresse dans core-site.xml. Si vous définissez la propriété de modèle d'adresse, vous devez également définir
fs.oci.client.regionCodeOrId dans core-site.xml.La valeur définie via le nom d'hôte dans
core-site.xml est prioritaire sur la valeur définie à l'aide de la propriété de modèle d'adresse dans 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>
Configuration d'un proxy HTTP
Vous pouvez définir les propriétés facultatives suivantes dans le fichier core-site.xml pour configurer un proxy HTTP :
| Propriété | Description | Type | Requise |
|---|---|---|---|
fs.oci.client.proxy.uri
|
URI de l'adresse de proxy. Par exemple, |
Chaîne | Non |
fs.oci.client.proxy.username
|
Nom utilisateur pour l'authentification auprès du proxy. | Chaîne | Non |
fs.oci.client.proxy.password
|
Mot de passe pour l'authentification auprès du proxy. | Chaîne | Non |
fs.oci.client.multipart.allowed
|
Permet au gestionnaire de téléchargement de prendre en charge les téléchargements multipart vers le serveur. | Valeur booléenne | Non |
fs.oci.client.multipart.minobjectsize.mb
|
Indique la taille minimale des objets en mébioctets afin d'utiliser le gestionnaire de téléchargement. |
Entier | Non |
fs.oci.client.multipart.partsize.mb
|
Indique la taille des parties en mébioctets pour le gestionnaire de téléchargement. | Entier | Non |
La configuration d'un proxy permet d'utiliser
ApacheConnectorProvider lors de l'établissement de connexions à Object Storage. Il met les demandes en mémoire tampon et peut avoir une incidence sur l'utilisation de la mémoire lors du téléchargement d'objets volumineux vers le serveur. Il est recommandé d'activer les téléchargements multipart vers le serveur et d'ajuster les propriétés multipart pour gérer l'utilisation de la mémoire.Téléchargements d'objets volumineux vers le serveur
Les objets volumineux sont téléchargés vers Object Storage via des téléchargements multipart. Le fichier est divisé en petites parties qui sont téléchargées en parallèle, ce qui réduit le temps de téléchargement. Cela permet également au connecteur HDFS de réessayer de télécharger les parties ayant échoué au lieu de faire échouer l'ensemble du téléchargement. Toutefois, les téléchargements peuvent échouer de façon temporaire, auquel cas le connecteur tente d'abandonner les fichiers partiellement téléchargés. Etant donné que ces fichiers s'accumulent (et que vous serez facturé pour le stockage), répertoriez les téléchargements régulièrement, puis après un certain nombre de jours, abandonnez-les manuellement en utilisant le kit SDK pour Java.
Pour plus d'informations sur l'utilisation de l'API Object Storage concernant la gestion des téléchargements multipart, reportez-vous à Utilisation des téléchargements multipart vers le serveur.
Si vous préférez ne pas utiliser les téléchargements multipart vers le serveur, vous pouvez les désactiver en définissant la propriété
fs.oci.client.multipart.allowed sur false.Meilleures pratiques
Les sections suivantes présentent les meilleures pratiques pour l'optimisation des performances et de l'utilisation.
Noms de répertoire
Il n'existe aucun répertoire réel dans Object Storage. Le regroupement de répertoires est une fonction de convention de dénomination, où les objets utilisent des délimiteurs / dans leur nom. Par exemple, un objet nommé a/example.json implique l'existence d'un répertoire nommé a. Toutefois, si cet objet est supprimé, le répertoire a est également supprimé de façon implicite. Pour conserver la sémantique du système de fichiers où le répertoire peut exister sans la présence de fichiers, le connecteur HDFS crée un objet réel dont le nom se termine par / avec un chemin représentant le répertoire (en l'occurrence, un objet nommé a/). Ainsi, la suppression de a/example.json n'a pas d'incidence sur l'existence du répertoire a car l'objet a/ reste présent. Toutefois, il est tout à fait possible de supprimer cet objet a/ sans supprimer les fichiers/répertoires qui se trouvent dedans. Le connecteur HDFS supprime uniquement l'objet de dossier s'il n'existe aucun objet sous ce chemin. L'objet de dossier lui-même représente zéro octet.
Système de fichiers incohérent
La suppression d'un répertoire implique la suppression de tous les objets qui commencent par le préfixe représentant ce répertoire. HDFS vous permet d'interroger le statut de fichier d'un répertoire ou d'un fichier. Le statut de fichier d'un répertoire est implémenté en vérifiant que l'objet de dossier existe pour ce répertoire. Toutefois, il est possible que l'objet de dossier ait été supprimé, mais que certains des objets dotés de ce préfixe existent toujours. Par exemple, s'il s'agit de ces objets :
-
a/b/example.json -
a/b/file.json -
a/b/
HDFS saurait que le répertoire /a/b/ existe et qu'il s'agit d'un répertoire, et l'analyse de ce dernier génèrerait example.json et file.json. Toutefois, si l'objet a/b/ était supprimé, le système de fichiers aurait un état incohérent. Vous pouvez l'interroger pour tous les fichiers du répertoire /a/b/ et trouver les deux entrées. Toutefois, si vous interrogez le statut du répertoire /a/b/ réel, une exception serait générée car le répertoire n'existe pas. Le connecteur HDFS ne tente pas de corriger l'état du système de fichiers.
Création de fichiers
Object Storage prend en charge les objets de plusieurs gigaoctets. La création des fichiers est normalement effectuée par l'écriture dans un fichier temporaire, puis par le téléchargement vers le serveur du contenu du fichier à la fermeture du flux de données. L'espace temporaire doit être suffisant pour permettre la gestion de plusieurs téléchargements. Le répertoire temporaire utilisé est contrôlé par la propriété de configuration hadoop.tmp.dir.
Prise en charge de la lecture/recherche
Lorsque les tampons en mémoire sont activés (fs.oci.io.read.inmemory), la recherche est entièrement prise en charge car l'intégralité du fichier est mise en mémoire tampon dans un tableau d'octets. Lorsque le tampon en mémoire n'est pas activé (probablement parce que les objets sont volumineux), la recherche est implémentée en fermant le flux de données et en effectuant une nouvelle demande de plage commençant au niveau du décalage indiqué.
Liste des répertoires
La création de la liste des répertoires correspond à une opération de création de liste de buckets avec un préfixe et un délimiteur spécifiés. Pour créer une instance FileStatus HDFS pour chaque clé, le connecteur effectue une demande HEAD supplémentaire afin d'obtenir ObjectMetadata pour chaque clé. Cette étape est requise jusqu'à ce qu'Object Storage prenne en charge des données d'opération de liste plus riches.
Format d'URI pour les systèmes de fichiers et les fichiers
Les fichiers et les systèmes de fichiers HDFS sont référencés via des URI. Le modèle précise le type de système de fichiers, et la partie restante de l'URI est libre pour que l'implémentation du système de fichiers l'interprète comme elle le souhaite.
Object Storage étant une banque d'objets, sa capacité à nommer les objets comme s'ils étaient des fichiers dans un système à fichiers est utilisée pour imiter un système à fichiers réel.
Racine
La racine du système De fichiers Object Storage est signalée par un chemin dont le composant d'autorité inclut le Nom de bucket et le Nom d'espace de noms, comme indiqué ci-dessous :
Dans les exemples, "
MyBucket" et "MyNamespace" sont des espaces réservés et doivent être remplacés par les valeurs appropriées.
oci://MyBucket@MyNamespace/
Il s'agit toujours de la racine du système de fichiers. La raison pour laquelle l'autorité est utilisée pour le bucket et l'espace de noms est que HDFS autorise uniquement la partie dédiée à l'autorité à déterminer l'emplacement du système de fichiers. La partie du chemin indique uniquement le chemin vers la ressource (par exemple, "oci/MyNamespace/MyBucket" ne fonctionne pas). Le caractère @ n'est pas un caractère valide pour les buckets ou les espaces de noms, et doit permettre à l'autorité d'être analysée correctement.
Sous-répertoires
Les sous-répertoires n'existent pas réellement, mais vous pouvez les imiter en créant des objets avec des caractères /. Par exemple, deux fichiers nommés a/b/c/example.json et a/b/d/path.json apparaîtraient comme s'ils se trouvaient dans un même répertoire commun a/b. Pour ce faire, vous devez utiliser l'interrogation basée sur un préfixe et sur un délimiteur Object Storage. Dans l'exemple donné, le référencement d'un sous-répertoire en tant qu'URI correspondrait à ce qui suit :
oci://MyBucket@MyNamespace/a/b/
Objets/fichiers
Un objet nommé a/b/c/example.json est référencé comme suit :
oci://MyBucket@MyNamespace/a/b/c/example.json
Journalisation
La journalisation dans le connecteur est effectuée via SLF4J. SLF4J est une abstraction de journalisation qui permet d'utiliser une bibliothèque de journalisation fournie par l'utilisateur (par exemple, log4j). Pour plus d'informations, reportez-vous au manuel de SLF4J.
L'exemple suivant montre comment activer la journalisation de base sur une sortie standard.
- Téléchargez le fichier JAR de liaison simple SLF4J : liaison simple SLF4J.
- Ajoutez le fichier JAR à votre variable d'environnement CLASSPATH.
- Ajoutez l'argument de machine virtuelle suivant pour activer la journalisation de niveau débogage (par défaut, le niveau information est utilisé) :
-Dorg.slf4j.simpleLogger.defaultLogLevel=debug.
Vous pouvez configurer des options de journalisation plus avancées à l'aide de la liaison log4j.
Utiliser la structure de surveillance
Le connecteur HDFS pour Object Storage inclut une structure de surveillance qui fournit des mesures sur les opérations effectuées à l'aide du connecteur. La structure de surveillance fournit une interface qui peut être implémentée pour utiliser/écouter les mesures générées par le connecteur. Vous pouvez fournir une implémentation personnalisée de cette interface ou utiliser l'implémentation de télémétrie publique OCI incluse dans cette structure.
Mise en route
Pour commencer à utiliser la structure de surveillance du connecteur HDFS, vous devez définir les propriétés suivantes. Une fois ces propriétés définies pour OCIMonitoring, vous pouvez utiliser la vue Explorateur de mesures dans la console OCI pour observer les mesures émises à partir du connecteur HDFS.
fs.oci.mon.consumer.plugins
fs.oci.mon.consumer.plugins prend une liste de noms de classe qualifiés complets des implémentations de l'interface de surveillance, séparés par des virgules. com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin doit être utilisé dans la liste si vous voulez que les mesures soient émises vers la télémétrie publique 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
fs.oci.mon.grouping.cluster.id indique l'identificateur du cluster HDFS ou de tout autre ID dans lequel regrouper les mesures. Cette propriété est obligatoire. Elle est également utilisée par OCIMonitorPlugin pour baliser les mesures. Cette propriété est visible en tant que dimension dans l'API et l'interface utilisateur de télémétrie publique OCI.<property>
<name>fs.oci.mon.grouping.cluster.id</name>
<value>hdfs-sample-cluster-id</value>
</property>
Propriétés com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
Si la propriété com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin est activée, les propriétés suivantes sont applicables :
fs.oci.mon.telemetry.ingestion.endpoint
fs.oci.mon.telemetry.ingestion.endpoint permet de configurer l'adresse d'inclusion de télémétrie de la surveillance OCI. Pour plus d'informations, voir la liste des points disponibles.
<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 permet de configurer le compartiment OCI auquel les mesures seront attachées. Il s'agit généralement du compartiment auquel appartiennent les buckets.<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 détermine si le nom du bucket doit être attaché en tant que dimension aux mesures émises.<property>
<name>fs.oci.mon.bucket.level.enabled</name>
<value>true</value>
</property>
fs.oci.mon.ns.name
fs.oci.mon.ns.name contrôle l'espace de noms utilisé pour les mesures émises par le connecteur HDFS. Un exemple d'espace de noms peut être "hdfsconnector". Cela résidera à côté d'autres espaces de noms prédéfinis tels que oci_objectstorage dans la télémétrie publique.<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 définit le nom du groupe de ressources utilisé pour contenir les mesures. Il peut s'agir de n'importe quel nom logique de regroupement de ressources qui sera surveillé ensemble. Ce nom de groupe de ressources apparaîtra sous l'espace de noms choisi précédemment dans la télémétrie publique OCI.<property>
<name>fs.oci.mon.rg.name</name>
<value>name.of.resource.group.on.oci.telemetry</value>
</property>
Création de votre propre consommateur pour les mesures
com.oracle.bmc.hdfs.monitoring.OCIMonitorConsumerPlugin, vous devez définir deux méthodes :-
accept -
shutdown
L'extension des classes doit avoir un constructeur avec la même signature que celle de la classe 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();
}
La classe OCIMetric peut être implémentée de trois manières :
OCIMetric simple avec les champs suivants :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 qui étend OCIMetric et contient des champs supplémentaires pour le débit et les octets transférés. Cela s'applique aux opérations READ et 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;
}
OCIMetricWithFBLatency qui étend OCIMetricWithThroughput, avec un temps supplémentaire pour le premier champ de latence d'octet. S'applique uniquement aux opérations READ :public class OCIMetricWithFBLatency extends OCIMetricWithThroughput {
/**
* The time to first byte when a read operation was performed in milliseconds.
*/
private final double ttfb;
}
Exemple de travail 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);
}
}Résolution des problèmes
Cette section contient des informations de résolution pour le connecteur HDFS.
Résolution des erreurs de service
Toute opération provoquant une erreur de service entraîne la génération d'une exception de type com.oracle.bmc.model.BmcException par le connecteur HDFS. Pour plus d'informations sur les erreurs de service courantes renvoyées par OCI, reportez-vous à Erreurs d'API.
Erreurs de taille de clé de cryptage Java
Le connecteur HDFS peut uniquement gérer les clés d'une longueur inférieure ou égale à 128 bits. Les utilisateurs obtiennent les erreurs "Exception de clé non valide" et "Taille de clé interdite" lorsqu'ils utilisent des clés plus longues, comme AES256. Appliquez l'une des solutions de contournement suivantes pour résoudre ce problème :
- Utilisez une clé de 128 bits, comme AES128.
-
Installez Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction à partir de l'adresse : http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html.
Contributions
Vous disposez d'une correction de bug ou d'une nouvelle fonctionnalité que vous souhaitez partager ? Le kit SDK est open source et accepte les demandes d'extraction sur GitHub.
Notifications
Pour être averti lorsqu'une nouvelle version du connecteur HDFS est disponible, abonnez-vous au flux Atom .
Questions ou commentaires
Méthodes d'interaction :
- Problèmes dans GitHub : pour enregistrer des bugs et effectuer des demandes de fonctionnalité
- Stack Overflow : utilisez les balises oracle-cloud-infrastructure et oci-hdfs-connector dans votre publication.
- Section Outils de développement des forums Oracle Cloud
- My Oracle Support