flink-1.11 pyflink 部署文档

本文主要参考了 孙金城 大佬的下面几篇文章:
Apache Flink 说道系列 - PyFlink 作业的多种部署模式
Three Min Series - How to using PyFlink Shell
代码参考:https://github.com/pyflink/playgrounds
结合自己测试过程,有些地方做了修改,做一个记录。

1.从源码编译 flink

如果已经获得 flink 二进制包,可以跳过该步骤。

可以参考官方文档 Build Flink
注意环境要求:

  • = Maven 3.2.5
  • = Java 8u51

使用下面命令编译:

git clone https://github.com/apache/flink
mvn clean install -DskipTests

2. 从源码编译 pyflink

如果已经获得 pyflink 二进制包,或者使用 pip 安装,可以跳过该步骤。

参考官方文档 Build PyFlink
需要注意的是,需要在 Python 3.5+ 环境下编译。
注意:需要 Python 3.5+。
进入 flink 源码目录,执行以下命令:

cd flink-python; python setup.py sdist bdist_wheel

上面的命令可以生成 sdist 包和 bdist_wheel 包。生成目录为 flink-python/dist/,sdist 包和 bdist_wheel 都可以用来安装 pyflink,选择一种即可。

2.安装并测试

本文只介绍 onyarn 模式的安装、部署
安装机器环境要求:

  • Apache Beam version == 2.19.0
  • Python 3.5+
  • Pip (version >= 7.1.0)
  • hadoop 文件系统

安装 beam:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple apache-beam==2.19.0

2.1 install pyflink

将获得的 sdist 包(apache-flink-*.tar.gz) 拷贝到需要安装的机器上。
-i 指定国内 pip 源,安装会快一点

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple  apache-flink-1.11.dev0.tar.gz

这样,通过 pip list 就可以看到 apache-flink 安装好了:

Package             Version
------------------- ---------
apache-beam         2.19.0
apache-flink        1.11.dev0
...

2.2 打包 Python 环境

因为 yarn 集群上 python 环境不一定符合 flink 程序的版本要求,所以我们需要使用 virtualenv 打包 python 环境。

2.2.1 install virtualenv

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple  virtualenv

2.2.2 创建 Python 环境

用 virtualenv 以 always-copy 方式建立一个全新的 Python 环境,这里定义名称为 venv:

virtualenv --always-copy venv

会在当前目录生成一个 venv 文件。

拷贝原环境的 python 标准库到 venv 中:

VENV_PYTHON=venv/bin/python
DST=`$VENV_PYTHON -c "import os;import pip;print(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(pip.__file__)))))"`
SRC=`$VENV_PYTHON -c "import os;import contextlib;print(os.path.dirname(os.path.abspath(contextlib.__file__)))"`
if [ "$SRC" != "$DST" ]; then find "$SRC" -maxdepth 1 ! -name "site-packages" ! -name "__pycache__" ! -name "python3.*" -exec cp -r -- "{}" "${DST}" \; ; fi

2.2.3 新环境安装 apache-beam

使用 venv 中的 pip 安装 apache-beam

venv/bin/pip install -i https://pypi.tuna.tsinghua.edu.cn/simple apache-beam==2.19.0

2.2.4 打包 Python 环境

把独立 python 环境打成 zip 包,目前打成的包比较大,有 100 多 MB

zip -r venv.zip venv

2.3 例子测试

Bath:拷贝下面的代码到 word_count.py 文件:

import logging
import os
import shutil
import sys
import tempfile

from pyflink.dataset import ExecutionEnvironment
from pyflink.table import BatchTableEnvironment, TableConfig


def word_count():
    content = "line Licensed to the Apache Software Foundation ASF under one " \
              "line or more contributor license agreements See the NOTICE file " \
              "line distributed with this work for additional information " \
              "line regarding copyright ownership The ASF licenses this file " \
              "to you under the Apache License Version the " \
              "License you may not use this file except in compliance " \
              "with the License"

    t_config = TableConfig()
    env = ExecutionEnvironment.get_execution_environment()
    t_env = BatchTableEnvironment.create(env, t_config)

    # register Results table in table environment
    tmp_dir = tempfile.gettempdir()
    result_path = tmp_dir + '/result'
    if os.path.exists(result_path):
        try:
            if os.path.isfile(result_path):
                os.remove(result_path)
            else:
                shutil.rmtree(result_path)
        except OSError as e:
            logging.error("Error removing directory: %s - %s.", e.filename, e.strerror)

    logging.info("Results directory: %s", result_path)

    sink_ddl = """
        create table Results(
            word VARCHAR,
            `count` BIGINT
        ) with (
            'connector.type' = 'filesystem',
            'format.type' = 'csv',
            'connector.path' = '{}'
        )
        """.format(result_path)
    t_env.sql_update(sink_ddl)

    elements = [(word, 1) for word in content.split(" ")]
    t_env.from_elements(elements, ["word", "count"]) \
         .group_by("word") \
         .select("word, count(1) as count") \
         .insert_into("Results")

    t_env.execute("word_count")


if __name__ == '__main__':
    logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(message)s")

    word_count()

执行以下命令,以 per-job 模式提交:

bin/flink run -m yarn-cluster -pyarch venv.zip -pyexec venv.zip/venv/bin/python -py word_count.py

Streaming: from_kafka_to_kafka.py

from pyflink.datastream import StreamExecutionEnvironment, TimeCharacteristic
from pyflink.table import StreamTableEnvironment, DataTypes, EnvironmentSettings
from pyflink.table.descriptors import Schema, Kafka, Json, Rowtime, Csv


def from_kafka_to_kafka_demo():
    # init environment
    s_env = StreamExecutionEnvironment.get_execution_environment()
    s_env.set_stream_time_characteristic(TimeCharacteristic.EventTime)
    s_env.set_parallelism(1)

    # use blink table planner
    st_env = StreamTableEnvironment \
        .create(s_env, environment_settings=EnvironmentSettings
                .new_instance()
                .in_streaming_mode()
                .use_blink_planner().build())

    # register source and sink
    register_rides_source(st_env)
    register_rides_sink(st_env)

    # query
    st_env.from_path("source").insert_into("sink")

    # execute
    st_env.execute("2-from_kafka_to_kafka")


def register_rides_source(st_env):
    st_env \
        .connect(  # declare the external system to connect to
            Kafka()
                .version("universal")
                .topic("words")
                .start_from_earliest()
                .property("zookeeper.connect", "localhost:2181")
                .property("bootstrap.servers", "localhost:9092")) \
        .with_format(  # declare a format for this system
            Csv()
                .field_delimiter("\n")
                .schema(DataTypes.ROW([DataTypes.FIELD("line", DataTypes.STRING())]))) \
        .with_schema(  # declare the schema of the table
            Schema()
                .field("line", DataTypes.STRING())) \
        .in_append_mode() \
        .create_temporary_table("source")

def register_rides_sink(st_env):
    st_env \
        .connect(  # declare the external system to connect to
            Kafka()
                .version("universal")
                .topic("tempwords")
                .property("zookeeper.connect", "localhost:2181")
                .property("bootstrap.servers", "localhost:9092")) \
        .with_format(  # declare a format for this system
            Csv()
                .field_delimiter("\n")
                .schema(DataTypes.ROW([DataTypes.FIELD("line", DataTypes.STRING())]))) \
        .with_schema(  # declare the schema of the table
            Schema()
                 .field('line', DataTypes.STRING())) \
        .in_append_mode() \
        .create_temporary_table("sink")


if __name__ == '__main__':
    from_kafka_to_kafka_demo()

执行以下命令,以 per-job 模式提交:

bin/flink run -m yarn-cluster -pyarch venv.zip -pyexec venv.zip/venv/bin/python -py from_kafka_to_kafka.py

参数说明:

参数 说明
-pyarch/–pyArchives venv.zip 将当前目录下的 venv.zip 上传到yarn集群. -pyarch/--pyArchives 可以上传独立 python 环境或者数据文件,并且只能是 zip 压缩格式。flink 将指定的 zip 文件将被解压到 python UDF worker 的工作目录,默认解压目录名和 zip 压缩包名相同,可以通过#指定解压的目录名,例如 -pyarch data.zip#data1将被解压为 data1。还可以使用 , 分隔指定多个 zip 压缩包,例如:-pyarch file:///tmp/py37.zip,file:///tmp/data.zip#data,然后可以通过 -pyexec 指定 python UDF worker 的 python 路径,例如 -pyexec py37.zip/py37/bin/python;python UDF worker 可以通过 f = open('data/data.txt', 'r')方式获取数据文件
-pyexec/–pyExecutable venv.zip/venv/bin/Python 指定venv.zip中的Python解释器来执行Python UDF,路径需要和zip包内部结构一致。
-py/–python pyflink_job.py 程序入口

flink 还提供了一些其他参数:

参数 说明
-pyfs,–pyFiles 为作业添加自定义的 python 文件,这些文件会被添加到 python UDF woker 的 PYTHONPATH 环境变量,标准 python resource 文件后缀如 .py/.egg/.zip 或者目录都是支持的,可以使用 , 分隔上传多个文件,例如 --pyFiles file:///tmp/myresource.zip,hdfs:///$namenode_address/myresource2.zip
-pym,–pyModule 指定 python 入口文件的 Python module,必须和 --pyFiles 一起使用
-pyreq,–pyRequirements 指定一个 requirements.txt 文件,用来安装第三方依赖,这些依赖会被添加到 python UDF worker 的 PYTHONPATH 环境变量中。用户可以选择的将这些依赖放到一个目录中(python UDF worker 就可以直接用了)用 # 指定要上传的目录。例如 --pyRequirements file:///tmp/requirements.txt#file:///tmp/cached_dir

本文参考
https://enjoyment.cool/2020/01/02/Apache-Flink-%E8%AF%B4%E9%81%93%E7%B3%BB%E5%88%97-PyFlink-%E4%BD%9C%E4%B8%9A%E7%9A%84%E5%A4%9A%E7%A7%8D%E9%83%A8%E7%BD%B2%E6%A8%A1%E5%BC%8F/#more
https://enjoyment.cool/2019/12/05/Apache-Flink-%E8%AF%B4%E9%81%93%E7%B3%BB%E5%88%97-%E5%A6%82%E4%BD%95%E5%9C%A8PyFlink-1-10%E4%B8%AD%E8%87%AA%E5%AE%9A%E4%B9%89Python-UDF

更多内容请关注 大神博客

你可能感兴趣的:(flink-1.11,pyflink)