AIGC标识 [Hadoop/Windows/Flink] 为解决windows的兼容问题,Hadoop的 winutils.exe / hadoop.dll 的作用是什么?

1 问题描述

  • 今天在本地电脑试验基于 netcat(模拟实时流) + JDK 11 + Flink 1.17 + Paimon (0.9.0) + MinIO来实现湖仓一体。但本地电脑(Windows)启动Flink作业时,报错:

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
at org.apache.flink.table.catalog.CatalogManager.createTable(CatalogManager.java:652)

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
	at org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Native Method)
	at org.apache.hadoop.io.nativeio.NativeIO$Windows.access(NativeIO.java:793)
	at org.apache.hadoop.fs.FileUtil.canRead(FileUtil.java:1249)
	at org.apache.hadoop.util.DiskChecker.checkAccessByFileMethods(DiskChecker.java:160)
	at org.apache.hadoop.util.DiskChecker.checkDirInternal(DiskChecker.java:100)
	at org.apache.hadoop.util.DiskChecker.checkDir(DiskChecker.java:77)
	at org.apache.hadoop.util.BasicDiskValidator.checkStatus(BasicDiskValidator.java:32)
	at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.confChanged(LocalDirAllocator.java:330)
	at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.getLocalPathForWrite(LocalDirAllocator.java:393)
	at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:165)
	at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:146)
	at org.apache.hadoop.fs.s3a.S3AFileSystem.createTmpFileForWrite(S3AFileSystem.java:1282)
	at org.apache.hadoop.fs.s3a.S3ADataBlocks$DiskBlockFactory.create(S3ADataBlocks.java:816)
	at org.apache.hadoop.fs.s3a.S3ABlockOutputStream.createBlockIfNeeded(S3ABlockOutputStream.java:211)
	at org.apache.hadoop.fs.s3a.S3ABlockOutputStream.<init>(S3ABlockOutputStream.java:188)
	at org.apache.hadoop.fs.s3a.S3AFileSystem.innerCreateFile(S3AFileSystem.java:1727)
	at org.apache.hadoop.fs.s3a.S3AFileSystem.lambda$create$6(S3AFileSystem.java:1646)
	at org.apache.hadoop.fs.statistics.impl.IOStatisticsBinding.lambda$trackDurationOfOperation$5(IOStatisticsBinding.java:499)
	at org.apache.hadoop.fs.statistics.impl.IOStatisticsBinding.trackDuration(IOStatisticsBinding.java:444)
	at org.apache.hadoop.fs.s3a.S3AFileSystem.trackDurationAndSpan(S3AFileSystem.java:2337)
	at org.apache.hadoop.fs.s3a.S3AFileSystem.trackDurationAndSpan(S3AFileSystem.java:2356)
	at org.apache.hadoop.fs.s3a.S3AFileSystem.create(S3AFileSystem.java:1645)
	at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:1195)
	at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:1175)
	at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:1064)
	at org.apache.paimon.s3.HadoopCompliantFileIO.newOutputStream(HadoopCompliantFileIO.java:56)
	at org.apache.paimon.fs.PluginFileIO.lambda$newOutputStream$1(PluginFileIO.java:52)
	at org.apache.paimon.fs.PluginFileIO.wrap(PluginFileIO.java:104)
	at org.apache.paimon.fs.PluginFileIO.newOutputStream(PluginFileIO.java:52)
	at org.apache.paimon.fs.FileIO.writeFile(FileIO.java:251)
	at org.apache.paimon.fs.FileIO.tryToWriteAtomic(FileIO.java:239)
	at org.apache.paimon.schema.SchemaManager.lambda$commit$9(SchemaManager.java:541)
	at org.apache.paimon.schema.SchemaManager.commit(SchemaManager.java:543)
	at org.apache.paimon.schema.SchemaManager.createTable(SchemaManager.java:172)
	at org.apache.paimon.schema.SchemaManager.createTable(SchemaManager.java:133)
	at org.apache.paimon.catalog.FileSystemCatalog.lambda$createTableImpl$7(FileSystemCatalog.java:120)
	at org.apache.paimon.catalog.FileSystemCatalog.uncheck(FileSystemCatalog.java:151)
	at org.apache.paimon.catalog.FileSystemCatalog.createTableImpl(FileSystemCatalog.java:120)
	at org.apache.paimon.catalog.AbstractCatalog.createTable(AbstractCatalog.java:247)
	at org.apache.paimon.catalog.DelegateCatalog.createTable(DelegateCatalog.java:117)
	at org.apache.paimon.flink.FlinkCatalog.createTable(FlinkCatalog.java:334)
	at org.apache.flink.table.catalog.CatalogManager.lambda$createTable$11(CatalogManager.java:663)
	at org.apache.flink.table.catalog.CatalogManager.execute(CatalogManager.java:909)
	at org.apache.flink.table.catalog.CatalogManager.createTable(CatalogManager.java:652)
	at org.apache.flink.table.api.internal.TableEnvironmentImpl.executeInternal(TableEnvironmentImpl.java:1000)
	at org.apache.flink.table.api.internal.TableEnvironmentImpl.executeSql(TableEnvironmentImpl.java:765)
	at org.example.SocketToPaimonWordCount.main(SocketToPaimonWordCount.java:68)
  • 进行深层分析,知道了:
  • Flink JAR(org.apache.flink:flink-shaded-hadoop-3-uber)整合了 Hadoop 全家桶(hadoop-common / hadoop-aws 等)
  • 由于Windows上我没有安装Hadoop环境,也没有配置HADOOP_HOME,故报上面错误。
  • 但为了解决windows的hadoop兼容问题,可以下载 winutils.exe / hadoop.dll到本地电脑,并在Flink 应用代码中(创建流式环境对象前)指定其目录作为 HADOOP_HOME 的目录。
//`winutils.exe` 提供适用于 Windows 系统 Hadoop 的 hadoop.dll 和 hdfs.dll 二进制文件。
// Windows 环境:必须指定 hadoop.home.dir,指向 winutils.exe 所在目录
// 下载地址: https://github.com/cdarlint/winutils/tree/master/hadoop-3.3.6/bin
System.setProperty("hadoop.home.dir", "D:\Program_Files\hadoop\hadoop-3.3.6");
  • 同时,还需确保windows已安装了hadoop.dll所需的 C++ 运行库补丁(常见隐性陷阱)

解释:hadoop.dll 本质上是一个用 C/C++ 编写并编译出来的 Windows 动态链接库文件(DLL)。在编译时,它是基于 Microsoft Visual StudioVC++)的环境构建的。因此,hadoop.dll依赖于 VC++ 的运行时 C 库(C Runtime Library / CRT)。
即使配置了 hadoop.dll,有时仍会报这个错误,原因是 Windows 缺少 Visual C++ Redistributable 运行库,导致 Java 无法真正加载 hadoop.dll。
解决办法:去微软官网下载并安装 Microsoft Visual C++ Redistributable (2015-2022) 64位运行库 (vc_redist.x64.exe) ,并重启电脑

  • 补充Gemini对此的建议

image

  • 好了,转回本篇关注的问题:为解决windows的兼容问题,Hadoop的 winutils.exe / hadoop.dll 的作用是什么?

2 原因分析

  • 在Windows上使用Hadoop(或依赖Hadoop的Spark、Flink、Hive等)时,winutils.exehadoop.dll 是解决"Hadoop原生是为Unix/Linux设计"这一根本矛盾的兼容性补丁。

下面分别说清楚它们各自解决什么问题。

  • 为什么缺少Visual C++ / hadoop.dll会触发 UnsatisfiedLinkError

当 Flink 运行到 Native 操作时,底层执行的逻辑:

  • JVM 尝试加载 DLL: Java 调用 System.loadLibrary("hadoop") 或尝试寻找 hadoop.dll
  • Windows 系统解析依赖: Windows 在加载 hadoop.dll 时,会检查它依赖的所有“子 DLL”。hadoop.dll 内部声明了依赖 MSVCR120.dll 或 VCRUNTIME140.dll 等 VC++ 运行库文件。
  • 依赖缺失导致静默加载失败: 如果你的系统里没有安装对应的 VC++ Redistributable,Windows 就找不到这些底层的 C 运行库,导致 hadoop.dll 根本无法被系统装载进内存。
  • Java 报出表面错误: 因为 DLL 装载失败,Java 在接下来试图调用里面的 NativeIO$Windows.access0 Native 方法时,发现找不到 C++ 函数入口,于是抛出:
java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0...

背景:Hadoop在Windows上为什么"缺东西"

  • Hadoop核心代码大量依赖POSIX语义——比如文件权限操作(chmod/chown)、进程fork、/tmp目录约定等。这些在Linux/Mac上由操作系统原生提供,但在Windows上不存在对应的系统调用

  • 为了让Hadoop能在Windows开发机上运行,Hadoop社区为Windows平台编译了两个关键二进制:

注意:主要是开发/调试/单机测试场景,生产集群依然跑Linux,

  • winutils.exe:可执行程序,桥接Windows文件系统与Hadoop期望的Unix风格文件操作
  • hadoop.dll:动态链接库,Hadoop native库的Windows实现,供JVM通过JNI调用

winutils.exe 的作用

定位%HADOOP_HOME%\bin\winutils.exe

它是一个Native Executable,主要解决Hadoop Shell和FileSystem层面对Unix命令的依赖:

  1. 文件权限模拟:Hadoop代码里到处调用FileSystem.setPermission(),底层要在Windows上模拟chmod。winutils.exe接管这些调用,把Unix权限位映射到Windows ACL
  2. 路径与符号链接:处理/tmp/hadoop-*这类Unix风格临时路径,在Windows上正确映射到C:\Users\<user>\AppData\Local\Temp\hadoop-*
  3. 被Hadoop脚本调用:Hadoop的cmd脚本启动时会调用winutils.exe来完成环境检查、目录初始化等
  4. Spark等上层框架也依赖它:Spark on Windows提交任务时,driver/executor会通过HADOOP_HOME/bin/winutils.exe做本地文件操作

经典报错 Could not locate executable null\bin\winutils.exe in the Hadoop binaries 就是Hadoop找不到这个文件——要么没设HADOOP_HOME,要么bin目录下缺winutils.exe

hadoop.dll 的作用

  • 定位%HADOOP_HOME%\bin\hadoop.dll(有时也在C:\Windows\System32\

  • 它是Hadoop native library 在Windows平台的编译产物,通过JNI被Java层调用,提供:

  1. Native IO:高性能的文件读写、内存映射,绕过JVM的IO瓶颈
  2. 压缩/编解码加速:zlib、gzip、snappy、lz4等codec的native实现(纯Java版也能用,但native版快很多)
  1. CRC32校验:native实现比Java版快一个量级
  2. Windows平台适配:把Hadoop native层对Unix API的调用转接到Windows API

如果不放hadoop.dll,Hadoop会退回到纯Java的实现,功能上能用但会有警告:

 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform...

性能敏感场景(如Spark shuffle大量数据)下,缺了这个dll会导致明显变慢。

两者的关系总结

维度 winutils.exe hadoop.dll
类型 可执行程序(.exe) 动态链接库(.dll)
调用方式 Hadoop脚本/shell调用 JVM通过JNI调用
主要职责 文件权限、路径、Shell操作 Native IO、压缩、CRC32
缺失表现 报"cannot find winutils.exe" 降级到纯Java实现,有警告

简单说:winutils.exe解决"命令行/权限层面"的Windows兼容问题,hadoop.dll解决"运行时native性能"的Windows兼容问题。两者配套使用,放在同一个%HADOOP_HOME%\bin\目录下。

实际使用建议

  1. 版本必须匹配:winutils.exe和hadoop.dll的版本要与你要用的Hadoop版本一致(如Hadoop 3.3.x就用对应3.3.x编译的版本)。版本错配可能导致诡异崩溃
  2. 获取途径
    • 从Hadoop官方发行包的bin目录获取(官方从2.x开始提供Windows二进制)
    • 或从开源镜像仓库(如gitHub.com/cdarlint/winutils)下载对应版本的预编译二进制
  3. 环境变量:必须正确设置HADOOP_HOME指向包含bin/的目录,且把%HADOOP_HOME%\bin加入PATH
  4. 仅开发场景:再次强调,这两个文件是为了让开发人员在Windows本地能跑通Hadoop/Spark程序而存在。生产集群请使用Linux,Windows上跑Hadoop伪分布式只适合学习和调试

Y 推荐文献

X 参考文献

posted @ 2026-07-27 16:00  千千寰宇  阅读(5)  评论(0)    收藏  举报