我有一个flink作业,它使用TextOutputFormat将数据写入目标。代码是这样的:
String basePath = "/Users/me/out";
// String basePath = "hdfs://10.199.200.204:9000/data";
// ensure we have a format for this.
TextOutputFormat<String> format = new TextOutputFormat<>(new Path(basePath, selection + "/" + uid));
StreamingRuntimeContext context = (StreamingRuntimeContext) getRuntimeContext();
format.configure(GlobalConfiguration.getConfiguration());
format.open(context.getIndexOfThisSubtask(), context.getNumberOfParallelSubtasks());
// then serialize and write.
String record = serializationFunction.map(value);
log.info("Writing " + record);
format.writeRecord(record);
当在普通文件系统上使用路径作为目标时,这非常正常。但是,当我将基本路径更改为hdfs位置时,它不再按预期工作。会发生的是,输出文件实际上是在HDFS上创建的,但它的大小为零字节。我在电话会议期间没有任何例外。
我正在使用Hadoop 2.6.0和Flink 0.10.1。使用命令行工具(hadoop fs -put ...
)将文件复制到hdfs是有效的,所以我想我可以排除一些Hadoop配置错误。我也开始使用Wireshark并看到数据被传输到Hadoop服务器,所以在实际写入之前我是否需要提交一些数据?
答案 0 :(得分:2)
为了将结果清除为HDFS,您必须在完成记录后调用close
的{{1}}方法。
TextOutputFormat
答案 1 :(得分:0)
我发现了它为什么会发生。实际上有两个原因:
Till Rohrmann指出,输出格式没有刷新。由于我在流媒体作业中使用该格式,因此关闭格式是没有选择的。我使用了自己的格式,可以刷新:
public class MyTextOutputFormat<T> extends TextOutputFormat<T> {
public MyTextOutputFormat(Path outputPath) {
super(outputPath);
}
public MyTextOutputFormat(Path outputPath, String charset) {
super(outputPath, charset);
}
// added a custom flush method here.
public void flush() throws IOException {
stream.flush();
}
}
我在VM guest虚拟机中运行HDFS并从VM主机连接到它。 Flink的HDFS客户端默认使用datanode的IP地址连接到数据节点。但是,datanode的IP地址报告为127.0.0.1
。所以flink尝试连接到127.0.0.1
,当然主机系统中没有运行HDFS datanode。然而,这仅在我添加手动冲洗操作后显示。为了解决这个问题,我不得不改变两件事:
在VM来宾中,修改$HADOOP_HOME/etc/hadoop/hdfs-site.xml
并添加
<property>
<name>dfs.datanode.hostname</name>
<value>10.199.200.204</value> <!-- IP of my VM guest -->
</property>
此更改使namenode报告成为datanode的正确可路由主机名。它实际上是一个没有文档的设置,但似乎工作。
在实际运行flink的系统上,我必须在文件夹中创建hdfs-site.xml
(例如/home/me/conf
),然后必须设置指向的环境变量HADOOP_CONF_DIR
/home/me/conf
。该文件包含以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.client.use.datanode.hostname</name>
<value>true</value>
</property>
</configuration>
此更改指示hadoop客户端使用主机名而不是ip地址连接到datanode。在这些更改之后,我的数据被正确写入HDFS。