Conector HDFS para almacenamiento de objetos
El Conector del Sistema de Archivos Distribuidos de Hadoop (HDFS) permite a su aplicación Apache Hadoop leer y escribir datos en el servicio Oracle Cloud Infrastructure Object Storage.
Este SDK y el ejemplo cuentan con la licencia universal permisiva 1.0 y la licencia de Apache 2.0; se otorga una licencia de contenido de terceros independiente como se describe en el código.
- Servicios soportados: Object Storage
- Descargar: GitHub o Maven
- Documentación de API: referencia de API del conector HDFS
Requisitos
Para utilizar el conector HDFS, debe tener:
- Una cuenta de Oracle Cloud Infrastructure.
- Un usuario creado en esa cuenta, en un grupo con una política que otorgue los permisos deseados para cualquier cubo que desee utilizar. Puede ser un usuario para sí mismo u otra persona/sistema que necesite llamar a la API. Para obtener un ejemplo de cómo configurar un nuevo usuario, grupo, compartimento y política, consulte Adición de usuarios. Para obtener una política básica de Object Storage, consulte Permitir a los administradores de Object Storage gestionar cubos y objetos.
- Java 8
- Un valor TTL de 60. Para obtener más información, consulte Configuración de TTL de JVM para consultas de nombre de DNS.
Credenciales y contraseñas
Si utiliza un archivo PEM cifrado para las credenciales, la contraseña se leerá desde la configuración mediante el método de configuración de Hadoop getPassword
. La opción getPassword
busca una contraseña en un proveedor de seguridad registrado. Si el proveedor de seguridad no contiene la clave solicitada, se reserva para leer la contraseña en texto sin formato directamente desde el archivo de configuración.
Configuración de TTL de JVM para consultas de nombres de DNS
Java Virtual Machine (JVM) almacena en caché las respuestas de DNS de las consultas durante una cantidad de tiempo definida, denominada tiempo de actividad (TTL). Esto garantiza un tiempo de respuesta más rápido en el código que requiere una resolución de nombres frecuente.
JVM utiliza la propiedad networkaddress.cache.ttl para especificar la política de almacenamiento en caché para las consultas de nombres de DNS. El valor es un entero que representa el número de segundos que se va a almacenar en caché la consulta correcta. El valor por defecto de muchas JVM, -1
, indica que la consulta se deben almacenar en caché para siempre.
Como los recursos de Oracle Cloud Infrastructure utilizan nombres de DNS que pueden cambiar, se recomienda cambiar el valor TTL a 60 segundos. Esto garantiza que la nueva dirección IP para el recurso se devuelva en la siguiente consulta DNS. Puede cambiar este valor de forma global o específica para la aplicación:
-
Para definir TTL de forma global para todas las aplicaciones mediante JVM, agregue lo siguiente en el archivo
$JAVA_HOME/jre/lib/security/java.security
:networkaddress.cache.ttl=60
-
Para definir TTL solo para la aplicación, defina lo siguiente en el código de inicialización de la aplicación:
java.security.Security.setProperty("networkaddress.cache.ttl" , "60");
Instalación
Copie los archivos jar agrupados de lib y de third-party/lib en cada nodo del cluster de Hadoop para que se incluyan en la CLASSPATH de Hadoop.
SDK para Java y artefactos de Maven
La creación de un conector HDFS se basa En artefactos de Maven proporcionados por el SDK para Java de Oracle Cloud Infrastructure. Para obtener los artefactos, debe descargar el SDK para Java y crearlo localmente. A continuación, puede crear el conector HDFS.
La versión del archivo del SDK para Java que descargue de la página de versiones de Oracle debe coincidir con la versión del conector HDFS, que puede encontrar en el archivo
hdfs-connector/pom.xml
del bloque de etiquetas de dependencia que tiene el atributo groupId
.Conector HDFS y artefactos de Maven
El conector HDFS está disponible en Maven Central y JCenter.
Para utilizar el conector HDFS en el proyecto, importe la siguiente dependencia del proyecto. Por ejemplo:
<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>
Propiedades
Puede definir las siguientes propiedades del conector HDFS en el archivo core-site.xml
. En la página BmcProperties se muestran las propiedades adicionales que puede configurar para una conexión a Object Storage.
Propiedad | Descripción | Tipo | Necesaria |
---|---|---|---|
fs.oci.client.hostname
|
URL del punto final de host. Por ejemplo, |
Cadena | Sí |
fs.oci.client.auth.tenantId
|
OCID de su arrendamiento. Para obtener el valor, consulte Claves y OCID necesarios. |
Cadena | Sí |
fs.oci.client.auth.userId
|
OCID del usuario que llama a la API. Para obtener el valor, consulte Claves y OCID necesarios. |
Cadena | Sí |
fs.oci.client.auth.fingerprint
|
Huella del par de claves que se está utilizando. Para obtener el valor, consulte Claves y OCID necesarios. |
Cadena |
Sí, a menos que proporcione un autenticador personalizado. |
fs.oci.client.auth.pemfilepath
|
Ruta de acceso completa y nombre de archivo de la clave privada utilizada para la autenticación. El archivo debe estar en el sistema de archivos local. | Cadena | Sí, a menos que proporcione un autenticador personalizado. |
fs.oci.client.auth.passphrase
|
Contraseña utilizada para la clave, si está cifrada. | Cadena | Solo si la clave está cifrada. |
fs.oci.client.regionCodeOrId
|
Código de región o identificador de región utilizado para establecer el nombre de punto final de Object Storage. | Cadena | No |
Puede especificar que un valor de propiedad se aplique a un cubo específico agregando
.<bucket_name>.<namespace_name>
al nombre de propiedad.Definición del punto final de región
Hay varios métodos que puede utilizar para definir el punto final de región para el conector HDFS:
- Especificando la propiedad hostname en
core-site.xml
- Especificando el código de región o la propiedad de identificador de región en
core-site.xml
- Permitiendo al cliente ObjectStorage seleccionar el punto final a través del servicio de metadatos de instancia
Configuración de propiedades con core-site.xml
En este ejemplo se muestra cómo se pueden configurar las propiedades en un archivo core-site.xml
(los OCID se acortan para abreviar):
<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 de principales de instancia para autenticación
Oracle proporciona principales de instancia para que ya no sea necesario configurar credenciales de usuario o proporcionar archivos PEM en servicios que se ejecutan en instancias. Cada una de estas instancias tiene su propia identidad y se autentica mediante certificados agregados a la instancia por principales de instancia.
Para utilizar la autenticación de principales de instancia con el conector HDFS, solo tiene que proporcionar la propiedad fs.oci.client.custom.authenticator
y definir el valor en com.oracle.bmc.hdfs.auth.InstancePrincipalsCustomAuthenticator
.
Puesto que el uso de principales de instancia proporciona al conector un autenticador personalizado, ya no es necesario configurar las siguientes propiedades:
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
El siguiente código de ejemplo ilustra el uso de principales de instancia para la autenticación con el conector 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>
Para obtener más información sobre principales de instancia, consulte la sección sobre el anuncio de principales de instancia para Identity and Access Management.
Uso de principales de recurso para la autenticación
Al igual que los principales del recurso, Oracle proporciona principales de recurso para autenticar los recursos que no son instancias (como un bloc de nota de Jupyter). Cada recurso tiene su propia identidad y se autentica mediante los certificados que se le agregan.
Para utilizar la autenticación de principales de recurso con el conector HDFS, solo tiene que proporcionar la propiedad fs.oci.client.custom.authenticator
y definir el valor en com.oracle.bmc.hdfs.auth.ResourcePrincipalsCustomAuthenticator
.
Dado que el uso de entidades de recurso proporciona al conector un autenticador personalizado, ya no es necesario configurar las siguientes propiedades:
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
El siguiente código de ejemplo ilustra el uso de principales de recurso para la autenticación con el conector 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>
Para obtener más información sobre los principales de recurso, consulte la sección sobre el uso de principales de recurso en el servicio Data Science.
Uso de la Autenticación de Kerberos
Oracle admite la autenticación de Kerberos para conectarse con Object Storage mediante el conector HDFS.
- En
core-site.xml
, defina la propiedadfs.oci.client.custom.authenticator
encom.oracle.bmc.hdfs.auth.spnego.UPSTAuthenticationCustomAuthenticator
. - En
core-site.xml
, defina las siguientes propiedades: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
El siguiente archivo core-site.xml
de ejemplo ilustra el uso de Kerberos con autenticación de token SPNEGO con el conector 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>
Para obtener más información sobre Kerberos, consulte el Tutorial del protocolo Kerberos.
Para obtener más información sobre SPNEGO, consulte RFC 4178.
Uso de HttpUrlConnectorProvider por defecto de Jersey
A partir de la versión 3.3.0.7.0.0, HDFS soporta el uso del cliente Apache por defecto para realizar llamadas de servicio de OCI. Esto se debe a que el conector HDFS depende del SDK para Java para enviar solicitudes al servidor. El SDK para Java soporta el uso de ApacheConnectorProvider
de Jersey por defecto en lugar de HttpUrlConnectorProvider
de Jersey para permitir que HttpClient de Apache realice llamadas de servicio de OCI.
Para volver al cliente antiguo por defecto de Jersey, defina la propiedad fs.oci.client.jersey.default.connector.enabled
del archivo core-site.xml
en true
. Por defecto, este valor está definido en false
.
Optimización del rendimiento con el conector Apache para HDFS
El conector Apache soporta dos estrategias de cierre de conexión: ApacheConnectionClosingStrategy.GracefulClosingStrategy
y ApacheConnectionClosingStrategy.ImmediateClosingStrategy
.
Al utilizar ApacheConnectionClosingStrategy.GracefulClosingStrategy
, los flujos devueltos de una respuesta se leen hasta el final del flujo cuando se cierra el flujo. Esto puede introducir tiempo adicional cuando se cierra el flujo con una lectura parcial, dependiendo del tamaño del flujo restante. Para evitar este retraso, considere utilizar ApacheConnectionClosingStrategy.ImmediateClosingStrategy
para archivos grandes con lecturas parciales. Con ApacheConnectionClosingStrategy.ImmediateClosingStrategy
, los flujos no se leen hasta el final cuando se cierra el flujo, lo que puede mejorar el rendimiento. Tenga en cuenta que ApacheConnectionClosingStrategy.ImmediateClosingStrategy
tarda más tiempo cuando se utiliza la lectura parcial para un tamaño de flujo más pequeño (flujos menores que 1 MB).
Definición de la Estrategia de Cierre de Conexión
Defina la estrategia de cierre de conexión definiendo la propiedad fs.oci.client.apache.connection.closing.strategy
del archivo core-site.xml
:
- Para utilizar
ApacheConnectionClosingStrategy.GracefulClosingStrategy
, definafs.oci.client.apache.connection.closing.strategy
engraceful
. - Para utilizar
ApacheConnectionClosingStrategy.ImmediateClosingStrategy
, definafs.oci.client.apache.connection.closing.strategy
enimmediate
.
Estas estrategias de cierre solo funcionan con el conector Apache para HDFS y se ignoran cuando se utiliza el conector por defecto de Jersey.
Cambio al conector por defecto de Jersey
El conector por defecto de Jersey lee los flujos hasta el final y, a continuación, reutiliza el flujo, lo que puede generar un mejor rendimiento que el conector Apache para HDFS en algunos escenarios. Si estas estrategias de cierre de conexión de Apache no proporcionan resultados óptimos para los casos de uso, puede volver al valor por defecto de Jersey 'HttpUrlConnectorProvider'. Puede volver al cliente por defecto de Jersey antiguo definiendo la propiedad fs.oci.client.jersey.default.connector.enabled
del archivo core-site.xml
en true
. Por defecto, este valor está definido en false
.
Para obtener más información, consulte: https://github.com/oracle/oci-java-sdk/blob/master/ApacheConnector-README.md.
Pool de conexiones en HDFS
Puede definir el número máximo de conexiones en el pool de conexiones del conector HDFS.
Para ello, cambie la propiedad fs.oci.client.apache.max.connection.pool.size
del archivo core-site.xml
a un entero positivo que especifique cuántas conexiones hay al pool.
Esta propiedad solo está soportada cuando se utiliza
ApacheConnector
para HDFS; de lo contrario, se ignora.Puntos finales dedicados
fs.oci.client.hostname
o el indicador de plantilla de punto final fs.oci.realmspecific.endpoint.template.enabled
en core-site.xml
. Si define la propiedad de plantilla de punto final, también debe definir
fs.oci.client.regionCodeOrId
en core-site.xml
.El valor definido mediante el nombre de host en
core-site.xml
tiene prioridad sobre el juego de valores mediante la propiedad de plantilla de punto final en 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>
Configuración de un proxy HTTP
Puede definir las siguientes propiedades opcionales en el archivo core-site.xml
para configurar un proxy HTTP:
Propiedad | Descripción | Tipo | Necesaria |
---|---|---|---|
fs.oci.client.proxy.uri
|
URI del punto final del proxy. Por ejemplo, |
Cadena | No |
fs.oci.client.proxy.username
|
Nombre de usuario para autenticar con el proxy. | Cadena | No |
fs.oci.client.proxy.password
|
Contraseña para autenticar con el proxy. | Cadena | No |
fs.oci.client.multipart.allowed
|
Permite al gestor de carga soportar cargas de varias partes | Booleana | No |
fs.oci.client.multipart.minobjectsize.mb
|
Especifica el tamaño mínimo de objeto en mebibytes para utilizar el gestor de carga. |
Entero | No |
fs.oci.client.multipart.partsize.mb
|
Especifica el tamaño de la parte en mebibytes para el gestor de carga. | Entero | No |
La configuración de un proxy permite el uso de
ApacheConnectorProvider
al realizar conexiones a Object Storage. Almacena en buffer las solicitudes en la memoria y puede afectar al uso de la memoria al cargar objetos grandes. Se recomienda activar las cargas de varias partes y ajustar las propiedades de varias partes para gestionar el consumo de memoria.Cargas de objetos grandes
Los objetos grandes se cargan en Object Storage mediante cargas de varias partes. El archivo se divide en partes más pequeñas que se cargan en paralelo, lo que reduce los tiempos de carga. Esto también permite que el conector HDFS vuelva a intentar las cargas de las partes con fallos en lugar de que falle la carga completa. Sin embargo, las cargas pueden fallar temporalmente y el conector intentará abortar parcialmente los archivos cargados. Dado que estos archivos se acumulan (y se le cobrará el almacenamiento), enumere las cargas periódicamente y, después de un determinado número de días, abórtelas manualmente con el SDK para Java.
En Uso de cargas de varias partesse puede encontrar información sobre el uso de la API de Object Storage para gestionar las cargas de varias partes.
Si prefiere no utilizar cargas de varias partes, puede desactivarlas definiendo la propiedad
fs.oci.client.multipart.allowed
en false
.Mejores prácticas
Las siguientes secciones contienen las mejores prácticas para optimizar el uso y el rendimiento.
Nombres de directorio
No hay directorios reales en Object Storage. El agrupamiento de directorios es una función de la regla de nomenclatura, en la que los objetos utilizan los delimitadores /
en sus nombres. Por ejemplo, un objeto denominado a/example.json
implica que hay un directorio denominado a
. Sin embargo, si se suprime ese objeto, el directorio a
también se suprime implícitamente. Para conservar la semántica del sistema de archivos donde puede existir el directorio sin la presencia de ningún archivo, el conector HDFS crea un objeto real cuyo nombre termina en /
con una ruta de acceso que representa el directorio (por ejemplo, crea un objeto denominado a/
). Ahora, la supresión de a/example.json
no afecta a la existencia del directorio a
, ya que el objeto a/
mantiene su presencia. Sin embargo, es totalmente posible que alguien pueda suprimir ese objeto a/
sin suprimir los archivos/directorios que están debajo. El conector HDFS sólo suprimirá el objeto de carpeta si no hay objetos por debajo de esa ruta de acceso. El objeto de carpeta en sí tiene cero bytes.
Sistema de archivos incoherente
La supresión de un directorio implica la supresión de todos los objetos que empiezan por el prefijo que representa ese directorio. El HDFS permite consultar el estado de un archivo o directorio. El estado de archivo de un directorio se implanta mediante la verificación de que existe el objeto de carpeta para ese directorio. Sin embargo, es posible que se haya suprimido el objeto de carpeta, pero todavía existan algunos de los objetos con ese prefijo. Por ejemplo, en una situación con estos objetos:
a/b/example.json
a/b/file.json
a/b/
HDFS sabría que el directorio /a/b/
existe y es un directorio y que la exploración daría como resultado example.json
y file.json
. Sin embargo, si se suprimió el objeto a/b/
, el sistema de archivos parecería estar en un estado incoherente. Puede consultarlo para todos los archivos del directorio /a/b/
y encontrar las dos entradas, pero si consulta el estado del directorio real /a/b/
, se producirá una excepción porque el directorio no existe. El conector HDFS no intenta corregir el estado del sistema de archivos.
Creación de archivos
El almacenamiento de objetos soporta objetos que pueden tener muchos GB de tamaño. Normalmente, la creación de archivos se realizará escribiendo en un archivo temporal y, a continuación, cargando el contenido del archivo cuando se cierre el flujo. El espacio temporal debe ser lo suficientemente grande como para manejar varias cargas. El directorio temporal utilizado se controla mediante la propiedad de configuración hadoop.tmp.dir
.
Soporte de lectura/búsqueda
Cuando se activan los buffers en memoria (fs.oci.io.read.inmemory
), la búsqueda se soporta completamente porque todo el archivo se almacena en buffer en una matriz de byte. Cuando el buffer en memoria no está activado (probablemente porque los tamaños de los objetos son grandes), la búsqueda se implanta cerrando el flujo y realizando una nueva solicitud de rango empezando por el desplazamiento especificado.
Listado de directorios
El listado de un directorio es básicamente una operación de enumeración de cubos con un prefijo y un delimitador especificados. Para crear una instancia de FileStatus de HDFS para cada clave, el conector realiza una solicitud HEAD adicional para obtener ObjectMetadata de cada clave individual. Esto será necesario hasta la compatibilidad de Object Storage con datos de operación de lista más completos.
Formato de URI para sistemas de archivos y archivos
Se hace referencia a los sistemas de archivos y archivos de HDFS a través de los URI. El esquema especifica el tipo de sistema de archivos y la parte restante del URI está realmente libre para que la implantación del sistema de archivos se interprete como lo desee.
Dado que Object Storage es un almacén de objeto, su capacidad para nombrar objetos como si fueran archivos en un sistema en archivos se utiliza para imitar un sistema en archivos real.
Raíz
La raíz del sistema de archivos de Object Storage se Indica mediante una ruta de Acceso en la que el componente de autoridad incluye el nombre de cubo y el nombre de espacio de nombres, como se muestra:
En los ejemplos, "
MyBucket
" y "MyNamespace
" son marcadores de posición y se deben sustituir por los valores adecuados.
oci://MyBucket@MyNamespace/
Esta es siempre la raíz del sistema de archivos. El motivo para utilizar la autoridad para el cubo y el espacio de nombres es que HDFS solo permite que la parte de la autoridad determine dónde está el sistema de archivos; la parte de la ruta de acceso indica solo la ruta de acceso al recurso (por ejemplo, "oci//MyNamespace/MyBucket" no funcionará). Tenga en cuenta que el carácter @
no es un carácter válido para cubos o espacios de nombres y debe permitir que la autoridad se analice correctamente.
Subdirectorios
Los subdirectorios no existen realmente, pero se pueden imitar creando objetos con caracteres /
. Por ejemplo, dos archivos denominados a/b/c/example.json
y a/b/d/path.json
aparecerían como si estuvieran en un directorio común a/b
. Esto se lograría mediante el uso de la consulta basada en el delimitador y el prefijo de Object Storage. En el ejemplo proporcionado, la referencia a un subdirectorio como URI sería:
oci://MyBucket@MyNamespace/a/b/
Objetos/Archivos
A un objeto denominado a/b/c/example.json
se hace referencia como:
oci://MyBucket@MyNamespace/a/b/c/example.json
Registro
El registro en el conector se realiza mediante SLF4J. SLF4J es una abstracción del registro que permite el uso de una biblioteca de registro proporcionado por el usuario (p. ej., log4j). Para obtener más información, consulte el manual de SLF4J.
En los siguientes ejemplos se muestra cómo activar el registro básico para la salida estándar.
- Descargue el archivo jar de enlace simple de SLF4J: SLF4J Simple Binding
- Agregue el archivo jar a la classpath
- Agregue el siguiente argumento de VM para activar el registro de nivel de depuración (por defecto, se utiliza el nivel de información):
-Dorg.slf4j.simpleLogger.defaultLogLevel=debug
Puede configurar opciones de registro más avanzadas mediante el enlace de log4j.
Uso del Marco de Supervisión
El conector HDFS para Object Storage incluye un marco de supervisión que proporciona métricas sobre las operaciones realizadas mediante el conector. El marco de supervisión proporciona una interfaz que se puede implantar para consumir/escuchar las métricas generadas por el conector. Puede proporcionar una implantación personalizada de esta interfaz o puede utilizar la implantación de telemetría pública de OCI incluida en este marco.
Introducción
Para empezar a utilizar la estructura de supervisión del conector HDFS, deberá definir las siguientes propiedades. Una vez definidas estas propiedades para OCIMonitoring
, puede utilizar la vista Metric Explorer en la consola de OCI para observar las métricas emitidas desde el conector HDFS.
fs.oci.mon.consumer.plugins
fs.oci.mon.consumer.plugins
toma una lista separada por comas de nombres de clase totalmente cualificados de implantaciones de la interfaz de supervisión. com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
se debe utilizar en la lista si desea que las métricas se emitan a la telemetría pública de 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
especifica el identificador del cluster de HDFS o cualquier otro identificador en el que desee agrupar las métricas. Esta es una propiedad obligatoria, que también utiliza OCIMonitorPlugin
para etiquetar métricas. Esta propiedad está visible como una dimensión en la API y la interfaz de usuario de telemetría pública de OCI.<property>
<name>fs.oci.mon.grouping.cluster.id</name>
<value>hdfs-sample-cluster-id</value>
</property>
Propiedades com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
Si la propiedad com.oracle.bmc.hdfs.monitoring.OCIMonitorPlugin
está activada, se aplican las siguientes propiedades:
fs.oci.mon.telemetry.ingestion.endpoint
fs.oci.mon.telemetry.ingestion.endpoint
ayuda a configurar el punto final de ingesta de telemetría de OCI Monitoring. Para obtener más información, consulte la lista de puntos 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
se utiliza para configurar el compartimento de OCI al que se asociarán las métricas. Normalmente será el compartimento al que pertenecen los cubos.<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
determina si se debe asociar el nombre de cubo como dimensión a las métricas emitidas.<property>
<name>fs.oci.mon.bucket.level.enabled</name>
<value>true</value>
</property>
fs.oci.mon.ns.name
fs.oci.mon.ns.name
controla el espacio de nombres utilizado para las métricas emitidas por el conector HDFS. Un espacio de nombres de ejemplo podría ser "hdfsconnector". Esto residirá junto con otros espacios de nombres predefinidos como oci_objectstorage
en la telemetría pública.<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
define el nombre del grupo de recursos utilizado para contener las métricas. Puede ser cualquier nombre lógico para agrupar recursos que se supervisarán juntos. Este nombre de grupo de recursos se mostrará en el espacio de nombres que se eligió anteriormente en la telemetría pública de OCI.<property>
<name>fs.oci.mon.rg.name</name>
<value>name.of.resource.group.on.oci.telemetry</value>
</property>
Creación de su propio consumidor para métricas
com.oracle.bmc.hdfs.monitoring.OCIMonitorConsumerPlugin
, tendrá que definir dos métodos:accept
shutdown
La ampliación de clases debe tener un constructor con la misma firma que la de la clase 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 clase OCIMetric
se puede implantar de tres formas:
OCIMetric
simple con los siguientes campos: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
que amplía OCIMetric
y tiene campos adicionales para el rendimiento y los bytes transferidos. Esto se aplica a las operaciones READ y 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
que amplía OCIMetricWithThroughput
, con un tiempo adicional al campo de latencia del primer byte. Esto solo se aplica a las operaciones READ:public class OCIMetricWithFBLatency extends OCIMetricWithThroughput {
/**
* The time to first byte when a read operation was performed in milliseconds.
*/
private final double ttfb;
}
Trabajo de Hadoop de ejemplo
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);
}
}
Solución de problemas
Esta sección contiene información de solución de problemas del conector HDFS.
Solución de errores de servicio
Cualquier operación que da como resultado un error de servicio provocará una excepción de tipo com.oracle.bmc.model.BmcException que debe devolver el conector HDFS. Para obtener más información sobre los errores de servicio comunes devueltos por OCI, consulte Errores de API.
Errores de tamaño de clave de cifrado de Java
El conector HDFS solo puede manejar claves con una longitud de 128 bits o inferior. Los usuarios obtienen los errores "Excepción de clave no válida" y "Tamaño de clave no válido" cuando utilizan claves más largas, como AES256. Utilice una de las siguientes soluciones alternativas para solucionar este problema:
- Utilice una clave de 128 bits, como AES128.
-
Instale la jurisdicción de solidez ilimitada de Java Cryptography Extension (JCE) desde la siguiente ubicación: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
Aportaciones
¿Ha obtenido una corrección para un bug o una nueva función que desee aportar? SDK es un código abierto y acepta solicitudes de obtención en GitHub.
Notificaciones
Si desea recibir una notificación cuando se lance una nueva versión del conector HDFS, suscríbase a la fuente Atom.
Preguntas o comentarios
Formas de contactar:
- Problemas de GitHub: para presentar bugs y solicitudes de funciones
- Desbordamiento de pila: utilice las etiquetas oracle-cloud-infrastructure y oci-hdfs-connector en su publicación
- Sección de herramientas de desarrollador de los foros de Oracle Cloud
- My Oracle Support