pyflink连接hadoop异常处理
异常明细
Caused by: org.apache.flink.core.fs.UnsupportedFileSystemSchemeException: Could not find a file system implementation for scheme 'hdfs'. The scheme is not directly supported by Flink and no Hadoop file system to support this scheme could be loaded. For a full list of supported file systems, please see https://nightlies.apache.org/flink/flink-docs-stable/ops/filesystems/.
介绍
之前在接触checkpoint时,flink官网中说明,cp建议存储在分布式文件系统中,有介绍使用时直接配置 hdfs 相关地址就行,
例如配置 hdfs://localhost:9000/test/cp_test
, 当时因为本地ide中运行时一直无法使用,提示上述的异常, 这个提示其实是缺失hadoop相关 jar包导致的,
在服务器上运行时因为有hadoop环境,且是提交yarn执行,
按照官网yarn提交运行地提示
在 /etc/profile
中配置后服务器上可以运行
export HADOOP_CLASSPATH=`hadoop classpath`
所以当时是 服务器运行正常,本地无法使用, 当时以为是因为本地没有hadoop环境导致的
最近又碰到有同学本地有 hadoop
的情况下提示这个问题,于是想一探究竟
HADOOP_ClASSPATH 的值是什么
本质上是一堆hadoop jar包的地址
# 服务器上运行
hadoop classpath
flink 为啥要配置 hadoop的jar地址
有时flink需要hadoop,但是它自身里面又不包含它的jar
- flink 可以提交到yarn集群来管理
- flink 支持 hdfs 分布式文件格式,例如它的 checkpoint 直接就可以存储到 hdfs中
- 关键是 flink本身把 hadoop相关包分离出来了,这个建议去看flink的发布记录,里面有记录为啥分离及何时分离
pyflink 怎么将 hadoop相关jar包加载进来
这里我是在使用pyflink时对该问题的解决; 有两种方法
-
使用封装好的全包装 jar包,例如
flink-shaded-hadoop-2-uber.jar
- 本地运行时将其放到 pyflink安装目录对应 lib中
- 提交到服务器集群中运行,放置到对于flink安装目录的 lib中
-
使用 hadoop 安装包中 jar包
- 环境变量中配置
HADOOP_ClASSPATH
- 环境变量中配置
pyflink 何时加载 hadoop 的jar
这里之所有想问这个问题,因为在我已经知道flink缺 jar 的情况下,解决方案就是把 jar 给flink加上,
- 尝试通过 add_jar的方式加载
flink-shaded-hadoop-2-uber.jar
时:不行 - 将jar放置在pyflink安装目录对于lib中: 可以
于是我感觉pyflink对于加载hadoop的jar相关时机肯定很重要
要理解这一点,要翻翻pyflink何时加载 HADOOP_ClASSPATH
的源码了
-
结果发现在初始化env(StreamExecutionEnvironment)时就通过调用函数
construct_hadoop_classpath
已经进行了 hadoop_classpath的使用逻辑,所以加载hadoop_classpath要在env初始化之前 -
事实上文档中也有所提示在文档高级配置篇中它又有这么一段话
如果你想在Hadoop中使用Flink,你需要有一个包含Hadoop依赖项的Flink设置, 而不是添加Hadoop作为应用程序依赖项。换句话说,Hadoop必须是一个依赖项 Flink系统本身,而不是包含应用程序的用户代码。Flink将使用 由HADOOP_CLASSPATH环境变量指定的Hadoop依赖项,可以这样设置
所有对于 pyflink 加载hadoop包应该是系统启动时初始之前就要准备好jar包了,等到env初始化好之后在add_jar已经没有用了
示例
from pyflink.datastream import StreamExecutionEnvironment
import os
def construct_local_hadoop_classpath(lib_base):
"""
加载遍历 hadoop jar包,或者直接在目录下放一个 flink-shaded-hadoop-2-uber.jar
Args:
lib_base:
Returns:
"""
import glob
dir_list = ["client", "common", "hdfs", "tools", "yarn", "mapreduce"]
test_jar_patterns = [lib_base + os.sep + x + os.sep + "*" for x in dir_list]
test_jars = []
for pattern in test_jar_patterns:
pattern = pattern.replace("/", os.path.sep)
test_jars += glob.glob(pattern)
return os.path.pathsep.join(test_jars)
def test():
# 加载hadoop的jar包
# 如果本地能直接执行hadoop命令,
# os.environ["HADOOP_CLASSPATH"] = os.popen("hadoop classpath").read()
# 如果本地不能直接运行hadoop命令,就自己组装
os.environ["HADOOP_CLASSPATH"] = construct_local_hadoop_classpath(
"/Users/faron/Documents/install/hadoop-3.3.6/share/hadoop")
env = StreamExecutionEnvironment.get_execution_environment()
env.set_parallelism(1)
hdfs_path = "hdfs://localhost:9000/test/a.log"
data_stream = env.read_text_file(hdfs_path)
data_stream.print()
env.execute()
if __name__ == '__main__':
test()