文章

CentOS 6.7 上消除 Hadoop “Unable to load native-hadoop library” 警告:从定位到编译替换一条龙

环境:CentOS 6.7(glibc 2.12)、Hadoop 2.6.5
目标:消除执行 hadoop fs ... 时出现的警告:
WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable


1. 问题现象

在创建 HDFS 目录时:

hadoop fs -mkdir /myhive2

出现警告:

WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

这个警告的含义是:Hadoop 没有成功加载 native(C/C++)库,于是退回到纯 Java 实现。


2. 初步判断:native 库到底有没有?

先看 $HADOOP_HOME/lib/native

ls -l $HADOOP_HOME/lib/native

我这边能看到:

  • libhadoop.so -> libhadoop.so.1.0.0

  • libhdfs.so -> libhdfs.so.0.0.0

说明 库文件本身存在,但仍然无法加载,问题大概率在:

  1. JVM/动态链接器找不到库或依赖

  2. 库和系统不兼容(最典型:glibc 版本不匹配)


3. 关键定位:ldd 报 GLIBC 版本不满足

我用 ldd 检查 libhadoop.so

ldd $HADOOP_HOME/lib/native/libhadoop.so.1.0.0 | egrep "not found|GLIBC"

得到致命信息:

/lib64/libc.so.6: version `GLIBC_2.14' not found

这就说明:当前 libhadoop.so 是在需要 glibc 2.14 的系统上编译的,而我这台机器是 CentOS 6.7,glibc 版本更低。


4. 进一步确认:系统 glibc 版本是多少?

cat /etc/redhat-release
ldd --version | head -n 1

输出:

  • CentOS release 6.7 (Final)

  • glibc 2.12

再看系统实际提供的符号版本:

strings /lib64/libc.so.6 | grep -E 'GLIBC_2\.(1[0-2])' | tail

结果包含 GLIBC_2.10/2.11/2.12,但 没有 GLIBC_2.14

这也解释了一个常见误区:
yum update glibc 只能更新 2.12 的 release(修补版),并不会把 CentOS 6 的 glibc 升到 2.14。


5. 解决思路:让 native 库在本系统上可用

既然核心矛盾是 glibc 不兼容,那解决方案就很清晰:

  • ✅ 推荐:在 CentOS 6.7 上重新编译 Hadoop 2.6.5 native(生成只依赖 GLIBC_2.12 的 .so

  • ✅ 或者:直接找一套在 CentOS 6 上编译好的 native 目录替换

  • ❌ 不推荐:强行升级系统 glibc 到 2.14(风险极高,可能把系统“地基”搞崩)

我选择了 重新编译 Hadoop 2.6.5 的 native


6. 重新编译 Hadoop native:过程中的坑与修复

6.1 先装 Maven(CentOS 6 默认源没有 maven)

我手头有 apache-maven-3.6.3-bin.zip,安装方式如下:

yum -y install unzip
mkdir -p /opt
cd /opt
unzip -q /root/apache-maven-3.6.3-bin.zip
ln -sfn /opt/apache-maven-3.6.3 /opt/maven

cat >/etc/profile.d/maven.sh <<'EOF'
export MAVEN_HOME=/opt/maven
export PATH=$MAVEN_HOME/bin:$PATH
EOF
source /etc/profile.d/maven.sh

mvn -version

6.2 Javadoc 构建失败:直接跳过

用 JDK8 构建 Hadoop 2.6.5 时,hadoop-annotations 会因为 javadoc HTML 更严格而失败。解决办法:跳过 javadoc

mvn -Pdist,native -DskipTests -Dtar -Dmaven.javadoc.skip=true clean package

6.3 下载依赖“卡住”:配置 Maven 镜像

构建过程中会下载大量依赖,我用阿里云 Maven 镜像加速(注意必须有 <settings> 根节点):

~/.m2/settings.xml

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
  <mirrors>
    <mirror>
      <id>aliyunmaven</id>
      <mirrorOf>*</mirrorOf>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>
</settings>

6.4 protoc 缺失:手动编译 protobuf 2.5.0

构建失败提示:

Cannot run program "protoc": No such file or directory

CentOS 6 的源里也没有 protobuf-compiler,于是我选择编译安装 protobuf 2.5.0(带 protoc):

# 解压源码 protobuf-2.5.0.tar.gz 后
cd protobuf-2.5.0
./configure --prefix=/usr/local
make -j$(nproc)
make install
ldconfig

/usr/local/bin/protoc --version

并确保 /usr/local/bin 在 PATH:

echo 'export PATH=/usr/local/bin:$PATH' >/etc/profile.d/localbin.sh
source /etc/profile.d/localbin.sh

6.5 Ant 下载 Tomcat 反复卡:手动放置到 downloads 目录

构建过程中(KMS/HttpFS)会通过 Ant <get> 下载 Tomcat 6.0.41:

  • hadoop-common-project/hadoop-kms/downloads/

  • hadoop-hdfs-project/hadoop-hdfs-httpfs/downloads/

这两个目录是分开的,所以会“下载两次”。做法是 手动下载一次,然后软链接/复制到另一个目录


7. 找到新编译的 native 库并验证 GLIBC 版本

编译完成后我用 find 定位 libhadoop.so

cd /root/hadoop-2.6.5-src
find . -name 'libhadoop.so*' -o -name 'libhdfs.so*' | head -n 50

最终选择发行版目录里的这份:

./hadoop-dist/target/hadoop-2.6.5/lib/native/libhadoop.so.1.0.0

验证其依赖的 GLIBC:

strings ./hadoop-dist/target/hadoop-2.6.5/lib/native/libhadoop.so.1.0.0 \
  | grep GLIBC_ | sort -V | tail -n 10

输出最高只有:

GLIBC_2.12

✅ 这正是我需要的(兼容 CentOS 6.7)。


8. 替换现网 Hadoop 的 native 并验证

8.1 备份并替换

export HADOOP_HOME=/usr/local/hadoop-2.6.5

mv $HADOOP_HOME/lib/native $HADOOP_HOME/lib/native.bak.$(date +%F)

mkdir -p $HADOOP_HOME/lib/native
cp -a /root/hadoop-2.6.5-src/hadoop-dist/target/hadoop-2.6.5/lib/native/* \
  $HADOOP_HOME/lib/native/

echo "$HADOOP_HOME/lib/native" > /etc/ld.so.conf.d/hadoop.conf
ldconfig

确保 hadoop-env.sh 里有:

export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export HADOOP_OPTS="$HADOOP_OPTS -Djava.library.path=$HADOOP_HOME/lib/native"

8.2 验证 native 已加载

hadoop checknative -a

看到关键行:

hadoop:  true /usr/local/hadoop-2.6.5/lib/native/libhadoop.so.1.0.0
snappy:  true ...
zlib:    true ...
openssl: true ...

再执行:

hadoop fs -mkdir /myhive2

不再出现 NativeCodeLoader 警告(如果目录已存在则提示 File exists 属正常行为)。


9. 分发到多台 slave(只同步 native,避免覆盖配置)

为了让集群其他节点也不再告警,我采用“只分发 native”方案:

master 上打包并 scp

cd /usr/local/hadoop-2.6.5
tar czf /tmp/hadoop-2.6.5-native-centos6.tgz -C lib native

for h in slave1 slave2 slave3; do
  scp /tmp/hadoop-2.6.5-native-centos6.tgz root@$h:/tmp/
done

每台 slave 上替换并验证

HADOOP_HOME=/usr/local/hadoop-2.6.5

mv $HADOOP_HOME/lib/native $HADOOP_HOME/lib/native.bak.$(date +%F_%H%M%S)
tar xzf /tmp/hadoop-2.6.5-native-centos6.tgz -C $HADOOP_HOME/lib
echo "$HADOOP_HOME/lib/native" > /etc/ld.so.conf.d/hadoop.conf
ldconfig

$HADOOP_HOME/bin/hadoop checknative -a

10. 总结

这次问题的核心不是“没有 lib/native 文件”,而是:

  • native 库与系统 glibc 不兼容GLIBC_2.14 not found

  • CentOS 6 只能稳定提供 glibc 2.12,所以必须:

    • 换一份在 CentOS 6 上编译的 native

    • 或在本机重新编译(最终我选择了这条)

最终效果:

  • hadoop checknative -a 显示 hadoop: true

  • hadoop fs ... 不再出现 NativeCodeLoader WARN

  • 分发到 slave 后全节点一致生效


如果你也在 CentOS 6 上折腾 Hadoop native,建议直接记住一句话:

遇到 GLIBC_x.y not found,别纠结 Hadoop 配置,先确认 native 库是在哪个系统上编译的。

许可协议:  CC BY 4.0