[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 Studio(VC++)的环境构建的。因此,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对此的建议

- 好了,转回本篇关注的问题:为解决windows的兼容问题,Hadoop的 winutils.exe / hadoop.dll 的作用是什么?
2 原因分析
- 在Windows上使用Hadoop(或依赖Hadoop的Spark、Flink、Hive等)时,winutils.exe 和 hadoop.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命令的依赖:
- 文件权限模拟:Hadoop代码里到处调用
FileSystem.setPermission(),底层要在Windows上模拟chmod。winutils.exe接管这些调用,把Unix权限位映射到Windows ACL - 路径与符号链接:处理
/tmp/hadoop-*这类Unix风格临时路径,在Windows上正确映射到C:\Users\<user>\AppData\Local\Temp\hadoop-* - 被Hadoop脚本调用:Hadoop的cmd脚本启动时会调用winutils.exe来完成环境检查、目录初始化等
- 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层调用,提供:
- Native IO:高性能的文件读写、内存映射,绕过JVM的IO瓶颈
- 压缩/编解码加速:zlib、gzip、snappy、lz4等codec的native实现(纯Java版也能用,但native版快很多)
- CRC32校验:native实现比Java版快一个量级
- 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\目录下。
实际使用建议
- 版本必须匹配:winutils.exe和hadoop.dll的版本要与你要用的Hadoop版本一致(如Hadoop 3.3.x就用对应3.3.x编译的版本)。版本错配可能导致诡异崩溃
- 获取途径:
- 从Hadoop官方发行包的
bin目录获取(官方从2.x开始提供Windows二进制) - 或从开源镜像仓库(如
gitHub.com/cdarlint/winutils)下载对应版本的预编译二进制
- 从Hadoop官方发行包的
- 环境变量:必须正确设置
HADOOP_HOME指向包含bin/的目录,且把%HADOOP_HOME%\bin加入PATH - 仅开发场景:再次强调,这两个文件是为了让开发人员在Windows本地能跑通Hadoop/Spark程序而存在。生产集群请使用Linux,Windows上跑Hadoop伪分布式只适合学习和调试
Y 推荐文献
X 参考文献
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

浙公网安备 33010602011771号