Apache Flink AWS S3 Sink是否需要Hadoop进行本地测试?

时间:2016-12-29 22:22:43

标签: hadoop amazon-s3 apache-flink flink-streaming

我对Apache Flink相对较新,我正在尝试创建一个生成AWS S3存储桶文件的简单项目。基于文档看起来我需要安装Hadoop才能执行此操作。

如何设置本地环境以允许我测试此功能?我在本地安装了Apache Flink和Hadoop。我已经为Hadoop的core-site.xml配置添加了必要的更改,并且还将我的HADOOP_CONF路径添加到了我的flink.yaml配置中。当我尝试通过Flink UI在本地提交作业时,我总是收到错误

2016-12-29 16:03:49,861 INFO  org.apache.flink.util.NetUtils                                - Unable to allocate on port 6123, due to error: Address already in use
2016-12-29 16:03:49,862 ERROR org.apache.flink.runtime.jobmanager.JobManager                - Failed to run JobManager.
java.lang.RuntimeException: Unable to do further retries starting the actor system
    at org.apache.flink.runtime.jobmanager.JobManager$.retryOnBindException(JobManager.scala:2203)
    at org.apache.flink.runtime.jobmanager.JobManager$.runJobManager(JobManager.scala:2143)
    at org.apache.flink.runtime.jobmanager.JobManager$.main(JobManager.scala:2040)
    at org.apache.flink.runtime.jobmanager.JobManager.main(JobManager.scala)

我假设我错过了我的环境设置方式。是否可以在本地进行此操作?任何帮助,将不胜感激。

4 个答案:

答案 0 :(得分:3)

虽然您需要Hadoop库,但您无需安装Hadoop即可在本地运行并写入S3。我刚刚尝试使用基于Avro架构编写Parquet输出并将生成的SpecificRecord生成到S3。我通过SBT和Intellij Idea在本地运行以下代码的版本。需要的部分:

1)使用以下文件指定所需的Hadoop属性(注意:不建议定义AWS访问密钥/密钥。最好在具有正确IAM角色的EC2实例上运行以读取/写入S3存储桶。但需要本地测试)

<configuration>
    <property>
        <name>fs.s3.impl</name>
        <value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
    </property>

    <!-- Comma separated list of local directories used to buffer
         large results prior to transmitting them to S3. -->
    <property>
        <name>fs.s3a.buffer.dir</name>
        <value>/tmp</value>
    </property>

    <!-- set your AWS ID using key defined in org.apache.hadoop.fs.s3a.Constants -->
    <property>
        <name>fs.s3a.access.key</name>
        <value>YOUR_ACCESS_KEY</value>
    </property>

    <!-- set your AWS access key -->
    <property>
        <name>fs.s3a.secret.key</name>
        <value>YOUR_SECRET_KEY</value>
    </property>
</configuration>

2)进口:     import com.uebercomputing.eventrecord.EventOnlyRecord

import org.apache.flink.api.scala.hadoop.mapreduce.HadoopOutputFormat
import org.apache.flink.api.scala.{ExecutionEnvironment, _}

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat
import org.apache.hadoop.conf.{Configuration => HadoopConfiguration}
import org.apache.hadoop.fs.Path
import org.apache.hadoop.mapreduce.Job

import org.apache.parquet.avro.AvroParquetOutputFormat

3)Flink代码使用具有上述配置的HadoopOutputFormat:

    val events: DataSet[(Void, EventOnlyRecord)] = ...

    val hadoopConfig = getHadoopConfiguration(hadoopConfigFile)

    val outputFormat = new AvroParquetOutputFormat[EventOnlyRecord]
    val outputJob = Job.getInstance

    //Note: AvroParquetOutputFormat extends FileOutputFormat[Void,T]
    //so key is Void, value of type T - EventOnlyRecord in this case
    val hadoopOutputFormat = new HadoopOutputFormat[Void, EventOnlyRecord](
      outputFormat,
      outputJob
    )

    val outputConfig = outputJob.getConfiguration
    outputConfig.addResource(hadoopConfig)
    val outputPath = new Path("s3://<bucket>/<dir-prefix>")
    FileOutputFormat.setOutputPath(outputJob, outputPath)
    AvroParquetOutputFormat.setSchema(outputJob, EventOnlyRecord.getClassSchema)

    events.output(hadoopOutputFormat)

    env.execute

    ...

    def getHadoopConfiguration(hadoodConfigPath: String): HadoopConfiguration = {
      val hadoopConfig = new HadoopConfiguration()
      hadoopConfig.addResource(new Path(hadoodConfigPath))
      hadoopConfig
    }

4)构建使用的依赖项和版本:

    val awsSdkVersion = "1.7.4"
    val hadoopVersion = "2.7.3"
    val flinkVersion = "1.1.4"

    val flinkDependencies = Seq(
      ("org.apache.flink" %% "flink-scala" % flinkVersion),
      ("org.apache.flink" %% "flink-hadoop-compatibility" % flinkVersion)
    )

    val providedFlinkDependencies = flinkDependencies.map(_ % "provided")

    val serializationDependencies = Seq(
      ("org.apache.avro" % "avro" % "1.7.7"),
      ("org.apache.avro" % "avro-mapred" % "1.7.7").classifier("hadoop2"),
      ("org.apache.parquet" % "parquet-avro" % "1.8.1")
    )

    val s3Dependencies = Seq(
      ("com.amazonaws" % "aws-java-sdk" % awsSdkVersion),
      ("org.apache.hadoop" % "hadoop-aws" % hadoopVersion)
    )

编辑将writeAsText用于S3:

1)创建一个Hadoop配置目录(将其引用为hadoop-conf-dir),其中包含文件core-site.xml。

例如:

mkdir /home/<user>/hadoop-config
cd /home/<user>/hadoop-config
vi core-site.xml

#content of core-site.xml 
<configuration>
    <property>
        <name>fs.s3.impl</name>
        <value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
    </property>

    <!-- Comma separated list of local directories used to buffer
         large results prior to transmitting them to S3. -->
    <property>
        <name>fs.s3a.buffer.dir</name>
        <value>/tmp</value>
    </property>

    <!-- set your AWS ID using key defined in org.apache.hadoop.fs.s3a.Constants -->
    <property>
        <name>fs.s3a.access.key</name>
        <value>YOUR_ACCESS_KEY</value>
    </property>

    <!-- set your AWS access key -->
    <property>
        <name>fs.s3a.secret.key</name>
        <value>YOUR_SECRET_KEY</value>
    </property>
</configuration>

2)创建一个目录(将引用为flink-conf-dir),其中包含文件flink-conf.yaml。

例如:

mkdir /home/<user>/flink-config
cd /home/<user>/flink-config
vi flink-conf.yaml

//content of flink-conf.yaml - continuing earlier example
fs.hdfs.hadoopconf: /home/<user>/hadoop-config

3)编辑用于运行S3 Flink作业的IntelliJ Run配置 - 运行 - 编辑配置 - 并添加以下环境变量:

FLINK_CONF_DIR and set it to your flink-conf-dir

Continuing the example above:
FLINK_CONF_DIR=/home/<user>/flink-config

4)使用该环境变量集运行代码:

events.writeAsText("s3://<bucket>/<prefix-dir>")

env.execute

答案 1 :(得分:0)

我必须执行以下操作才能在本地运行到S3的flink作业:

1-在我的flink / plugins / flink-s3-fs-hadoop目录中添加了flink-s3-fs-hadoop-1.9.1.jar

2-修改了flink / conf / flink-conf.yaml以包括 s3.access-key:AWS_ACCESS_KEY s3.secret-key:AWS_SECRET_KEY fs.hdfs.hadoopconf:/ etc / hadoop-config

我在hadoop-config文件夹中有core-site.xml文件,但是它不包含任何配置,因此可能不需要fs.hdfs.hadoopconf。

答案 2 :(得分:0)

在 sbt 中,我只需要添加 S3 库依赖项即可像本地文件系统一样使用它

SBT 文件:

"org.apache.flink" % "flink-s3-fs-hadoop" % flinkVersion.value

阅读示例:

    public static void main(String[] args) throws Exception {
    final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    DataStream<String> text = env.readTextFile("s3://etl-data-ia/test/fileStreamTest.csv");
    text.print();
    env.execute("test");}

答案 3 :(得分:0)

基于该链接 https://ci.apache.org/projects/flink/flink-docs-release-1.13/docs/deployment/filesystems/s3/#hadooppresto-s3-file-systems-plugins

<块引用>

要使用 flink-s3-fs-hadoop 插件,您应该复制相应的 JAR 将文件从 opt 目录复制到 Flink 的 plugins 目录 在启动 Flink 之前分发。

我知道的另一种方法是通过环境变量启用它 ENABLE_BUILT_IN_PLUGINS="flink-s3-fs-hadoop-[flink-version].jar"

例如:flink-s3-fs-hadoop-1.12.2.jar

对于这两种方式,我们都必须在 flink-conf.yaml 文件中定义 S3 配置

<块引用>

Flink 会在内部将其转换回 fs.s3a.connection.maximum。无需使用 Hadoop 的 XML 配置文件传递配置参数。

s3.endpoint: <end-point>
s3.path.style.access : true

至于 AWS 凭证,它们必须在环境变量或。在 flink-conf.yaml 中配置

s3.endpoint: <end-point>
s3.path.style.access : true
s3.access-key: <key>
s3.secret-key: <value>
s3.region: <region>

一旦设置完毕,您就可以像@EyalP 提到的那样从 S3 读取,或写入 S3(即使用数据集)

dataset.map(new MapToJsonString())
                .writeAsText("s3://....",
                        FileSystem.WriteMode.OVERWRITE);

如果您想在本地进行测试(没有真实的 AWS 帐户),我建议您检查 localstack。它完全支持各种 AWS 服务(包括 S3)。如果你这样做,那么 AWS 凭证就不是必需的(可以提供为空),端点将是本地堆栈本身。