专栏目标

  1. 通过一个代码样例开始使用pyflink
  2. 通过阅读pyflink的源码,逐步了解flink的python接口实现

本文使用的flink版本和pyflink版本基于1.10.1

初识Flink

flink作为当前最流行的流批统一的数据计算处理框架,其开箱即用的部署方式(standalone)对于刚刚接触flink的人来说是非常友好和吸引人的。你可以通过地址找到你想要的版本,也可以直接下载编译好的包来进行下载,当然scala源码包也可以下载

flink的部署非常简单,如果你下载好了,你可以直接切换到解压后的目录下 并执行./bin/start-cluster.sh,默认端口为8080

浏览器打开访问一下试试,因为我这边8080被占用,flink会自动往后使用端口,所以我这边是8081

flink支持python吗 flink python_flink支持python吗

邂逅PyFlink

PyFlink 是什么?这个问题也许会让人感觉问题的答案太明显了,那就是 Flink + Python,也就是 Flink on Python。那么到底 Flink on Python 意味着这什么呢?那么一个非常容易想到的方面就是能够让 Python 用享受到 Flink 的所有功能。其实不仅如此,PyFlink 的存在还有另外一个非常重要的意义就是,Python on Flink,我们可以将 Python 丰富的生态计算能力运行在 Flink 框架之上,这将极大的推动 Python 生态的发展。其实,如果你再仔细深究一下,你会发现这个结合并非偶然。

flink支持python吗 flink python_kafka_02


Python 生态和大数据生态

Pythoh 生态与大数据生态有密不可分的关系,我们先看看大家都在用 Python 解决什么实际问题?通过一份用户调查我们发现,大多数 Python 用户正在解决 ”数据分析“,”机器学习“的问题,那么这些问题场景在大数据领域也有很好的解决方案。那么 Python 生态和大数据生态结合,抛开扩大大数据产品的受众用户之外,对 Python 生态一个特别重要到意义就是单机到分布式的能力增强,我想,这也是大数据时代海量数据分析对 Python 生态的强需求。

阿里技术专家金竹的案例-PyFlink实现CDN日志实时分析

需求说明

将kafka的实时数据经过group 操作之后,将聚合结果存入mysql

代码目录

相信你已经对pyflink以及该项目有了一些自己的认识了,下边直接上代码。初学一个框架的时候,首先看实现效果,这样能快速的有个认知和学习欲望。
记得首先在你的python环境上安装一下pyflink

准备工作-安装pyflink

python3 -m pip install apache-flink

准备工作-准备一个kafka环境以及zk

准备工作-准备connector的包

Flink默认是没有打包connector的,所以我们需要下载各个connector所需的jar包并放入PyFlink的lib目录。首先拿到PyFlink的lib目录的路径:

$ PYFLINK_LIB=`python -c "import pyflink;import os;print(os.path.dirname(os.path.abspath(pyflink.__file__))+'/lib')"`

然后想需要的jar包下载到lib目录中去:

$ cd $PYFLINK_LIB 
$ curl -O https://repo1.maven.org/maven2/org/apache/flink/flink-sql-connector-kafka_2.11/1.10.0/flink-sql-connector-kafka_2.11-1.10.0.jar 
$ curl -O https://repo1.maven.org/maven2/org/apache/flink/flink-jdbc_2.11/1.10.0/flink-jdbc_2.11-1.10.0.jar 
$ curl -O https://repo1.maven.org/maven2/org/apache/flink/flink-csv/1.10.0/flink-csv-1.10.0-sql-jar.jar 
$ curl -O https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.19/mysql-connector-java-8.0.19.jar

程序目录如下图,只要三个文件即可

flink支持python吗 flink python_flink_03

cdn_demo.py

'''
@Date: 2020-06-07 01:00:16
@LastEditors: JingWeiZ
@LastEditTime: 2020-06-07 13:55:32
@FilePath: /flink-learning/cdn_demo.py
'''

import os

from pyflink.datastream import StreamExecutionEnvironment
from pyflink.table import StreamTableEnvironment, EnvironmentSettings
from enjoyment.cdn.cdn_udf import ip_to_province
from enjoyment.cdn.cdn_connector_ddl import kafka_source_ddl, mysql_sink_ddl

# 创建Table Environment, 并选择使用的Planner
env = StreamExecutionEnvironment.get_execution_environment()
t_env = StreamTableEnvironment.create(
    env,
    environment_settings=EnvironmentSettings.new_instance().use_blink_planner().build())

# 创建Kafka数据源表
t_env.sql_update(kafka_source_ddl)
# 创建MySql结果表
t_env.sql_update(mysql_sink_ddl)

# 注册IP转换地区名称的UDF
t_env.register_function("ip_to_province", ip_to_province)

# 核心的统计逻辑
t_env.from_path("cdn_access_log")\
    .select("uuid, "
            "client_ip as province, "  # IP 转换为地区名称
            "response_size, request_time")\
    .group_by("province")\
    .select(  # 计算访问量
    "province, count(uuid) as access_count, "
    # 计算下载总量
    "sum(response_size) as total_download,  "
    # 计算下载速度
    "sum(response_size) * 1.0 / sum(request_time) as download_speed") \
    .insert_into("cdn_access_statistic")

# 执行作业
t_env.execute("pyFlink_parse_cdn_log")

cdn_connector_ddl.py

'''
@Date: 2020-06-07 02:23:02
@LastEditors: JingWeiZ
@LastEditTime: 2020-06-07 03:07:35
@FilePath: /flink-learning/enjoyment/cdn/cdn_connector_ddl.py
'''
kafka_source_ddl = """ 
CREATE TABLE cdn_access_log ( 
 uuid VARCHAR, 
 client_ip VARCHAR, 
 request_time BIGINT, 
 response_size BIGINT, 
 uri VARCHAR 
) WITH ( 
 'connector.type' = 'kafka', 
 'connector.version' = 'universal', 
 'connector.topic' = 'access_log', 
 'connector.properties.zookeeper.connect' = '192.168.1.100:2181', 
 'connector.properties.bootstrap.servers' = '192.168.1.100:9092', 
 'format.type' = 'csv', 
 'format.ignore-parse-errors' = 'true' 
) 
"""


mysql_sink_ddl = """ 
CREATE TABLE cdn_access_statistic ( 
 province VARCHAR, 
 access_count BIGINT, 
 total_download BIGINT, 
 download_speed DOUBLE 
) WITH ( 
 'connector.type' = 'jdbc', 
 'connector.url' = 'jdbc:mysql://192.168.1.100:3306/flink', 
 'connector.table' = 'cdn_access_statistic', 
 'connector.username' = 'root', 
 'connector.password' = '123456', 
 'connector.write.flush.interval' = '1s' 
) 
"""

cdn_udf.py

'''
@Date: 2020-06-07 02:23:12
@LastEditors: JingWeiZ
@LastEditTime: 2020-06-07 02:23:29
@FilePath: /flink-learning/enjoyment/cdn/cdn_udf.py
'''
import re
import json
from pyflink.table import DataTypes
from pyflink.table.udf import udf
from urllib.parse import quote_plus
from urllib.request import urlopen


@udf(input_types=[DataTypes.STRING()], result_type=DataTypes.STRING())
def ip_to_province(ip):
    try:
        urlobj = urlopen(
            'http://whois.pconline.com.cn/ipJson.jsp?ip=%s' % quote_plus(ip))
        data = str(urlobj.read(), "gbk")
        pos = re.search("{[^{}]+\}", data).span()
        geo_data = json.loads(data[pos[0]:pos[1]])
        if geo_data['pro']:
            return geo_data['pro']
        else:
            return geo_data['err']
    except:
        return "UnKnow"

让程序跑起来

我们让代码跑在standalone的flink上边,这里我用pyflink自带的编译好的flink启动程序
本地运行作业

启动本地集群:

export PYTHONPATH=/Users/zhoujingwei/anaconda3/bin/
export PATH=$PYTHONPATH:$PATH
PYFLINK_LIB=$(python -c "import pyflink;import os;print(os.path.dirname(os.path.abspath(pyflink.__file__))+'/lib')")
$PYFLINK_LIB/../bin/start-cluster.sh

其中PYTHONPATH写上你的python执行器的具体bin目录,注意有多个python的机器上要修改为你安装了pyflink的环境
好了,flink启动之后,就要把我们的job提交到flink上

export PYTHONPATH=/Users/zhoujingwei/anaconda3/bin/
export PATH=$PYTHONPATH:$PATH
PYFLINK_LIB=$(python -c "import pyflink;import os;print(os.path.dirname(os.path.abspath(pyflink.__file__))+'/lib')")
echo $PYFLINK_LIB/../bin/
$PYFLINK_LIB/../bin/flink run -m localhost:8081 -py cdn_demo.py

然后可以看到任务已经提交到flink上了
这个时候你可以试着往kafka topic里边丢一些测试数据

cd /kafka/
./bin/kafka-console-producer.sh --broker-list 192.168.1.1:9092 --topic access_log
>abcd123,1.1.1.1,307,100000,https://www.aaa.com

然后去查看一下flink页面上是否有数据处理

flink支持python吗 flink python_kafka_04


再来看一下我们的mysql表里边有没有存进去把

flink支持python吗 flink python_Python_05


ok,存进去了,是不是很棒棒鸡!

当然我们用的是stream的api,这个任务只要你不取消他就一直在,后边我们一起分析一下源码以及一些常用的配置。

关注我,一起学pyflink。

参考文章:

1、https://ci.apache.org/projects/flink/flink-docs-release-1.10/api/python/pyflink.datastream.html
2、https://zhuanlan.zhihu.com/p/114717285
3、https://zhuanlan.51cto.com/art/202004/614030.htm
4、https://zhuanlan.zhihu.com/p/105909554
5、https://www.alibabacloud.com/blog/the-flink-ecosystem-a-quick-start-to-pyflink_596150
6、https://flink.apache.org/downloads.html