huanglaoxie0503 / pyflink-basic-introduction

PyFlink从入门到精通
19 stars 4 forks source link

PyFlink学习大纲

PyFlink简介

什么是PyFlink

PyFlink是一个可以让我们用Python语言编写Flink程序的库。它提供了与Flink Java/Scala API等价的Python API。

PyFlink的主要特征包括:

PyFlink使得Python用户可以非常方便地开发Flink数据分析程序,不需要掌握Java或Scala即可构建复杂的流批任务。它降低了编程复杂度,提供更直观的编程体验。

总体而言,PyFlink充分发挥了Python的简洁和Flink的并行计算优势,为数据工程师和数据科学家提供了一个更易用、更富表现力的大数据分析框架。它使Python和Flink两者的优点得以完美结合。

PyFlink的特性及优势

PyFlink作为Flink的Python API,具有以下主要特性和优势:

  1. 完全兼容Flink:PyFlink支持Flink所有核心API和运行时特性,用户可以无缝使用PyFlink访问Flink的功能。

  2. 流批一体:同时支持流处理和批处理,提供统一的编程模型。

  3. 基于pandas的批处理:批处理支持基于用户熟悉的pandas DataFrame API。

  4. 异步流处理:基于asyncio实现的异步数据流处理。

  5. Python UDF:支持使用Python自定义函数,扩展计算能力。

  6. 机器学习集成:提供与TensorFlow、PyTorch等的深度集成。

  7. 部署灵活:支持在YARN、K8s、Standalone等环境部署。

  8. 性能优越:通过代码生成和优化,批处理性能可与Java版媲美。

  9. 简化编程:大大降低编程复杂度,提高工作效率。

  10. 开发调试方便:支持Jupyter Notebook,有助于交互式开发。

综上,PyFlink兼具Python的简洁优雅和Flink的性能优势,是构建流批一体分析应用的极佳选择。它可以大幅降低开发和使用门槛,提升数据分析效率。

PyFlink vs Flink Java/Scala API对比

这里我简要对比一下PyFlink和Flink的Java/Scala API:

总体来说,PyFlink集Python和Flink优点于一体,是更易用和富有表现力的Flink API。

环境配置

安装PyFlink

使用conda安装PyFlink的步骤如下:

  1. 创建并激活一个conda环境:
conda create -n pyflink python=3.10
conda activate pyflink
  1. 配置conda以便搜索anaconda cloud上的PyFlink包:
conda config --add channels conda-forge
  1. 搜索可用的PyFlink版本:
conda search pyflink 
  1. 选择需要的PyFlink版本并安装:
# 例如安装最新版本
conda install pyflink=1.17.1
  1. 验证是否安装成功:
import pyflink
print(pyflink.__version__)

这样通过conda就可以方便快捷地安装PyFlink环境,并管理多个版本。

conda也能自动处理PyFlink所依赖的其他包,如py4j、pandas等。非常适合用于数据科学、机器学习项目中。

创建PyFlink环境

这里是在Python中创建PyFlink执行环境的常见方式:

1. 创建批处理环境

from pyflink.dataset import ExecutionEnvironment

env = ExecutionEnvironment.get_execution_environment()

2. 创建流处理环境

from pyflink.datastream import StreamExecutionEnvironment

env = StreamExecutionEnvironment.get_execution_environment()

3. 设置执行模式

# 本地执行
env.set_runtime_mode(RuntimeExecutionMode.LOCAL) 

# 集群执行 
env.set_runtime_mode(RuntimeExecutionMode.CLUSTER)

4. 注册函数

env.register_function("my_udf", udf)

5. 配置参数

env.get_config().set_parallelism(16)

通过创建执行环境,可以启动PyFlink作业的运行,并进行必要的配置。

PyFlink基础概念

Execution Environment

在PyFlink中,Execution Environment(执行环境)是所有Flink程序的基础入口点。它负责建立程序的上下文环境并负责执行程序。

PyFlink中创建Execution Environment的常用方式有两种:

  1. 创建一个批处理执行环境:
env = ExecutionEnvironment.get_execution_environment()
env.set_runtime_mode(RuntimeExecutionMode.BATCH)
  1. 创建一个流处理执行环境:
# 默认是流执行环境
env = StreamExecutionEnvironment.get_execution_environment()
# 也可以直接指定
env.set_runtime_mode(RuntimeExecutionMode.STREAMING)

Execution Environment提供了下列主要功能:

需要运行Flink Python程序时,第一步都是创建Execution Environment,这为后续编写实际的处理逻辑打下基础。

DataSet和DataStream

在PyFlink中,DataSet和DataStream是核心的编程抽象,用于构建批处理和流处理程序。

  1. DataSet

DataSet代表一个由各种数据组成的批量数据集合,用于构建批处理程序。常见操作包括:

使用DataSet可以方便地对批量数据进行ETL和分析。

  1. DataStream

DataStream表示一个包含连续数据的流,用于构建流处理程序。常见操作包括:

使用DataStream可以构建实时的流处理和分析应用。

DataSet和DataStream为PyFlink提供了统一的批流处理编程抽象和API。

函数和操作符

在PyFlink中,函数和操作符是编程的基本构建块,用于实现数据转换逻辑。

  1. 函数

PyFlink支持使用Python编写函数,常见类型包括:

所有这些函数可以方便地在PyFlink程序中被使用。

  1. 操作符

PyFlink提供了各种预定义的转换操作符,包括:

通过组合使用这些操作符,可以实现批流程序的复杂数据处理需求。

函数和操作符为PyFlink提供了丰富的编程模型,可实现自定义和灵活的数据处理。它们是开发PyFlink程序的基础。

数据类型和序列化

在 PyFlink中,支持以下主要的数据类型和序列化:

数据类型

序列化

Flink需要对数据进行序列化和反序列化。PyFlink支持多种序列化方式:

数据转换

PyFlink提供了方便的数据类型转换:

灵活使用这些类型转换可以简化代码。

注意正确设置序列化,避免数据解析错误。 Pickle序列化对Python对象支持广,但不够高效。 Avro和Arrow支持的数据类型更受限制,但性能更好。

PyFlink编程模型

批处理编程

读取和写入数据

在PyFlink中,读取和写入批处理数据有以下常用方式:

读取数据

ds = env.from_elements([1, 2, 3])  
ds = env.read_text('/path/to/file')
ds = env.from_jdbc(...)

写入数据

ds.write_csv('/path/to/file') 
print(ds)
ds.write_jdbc(...)
ds.connect_sink(...)  

通过这些机制,可以访问各种外部系统的数据源,也可以将处理结果输出到不同目标系统。

转换操作

在PyFlink中,常见的批处理DataSet转换操作包括:

ds.map(lambda x: x * 2)
ds.filter(lambda x: x > 5)
ds.reduce(lambda x, y: x + y)
ds1.join(ds2).where(1).equal_to(2) 
ds1.union(ds2)
ds.partition_by_hash('id').sort_partition('score', Order.DESCENDING)
ds.with_broadcast_set('dim_table', dim_ds)

通过组合这些转换操作,可以实现复杂的业务逻辑和数据处理流程。

分组和聚合

在PyFlink中,可以通过 groupby 和 aggregate 操作对批处理数据进行分组和聚合。

分组 GroupBy

按指定键对数据集进行分组:

grouped_ds = ds.group_by('key') 

聚合 Aggregate

在分组上进行聚合运算:

grouped_ds.aggregate(AggregateFunction)  

常用的聚合函数包括:

示例:

# 按学生分组,计算每组学生的平均分数  
ds.group_by('student_id')
   .aggregate(StudentAverage('score'))

groupBy 和 aggregate 提供了对批数据集进行聚合统计和得出指标的能力,是批处理的重要操作。

流处理编程

定义源

在 PyFlink中定义流处理程序的数据源,常见的方式包括:

  1. 从集合创建流:
stream = env.from_collection([1, 2, 3])
  1. 从文件读取流:
stream = env.read_text('file_path') 
  1. 从kafka读取流:
stream = env.add_source(FlinkKafkaConsumer(topics='topic', deserialization_schema=DeserializationSchema(), properties={}))
  1. 自定义源函数:
class MySource(SourceFunction):
  def run(self):
    ...

stream = env.add_source(MySource())  
  1. 从数据流生成流:
stream1 = ...
stream2 = stream1.filter(...)  

按数据源区分,PyFlink支持集合、文件、Kafka等外部流源,也可以自定义源函数实现自定义逻辑。

转换操作

在PyFlink中,常见的流处理DataStream转换操作包括:

stream.map(lambda x: x * 2)
stream.filter(lambda x: x > 5)  
stream.key_by(lambda x: x[0]) 
stream.key_by(...).reduce(lambda x, y: x + y)
stream1.connect(stream2)
stream.key_by(...).window(TumblingWindow)
stream.process(MyProcessFunction())

通过组合这些转换操作,可以在流上进行复杂的Events Driven 应用处理。

输出结果

在PyFlink中,常见的流处理结果输出方式包括:

stream.print()
stream.write_text('/path/to/file')
stream.add_sink(FlinkKafkaProducer('topic'))
stream.add_sink(JdbcSink()) 
class MySink(SinkFunction):
  def invoke(self, value):
    ...

stream.add_sink(MySink())
stream.execute_insert('output_table')
stream.add_sink(Converters.to_data_stream(collector))

PyFlink支持将流处理结果输出到外部存储、消息系统或通过自定义Sink函数输出到其他目标系统。

PyFlink Table API和SQL

创建表

在PyFlink中,可以通过Table API和SQL来创建表。

Table API

使用table_environment.from_elements从数据集合创建表:

from pyflink.table import TableEnvironment

env = TableEnvironment.create(...)  

table = env.from_elements([(1, 'John'), (2, 'Peter')])

或者从文件、数据库等外部系统读取数据创建表。

SQL

使用CREATE TABLE语句创建表:

CREATE TABLE MyTable (
  id BIGINT,
  name STRING
) WITH (
  'connector' = 'filesystem',
  'path' = '/path/to/file'
);

注册表

无论是使用Table API还是SQL创建的表,都需要在环境中注册以便后续查询:

env.create_temporary_table('MyTable', table)
CREATE TEMPORARY TABLE MyTable ...

Table API和SQL为PyFlink提供了声明式的表处理和分析能力。

查询表

在PyFlink中,可以通过Table API和SQL来查询表中的数据。

Table API

通过table对象查询:

result = table.select(table.id, table.name).filter(table.id > 1)

SQL

通过sql_query方法查询:

result = env.sql_query("SELECT id, name FROM MyTable WHERE id > 1")

或者在SQL CLI环境中交互查询:

Flink SQL> SELECT * FROM MyTable

结果处理

查询结果可以进一步转换或输出:

result.to_pandas() # 转为 Pandas DataFrame

result.execute_insert('output_table') # 插入到表中

Table API提供了面向对象的查询方式,SQL提供了声明式的查询方式。结合两者可以实现复杂的表分析和处理。

关联和聚合

在PyFlink中,Table API和SQL都支持对表进行联结和聚合查询。

关联查询

Table API:

result = table1.join(table2).where(table1.id == table2.id)

SQL:

SELECT * 
FROM table1 
JOIN table2 
ON table1.id = table2.id

支持INNER JOIN、LEFT JOIN、RIGHT JOIN等。

聚合查询

Table API:

result = table.group_by(table.key).select(table.key, table.value.avg)

SQL:

SELECT key, AVG(value)
FROM table 
GROUP BY key

支持聚合函数 COUNT、SUM、AVG、MAX、MIN等。

Table API 和 SQL为PyFlink提供了统一的表处理查询能力,可以混合使用。

部署和运行

本地执行

使用PyFlink进行本地部署运行的基本步骤如下:

  1. 安装PyFlink

使用pip或conda安装PyFlink及其依赖:

pip install apache-flink
  1. 编写PyFlink程序

编写批处理或流处理程序代码,并设置执行环境。

  1. 启动本地Flink集群

启动standalone session集群作为运行时环境:

./bin/start-cluster.sh
  1. 提交PyFlink程序

设置执行环境为本地集群后提交程序:

env.set_runtime_mode(execution_mode.cluster) 
env.execute("pyflink job")
  1. 监控执行

通过Flink UI监控作业运行情况:

http://localhost:8081
  1. 停止集群

作业结束后关闭本地standalone集群:

./bin/stop-cluster.sh

这提供了一个基本的PyFlink本地测试、调试、运行的工作流程。也可以部署到其他集群环境中进行生产运行。

提交到Standalone、YARN等集群

PyFlink程序可以部署到Standalone、YARN等不同的集群环境中进行生产运行。

Standalone集群

  1. 启动Flink Standalone集群

  2. 在执行环境中设置运行模式为集群:

env.set_runtime_mode(execution_mode.cluster)
  1. 设置JAR包位置:
env.add_jars("myprogram.jar") 
  1. 提交PyFlink作业,会提交到Standalone集群

YARN集群

  1. 启动YARN集群

  2. 设置执行环境为YARN模式

  3. 设置JAR包位置

  4. 设置其他YARN配置(队列等)

  5. 提交PyFlink作业到YARN集群运行

Kubernetes Session集群

启动Flink K8s Session集群后,部署方式与Standalone类似。

PyFlink可以与主流集群资源管理器无缝集成,支持弹性的生产环境部署。

调试和测试

日志和监控

PyFlink提供了日志和指标监控的功能,可以帮助观察和诊断作业运行情况。

日志

PyFlink内置log4j日志框架,支持控制台打印和文件输出。

设置日志级别:

import logging
logging.info("test logging")

指标监控

PyFlink收集了丰富的指标,可以在Web UI中查看,也可以配置推送到Prometheus。

常用指标:

Web UI

Flink Web UI显示了作业度量指标、检查点信息、异常等监控数据。

外部系统

还可以使用ELK栈进行日志分析,Prometheus等系统存储指标数据。

PyFlink的监控功能可以提供作业运行状态的全方位视图。

测试数据

PyFlink提供了一些内置的测试数据,可以用来调试和演示程序,主要包括:

集合数据

直接使用from_elements创建包含内置数据的表或流:

env.from_elements([(1, 'Hi'), (2, 'Hello')])

文件数据

从内置的文件读取测试数据:

例如:

env.read_text('words.txt')

生成数据

使用生成函数创建测试数据:

例如:

ds = env.generate_sequence(1, 100000)

连接器数据

一些连接器提供了获取测试数据的方法:

等等

PyFlink提供了丰富的测试数据源,可以方便编写和调试程序。

模块化和组件测试

在PyFlink中可以通过以下方式进行模块化和组件测试:

  1. 单元测试

使用unittest等框架,基于PyFlink的组件接口编写单元测试用例,例如对自定义函数进行独立测试。

  1. 集成测试环境
  1. 模拟数据源

使用TestSourceContext并行读取内存数据,测试流组件 chains。

  1. 测试Sink

使用TestSink验证和检查执行结果。

  1. 本地执行

在不启动整个集群的情况下,通过本地执行模式测试组件串联执行。

  1. 集群模拟

MiniClusterWithClient可以在本地启动一个最小化的集群用于测试。

  1. CI框架

结合GitHub Actions, Jenkins等实现自动化测试。

通过这些策略,可以对PyFlink程序进行全面的测试与验证,提高质量。

最佳实践

性能优化

这里我总结一下在Flink中的常见性能优化方案:

  1. 优化检查点配置
  1. 调优Task参数
  1. 数据倾斜优化
  1. 提高网络传输效率
  1. 运行时通信优化
  1. 减少序列化开销
  1. 算法调优与代码生成
  1. 优化状态后端

多方面综合调优可以显著提升Flink大规模生产环境下的执行效率。

常见问题及解决方案

Flink应用运行中常见的问题及解决方案包括:

通过日志打印和指标监控,可以定位问题原因,并根据类型采取不同的优化手段进行故障排除和性能提升。