Escribir en HDFS desde Java, obtener "solo se podría replicar en 0 nodos en lugar de minReplication"
hadoop (11)
He descargado y puesto en marcha la máquina virtual de demostración Hadoop de Cloudera para CDH4 (ejecutando Hadoop 2.0.0). Estoy intentando escribir un programa Java que se ejecutará desde mi máquina con Windows 7 (la misma máquina / sistema operativo en el que se ejecuta la máquina virtual). Tengo un programa de ejemplo como:
public static void main(String[] args) {
try{
Configuration conf = new Configuration();
conf.addResource("config.xml");
FileSystem fs = FileSystem.get(conf);
FSDataOutputStream fdos=fs.create(new Path("/testing/file01.txt"), true);
fdos.writeBytes("Test text for the txt file");
fdos.flush();
fdos.close();
fs.close();
}catch(Exception e){
e.printStackTrace();
}
}
Mi archivo config.xml solo tiene en la propiedad definida: fs.default.name = hdfs: // CDH4_IP: 8020.
Cuando lo ejecuto me sale la siguiente excepción:
org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /testing/file01.txt could only be replicated to 0 nodes instead of minReplication (=1). There are 1 datanode(s) running and 1 node(s) are excluded in this operation.
at org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.chooseTarget(BlockManager.java:1322)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getAdditionalBlock(FSNamesystem.java:2170)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.addBlock(NameNodeRpcServer.java:471)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.addBlock(ClientNamenodeProtocolServerSideTranslatorPB.java:297)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java:44080)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:453)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:898)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1693)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1689)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1332)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:1687)
at org.apache.hadoop.ipc.Client.call(Client.java:1160)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:202)
at $Proxy9.addBlock(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:164)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:83)
at $Proxy9.addBlock(Unknown Source)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.addBlock(ClientNamenodeProtocolTranslatorPB.java:290)
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.locateFollowingBlock(DFSOutputStream.java:1150)
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.nextBlockOutputStream(DFSOutputStream.java:1003)
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:463)
He buscado en Internet y parece que esto sucede cuando el espacio en disco es bajo, pero no es así para mi cuando ejecuto "hdfs dfsadmin -report", obtengo lo siguiente:
Configured Capacity: 25197727744 (23.47 GB)
Present Capacity: 21771988992 (20.28 GB)
DFS Remaining: 21770715136 (20.28 GB)
DFS Used: 1273856 (1.21 MB)
DFS Used%: 0.01%
Under replicated blocks: 0
Blocks with corrupt replicas: 0
Missing blocks: 0
-------------------------------------------------
Datanodes available: 1 (1 total, 0 dead)
Live datanodes:
Name: 127.0.0.1:50010 (localhost.localdomain)
Hostname: localhost.localdomain
Decommission Status : Normal
Configured Capacity: 25197727744 (23.47 GB)
DFS Used: 1273856 (1.21 MB)
Non DFS Used: 3425738752 (3.19 GB)
DFS Remaining: 21770715136 (20.28 GB)
DFS Used%: 0.01%
DFS Remaining%: 86.4%
Last contact: Fri Jan 11 17:30:56 EST 201323 EST 2013
También puedo ejecutar este código desde la máquina virtual. No estoy seguro de cuál es el problema o cómo solucionarlo. Esta es la primera vez que uso hadoop, así que probablemente me esté perdiendo algo básico. ¿Algunas ideas?
Actualizar
Lo único que veo en los registros es una excepción similar a la de obtener en el cliente:
java.io.IOException: File /testing/file01.txt could only be replicated to 0 nodes instead of minReplication (=1). There are 1 datanode(s) running and 1 node(s) are excluded in this operation.
at org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.chooseTarget(BlockManager.java:1322)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getAdditionalBlock(FSNamesystem.java:2170)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.addBlock(NameNodeRpcServer.java:471)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.addBlock(ClientNamenodeProtocolServerSideTranslatorPB.java:297)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java:44080)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:453)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:898)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1693)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1689)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1332)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:1687)
Intenté cambiar los permisos en el directorio de datos (/ var / lib / hadoop-hdfs / cache / hdfs / dfs / data) y eso no lo solucionó (llegué a dar acceso completo a todos).
Me doy cuenta de que cuando navego por el HDFS a través de la aplicación web HUE, veo que se creó la estructura de carpetas y que el archivo existe pero está vacío. Intenté colocar el archivo en el directorio de usuario predeterminado usando
FSDataOutputStream fdos=fs.create(new Path("testing/file04.txt"), true);
en lugar de
FSDataOutputStream fdos=fs.create(new Path("/testing/file04.txt"), true);
Lo que hace que la ruta del archivo se convierta en "/user/dharris/testing/file04.txt" (''dharris'' es mi usuario de Windows). Pero eso me dio el mismo tipo de error.
Así es como creo archivos en el HDFS:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
FileSystem hdfs = FileSystem.get(context.getConfiguration());
Path outFile=new Path("/path to store the output file");
String line1=null;
if (!hdfs.exists(outFile)){
OutputStream out = hdfs.create(outFile);
BufferedWriter br = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
br.write("whatever data"+"/n");
br.close();
hdfs.close();
}
else{
String line2=null;
BufferedReader br1 = new BufferedReader(new InputStreamReader(hdfs.open(outFile)));
while((line2=br1.readLine())!=null){
line1=line1.concat(line2)+"/n";
}
br1.close();
hdfs.delete(outFile, true);
OutputStream out = hdfs.create(outFile);
BufferedWriter br2 = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
br2.write(line1+"new data"+"/n");
br2.close();
hdfs.close();
}
Como encontré muchas preguntas como esta en mi búsqueda por tener exactamente el mismo problema, pensé que compartiría lo que finalmente me funcionó. Encontré esta publicación en el foro de Hortonworks: https://community.hortonworks.com/questions/16837/cannot-copy-from-local-machine-to-vm-datanode-via.html
La respuesta fue realmente entender lo que significa llamar a una nueva configuración () y establecer los parámetros correctos según los necesito. En mi caso fue exactamente la mencionada en ese post. Así que mi código de trabajo se ve así.
try {
Configuration config = new Configuration();
config.set("dfs.client.use.datanode.hostname", "true");
Path pdFile = new Path("stgicp-" + pd);
FileSystem dFS = FileSystem.get(new URI("hdfs://" + HadoopProperties.HIVE_HOST + ":" + HadoopProperties.HDFS_DEFAULT_PORT), config,
HadoopProperties.HIVE_DEFAULT_USER);
if (dFS.exists(pdFile)) {
dFS.delete(pdFile, false);
}
FSDataOutputStream outStream = dFS.create(pdFile);
for (String sjWLR : processWLR.get(pd)) {
outStream.writeBytes(sjWLR);
}
outStream.flush();
outStream.close();
dFS.delete(pdFile, false);
dFS.close();
} catch (IOException | URISyntaxException | InterruptedException e) {
log.error("WLR file processing error: " + e.getMessage());
}
El factor de replicación del mensaje de error parece estar bien, es decir1. Parece que datanode está funcionando correctamente o tiene problemas de permisos. Verifique los permisos y verifique el estado de datanode del usuario, está intentando ejecutar hadoop.
Me encontré con un problema similar y tengo dos datos que pueden ayudarte.
Lo primero que me di cuenta es que estaba usando el túnel ssh para acceder al nodo de nombre y cuando el código del cliente intenta acceder al nodo de datos no puede encontrar el nodo de datos debido a que el túnel de alguna manera desordenado la comunicación. Luego ejecuto el cliente en el mismo cuadro que el nodo de nombre hadoop y resolvió el problema. En resumen, la configuración de red no estándar confundió a hadoop para encontrar el nodo de datos.
La razón por la que usé el túnel ssh es que no puedo acceder al nodo de nombre de forma remota y pensé que se debía a una restricción de puerto por parte del administrador, así que utilicé el túnel ssh para omitir la restricción. Pero resulta ser una mala configuración de hadoop.
En core-site.xml después de que cambié
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
a
<value>hdfs://host_name:9000</value>
Ya no necesito el ssh turnnel y puedo acceder a los hdfs de forma remota.
Parece ser un problema con el FS. O bien los parámetros en cross-site.xml no coinciden con el archivo que intenta leer
O
hay una falta de coincidencia común en la ruta (veo que hay una referencia de WINDOWS).
puede usar la herramienta cygwin para configurar la ruta y colocarla en el lugar donde se ubican los datanodes y las ubicaciones de los archivos temporales y eso debería hacer el truco. Ubicación: $ / bin / cygpath.exe
La replicación de PS no parece ser el problema principal aquí, según mi opinión
Puede intentar eliminar la carpeta de datos (dfs / data) manualmente y formando el namenode. A continuación, puede iniciar hadoop.
Tengo un mismo problema.
En mi caso, una clave del problema fue el siguiente mensaje de error.
Hay 1 datanode (s) en ejecución y 1 nodo (s) se excluyen en esta operación.
Significa que su cliente hdfs no pudo conectarse a su datanode con el puerto 50010. Cuando se conectó a hdfs namenode, podría obtener el estado de un datanode. Sin embargo, su cliente hdfs no se pudo conectar a su nodo de datos.
(En hdfs, un namenode administra directorios de archivos y datanodes. Si hdfs-client se conecta a un namnenode, encontrará una ruta de archivo de destino y una dirección de datanode que contiene los datos. Luego hdfs-client se comunicará con datanode. compruebe esos uri de datanode utilizando netstat. porque hdfs-client intentará comunicarse con datanodes utilizando una dirección informada por namenode)
Resolví ese problema por:
- abriendo el puerto 50010 (dfs.datanode.address) en un servidor de seguridad.
- añadiendo propiedad
"dfs.client.use.datanode.hostname", "true"
- agregando nombre de host a hostfile en mi PC cliente.
Lo siento por mi pobre habilidad en inglés.
Tuve un problema similar, en mi caso, simplemente vacié la siguiente carpeta ${hadoop.tmp.dir}/nm-local-dir/usercache/{{hdfs_user}}/appcache/
Vaya a la máquina virtual de Linux y compruebe el nombre de host y la DIRECCIÓN iP (use ifconfig cmd). Luego en el archivo linux vm edit / etc / host con
IPADDRESS (SPALCE) nombre de host
ejemplo: 192.168.110.27 clouderavm
y cambiar todos los archivos de configuración de Hadoop como
core-site.xml
hdfs-site.xml
mapred-site.xml
hilo-sitio.xml
cambie localhost o localhost.localdomain o 0.0.0.0 a su nombre de host
A continuación, reinicie Cloudera pesebre.
en la máquina de Windows edite C: / Windows / System32 / Drivers / etc / hosts
añadir una línea al final con
vm machine ip y nombre de host (igual a como lo hizo en el archivo / etc / host en vm)
VMIPADRESS VMHOSTNAME
ejemplo:
192.168.110.27 clouderavm
luego verifique, debería funcionar, para una verificación detallada de la configuración después de VIDEO desde su tubo
agregar propiedad dada en hdfs-site.xml
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
y agrega este archivo también en tu programa
conf.addResource("hdfs-site.xml");
deja de hadoop
stop-all.sh
entonces empezar
start-all.sh
en la configuración de hadoop, la replicación predeterminada se establece en 3. verifíquela una vez y modifíquela según sus requisitos