前阵子有个朋友从外地打电话过来,说单位新采购了一批复原服务器,出厂预装的全是 alinux3,可集团上层的数仓平台又指定要用 CDH 6.3.2。他在网上搜了一圈,发现 CDH 6.3.2 的官方支持列表里只写了 RHEL 7 和 CentOS 7,当场心态就炸了。第一天尝试直接装 Cloudera Manager,Agent 都装不上;第二天好不容易把 CM Server 拉起来,Parcel 下载校验又报错;第三天他差点准备把所有机器重装成 CentOS 7。其实这两年国产化操作系统替换和 CentOS 8 过渡叠加在一起,很多人都在 CentOS 8、alinux3 或者其他基于 EL8 的兼容发行版上装 CDH 6.3.2。我前后在好几套环境里把这条链路完整踩了一遍,适配方案基本稳定了,这里面的操作有不少是官方文档里找不到的,今天整理出来给需要的人省点时间。
1. 为什么在 CentOS 8 上装 CDH 6.3.2 会这么费劲
1.1 官方兼容矩阵与真实需求的冲突
先说结论:CDH 6.3.2 不是完全装不上 CentOS 8,而是 Cloudera 的整套安装链路——从 Cloudera Manager Server、CM Agent 到 Parcel 激活——都默认你跑在 EL7 上。它内部有一堆脚本会去读操作系统版本号、检查 python 解释器、找特定版本的动态库,一旦某个环节不在它预期内,就直接给你一个让人摸不着头脑的报错。
官方支持矩阵里,CDH 6.3.2 对应的是 RHEL 7 / CentOS 7 系的 7.6、7.7,数据库支持 MySQL 5.7、PostgreSQL 等。这套东西发布的时间点,CentOS 8 都还没有完全铺开,Cloudera 自然没有义务为它做适配。但现实里大家遇到 CentOS 8 / alinux3 无非三种情况:
- 企业新购服务器预装了 alinux3,为了过等保或者集团统一基线,不让你重装系统;
- 业务侧强制推进国产化操作系统替代,CentOS 7 到期之后必须迁到 EL8 系;
- 单纯的测试环境,手头只有 CentOS 8 镜像,不想再折腾 CentOS 7。
所以我们需要做的工作,其实并不是"让 CDH 支持 CentOS 8",而是"让 CDH 的安装链路自认为跑在 CentOS 7 上,同时把 EL8 系统里缺失的运行时依赖补齐"。这是个很微妙的思路,后面所有操作都是围绕它展开的。
1.2 alinux3 和 CentOS 8 到底差在哪
alinux3 全称是阿里云 Linux 3,底层基于 EL8,跟 CentOS 8 在用户态上高度一致,绝大多数 rpm 包可以直接互用。它甚至自带阿里云的 yum 源,内网环境如果开了专线访问 OSS 源,装基础依赖比原版 CentOS 8 还方便。
但有几个 EL8 系的通病需要留意:
- 默认 python 指向 python3,而 CM Agent 和 CDH 的很多脚本还依赖 python2.7;
- 默认没有安装 libnsl、ncurses-compat-libs 这类老库,CDH 里 Impala、Kudu 等组件启动时可能直接报找不到 libnsl.so.1;
- 系统自带的 openssl、glibc 版本比 EL7 新,部分在 CentOS 7 上编译好的二进制动态库依赖会不满足;
- 默认 firewalld 是随开机启动的,SELinux 也是 Enforcing,这两样不关,CM Agent 和 HDFS 角色很容易出现权限和端口问题。
我后面在文里把这些坑一个个填掉。你只要记住:凡是基于 EL8 重新构建的发行版,大体都可以参考同一套适配方法,只是个别包的名字或源位置略有差异。
2. 装系统阶段就该打好的地基
2.1 分区、主机名与初始化的三个建议
很多人在装系统的时候不重视规划,等 CDH 部署到一半才发现磁盘不够、主机名带下划线、swap 分区过大,最后哭着收场。我建议从源头就按生产标准来:
- 数据盘独立:HDFS 数据目录、Zookeeper 数据目录、MySQL 数据目录,至少各自挂一块独立磁盘。用
df -h检查挂载点,不要一股脑全扔在根分区。CDH 的 HDFS 数据目录默认是/dfs/nn、/dfs/dn,如果你根分区只有 50G,一个 10 节点集群跑两天就把盘打满了。 - 主机名规范:主机名不要出现下划线,不要以数字开头,大小写尽量统一。CDH 的 Host Inspector 对主机名解析很敏感,尤其要注意
/etc/hosts里必须把本机 IP 和 hostname、FQDN 全部对应上。我见过最多的问题就是/etc/hosts写成了127.0.0.1 localhost.localdomain localhost,然后 CM 在启动角色时按主机名找 IP,结果所有 agent 都注册到期 backup 节点上。 - swap 分区:如果内存超过 64G,swap 可以设小一点;如果内存不大,swap 设置成内存一半即可。
vm.swappiness后面会调低,但如果 swap 本身就是个几 GB 的大分区,调了也能帮你兜底内存突发压力。
2.2 网络配置分歧:NetworkManager 与静态 IP
CentOS 8 和 alinux3 默认都用 NetworkManager 管理网络,这和 CentOS 7 时代大家习惯用的 network.service 差别很大。CDH 本身不依赖网络管理工具,但它要求所有节点静态 IP、主机名可解析,所以网络配置必须稳定。
使用 NetworkManager 配置静态 IP 的方式很简单:
nmcli connection modify ens3 ipv4.addresses 192.168.10.11/24 nmcli connection modify ens3 ipv4.gateway 192.168.10.1 nmcli connection modify ens3 ipv4.dns 192.168.10.1 nmcli connection modify ens3 ipv4.method manual nmcli connection up ens3配置完之后用ip addr确认地址生效。这里有个常见的坑:如果你先配置好 IP,再修改 hostname,NetworkManager 可能会因为主机名变化把连接反复重建,所以建议顺序是——先hostnamectl set-hostname cdh01.example.com,再配置网络,最后把所有节点的/etc/hosts写好,再做一次systemctl restart NetworkManager。
另外,如果你确实更习惯老的 network-scripts,在 EL8 上需要额外安装:
dnf install network-scripts但我不太推荐在生产上这么干,因为 EL8 后续版本对 network-scripts 的支持已经降到极低优先级,保持 NetworkManager 是更省心的选择。
2.3 内核参数、防火墙、SELinux 与小工具依赖
安装 CDH 之前,每个节点上都要做几件事,不然后面排查起来会非常痛苦。
关闭防火墙和 SELinux:
systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config内核参数调整:编辑/etc/sysctl.conf,追加以下内容:
vm.swappiness=1 vm.overcommit_memory=1 net.ipv4.ip_forward=1 net.core.rmem_max=16777216 net.core.wmem_max=16777216执行sysctl -p让配置生效。其中vm.swappiness调低是避免系统频繁使用 swap,影响 HDFS 和 Impala 的读写性能;vm.overcommit_memory=1是 Impala 官方文档明确要求的,它让 Impala 在做内存分配判断时不至于因为系统内存几何级估算而拒绝启动。
关闭透明大页 THP:这是大内存集群最容易忽略的性能杀手:
echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag为了重启后依然生效,把它写进/etc/rc.local,并给 rc.local 加执行权限。
基础工具包:装 CDH 前建议把常用依赖一次性补齐:
dnf install -y psmisc perl openldap-clients dmidecode bc unzip tar wget curl \ libxslt lzo python2 libnsl ncurses-compat-libs这里重点提一下python2和libnsl,它们不是可选依赖,是 CentOS 8 / alinux3 上装 CDH 必装的兼容层。此外,如果你发现系统里缺了某个动态库,可以用ldconfig -p | grep 库名去查,再去阿里云源搜包,省去反复试错的功夫。
顺带说一句:如果你在 EL8 上开了图形界面,又一直在被"远程桌面自动注销"折磨,最简单的办法是生产集群直接不装图形界面,或者把默认启动级别改到 multi-user.target:
systemctl set-default multi-user.target我是不建议在集群节点上留 GUI 的,纯属给自己增加维护负担。
3. 骗过 Cloudera Manager:操作系统识别适配
3.1 改 redhat-release 只是第一步
Cloudera Manager 从 Server 到 Agent 再到 Parcel 激活,都会读取/etc/redhat-release来做操作系统类型识别。所以第一个要动的就是它。
备份原文件再修改:
cp /etc/redhat-release /etc/redhat-release.bak echo "CentOS Linux release 7.9.2009 (Core)" > /etc/redhat-release注意:不是只改 CM Server 那一台,是所有参与集群的节点都要改。因为 CM Agent 上报操作系统类型给 Server,Parcel 分发到每台 agent 节点时,agent 本地也要通过校验。
改完之后,有些系统工具如yum、dnf可能会读取这个文件做仓库判断,实际上影响不大,因为 yum/dnf 更多依赖/etc/os-release。如果你的发行版还有自己的/etc/os-release,不用动它,CM 基本不认这个文件。
有个容易被忽略的细节:当你在 CM 界面上做 "Add Hosts" 向导时,CM 会尝试用 SSH 连到每台新主机来装 Agent,这一步如果它检测到系统版本异常,可能在向导阶段就中断。所以不等向导报错,你在操作系统层面就把版本伪装好,后面会顺很多。
3.2 python2 兼容层是如何救命的
CDH 6.3.2 发布时,Ansible、Cloudera Manager 脚本和部分组件进程管理脚本默认走/usr/bin/python,而且往往用的是 Python 2 语法。CentOS 8 / alinux3 的默认 python 指向 python3,在安装过程中你会看到各种诡异的报错,比如:
cloudera-scm-agent启动后立刻退出,日志里写ImportError: No module named cm_client或SyntaxError;- Parcel 解压后激活失败,提示
UnicodeDecodeError; yum插件被某个脚本调用时出现 Python 运行时错误。
解决办法是显式安装 python2,并把/usr/bin/python软链到 python2:
dnf install -y python2 ln -sf /usr/bin/python2 /usr/bin/python python --version执行到最后一步,你应该看到输出Python 2.7.x。这个改动对整个系统的影响可以说非常小,因为 EL8 上很多运维脚本已经改成显式调用python3了,不会有路径冲突。但 CM 的脚本是千年不变的/usr/bin/python,所以有这个软链它才能跑起来。
如果你只想治标不治本,也可以去改 CM 脚本头部改解释器路径,但几十个脚本分布在/opt/cloudera/下面,一个个改不仅累,还容易在下次升级时被覆盖。我觉得用软链是性价比最高的方案。
3.3 离线环境下的 RPM 依赖收集与 openssh 自定义打包经验
有些政企内网环境,所有机器都不能访问公网。这种时候「在线 yum 安装」就是奢望,只能在能联网的跳板机上把依赖包全部倒腾下来,再拷贝进去。这里分享一个流程,照着做基本不会漏包。
方法一:dnf download收集指定依赖
dnf install -y dnf-plugins-core dnf download cloudera-manager-server-6.3.2-1468238.el7.x86_64.rpm \ cloudera-manager-agent-6.3.2-1468238.el7.x86_64.rpm \ --resolve --alldeps --destdir=/data/rpm_packages--resolve会把依赖全部拉下来,这个命令需要在联网的 CentOS 8 / alinux3 环境执行,然后把整个/data/rpm_packages目录打包传到内网。
方法二:先用rpm -qpR查依赖再逐个下载
rpm -qpR cloudera-manager-agent-6.3.2-*.rpm拿到依赖列表后去在线仓库逐个下载。这个方法适合你只缺一两个包的时候,效率很高。
另外,专门说一下 OpenSSH 打包 rpm 的事。很多内网安全基线要求 OpenSSH 升级到特定版本,比如修复 CVE 的版本,但 EL8 基础源里的 openssh 版本不满足要求。这时需要自行用 rpmbuild 重打包:
dnf install -y rpm-build openssl-devel zlib-devel gcc mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} tar xf openssh-9.6p1.tar.gz -C ~/rpmbuild/SOURCES/编辑 openssh.spec 时,重点检查%configure那段,加上--with-openssl路径选项,再执行rpmbuild -ba openssh.spec。生成的新 rpm 会放在~/rpmbuild/RPMS/x86_64/下。这里有个容易踩的坑:如果你在 CentOS 7 上打了这个包,拿到 CentOS 8 / alinux3 上装,很容易出现 glibc 版本兼容问题,所以建议在哪套系统上生产,就在哪套系统上构建。
4. 数据库层选 MySQL 8.0 还是 5.7?
4.1 CDH 6.3.2 对数据库的隐性要求
CDH 6.3.2 默认自带一个嵌入式的 PostgreSQL,用于 CM Server 的元数据存储。可一旦你要上生产,我强烈建议把数据库外置。原因有两点:
- CM 自带的 PostgreSQL 只有单机模式,没有备份和主从方案,挂了一次整个管理面就全凉;
- 业务上通常已经有统一的 MySQL 运维规范,接入现有 MySQL 体系比另维护一套 PG 更省事。
CDH 6.3.2 在官方文档里对 MySQL 的支持主要针对 5.7,但实际生产里我用 MySQL 8.0 跑通了好几次,关键点在于解决认证插件和 JDBC 驱动问题。如果你所在团队有条件选,优先用 MySQL 5.7,因为 CM 对它的兼容性是开箱即用的;如果由于集团数据库规范强制 MySQL 8.0,那就参考我下面的适配方案。
4.2 MySQL 8.0 认证插件与 JDBC 驱动的适配方案
MySQL 8.0 默认的认证插件是caching_sha2_password,而 CDH 内部很多组件进程——Hive Metastore、Cloudera Manager Server、Hue、Ranger——走 JDBC 连接数据库时,如果使用旧版驱动(特别是 mysql-connector-java 5.1.x),就会报Unable to load authentication plugin 'caching_sha2_password'。
解决办法有两个方向:
方向一:让 MySQL 兼容旧认证方式
在/etc/my.cnf的[mysqld]段加上:
default_authentication_plugin=mysql_native_password或者在创建用户时显式指定:
CREATE USER 'scm'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password';这样即使驱动比较旧,也能正常认证。
方向二:升级 JDBC 驱动
下载 mysql-connector-java 8.0.x 版本,放到所有需要连接 MySQL 的节点上。我建议把 jar 包统一放到两个位置:
/usr/share/java/mysql-connector-java.jar /opt/cloudera/cm/lib/mysql/mysql-connector-java.jar其中/usr/share/java/mysql-connector-java.jar是 CM 的引导脚本会主动扫描的路径,如果你不放在这里,后面执行scm_prepare_database.sh时它会提示找不到驱动。权限方面记得是cloudera-scm用户可读,最好把属主直接改成cloudera-scm:cloudera-scm。
使用 MySQL 8.0 新版驱动时,JDBC URL 里要注意两个参数:
jdbc:mysql://cdh01:3306/hive?useSSL=false&allowPublicKeyRetrieval=trueuseSSL=false:MySQL 8.0 默认开启 SSL 校验,如果你没配证书,连接会直接失败;allowPublicKeyRetrieval=true:配合caching_sha2_password认证时,需要这个参数才能允许从服务器获取公钥,否则连接过程会报 Public Key Retrieval is not allowed。
4.3 scm/hive 等库的初始化与 db.properties 配置
安装 MySQL 并启动后,先创建 CDH 需要的各个元数据库:
CREATE DATABASE scm DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE DATABASE amon DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE DATABASE rman DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE DATABASE hive DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE DATABASE sentry DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE DATABASE nav DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE DATABASE navms DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; CREATE USER 'scm'@'%' IDENTIFIED WITH mysql_native_password BY 'scm_password'; CREATE USER 'amon'@'%' IDENTIFIED WITH mysql_native_password BY 'amon_password'; CREATE USER 'rman'@'%' IDENTIFIED WITH mysql_native_password BY 'rman_password'; CREATE USER 'hive'@'%' IDENTIFIED WITH mysql_native_password BY 'hive_password'; CREATE USER 'sentry'@'%' IDENTIFIED WITH mysql_native_password BY 'sentry_password'; CREATE USER 'nav'@'%' IDENTIFIED WITH mysql_native_password BY 'nav_password'; CREATE USER 'navms'@'%' IDENTIFIED WITH mysql_native_password BY 'navms_password'; GRANT ALL PRIVILEGES ON scm.* TO 'scm'@'%'; GRANT ALL PRIVILEGES ON amon.* TO 'amon'@'%'; GRANT ALL PRIVILEGES ON rman.* TO 'rman'@'%'; GRANT ALL PRIVILEGES ON hive.* TO 'hive'@'%'; GRANT ALL PRIVILEGES ON sentry.* TO 'sentry'@'%'; GRANT ALL PRIVILEGES ON nav.* TO 'nav'@'%'; GRANT ALL PRIVILEGES ON navms.* TO 'navms'@'%'; FLUSH PRIVILEGES;之后在 CM Server 节点执行初始化脚本:
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql scm scm_password这个脚本会往scm库里写入 CM 自己的 Schema。执行前确认/etc/cloudera-scm-server/db.properties里的连接信息匹配,如果你用的是 MySQL 8.0,脚本如果因驱动找不到失败,多半是 JDBC jar 路径问题,按 4.2 里我给的路径放好再试一遍即可。
5. Cloudera Manager 部署和 Parcel 分发的完整链路
5.1 用 rpm 离线装 CM Server/Agent 的关键步骤
在线安装方式没有多少技术含量,但在内网环境我推荐把 rpm 包下载下来,用dnf localinstall去装,这样既可控又能保留安装日志。
先到 Cloudera Archive 仓库找到对应版本号的 rpm 包下载列表,主要下载四个包:
- cloudera-manager-daemons
- cloudera-manager-server
- cloudera-manager-agent
- cloudera-manager-server-db(如果要用自带 PG 才装,生产环境可跳过)
安装顺序:先装 daemons,再装 server 和 agent:
dnf localinstall -y cloudera-manager-daemons-6.3.2-*.el7.x86_64.rpm dnf localinstall -y cloudera-manager-server-6.3.2-*.el7.x86_64.rpm dnf localinstall -y cloudera-manager-agent-6.3.2-*.el7.x86_64.rpmdaemons 是 CM Server 和 Agent 共用的运行环境,里面包含了脚本、库文件、默认配置。装上之后在 CM Server 节点启动:
systemctl start cloudera-scm-server systemctl start cloudera-scm-agentAgent 节点上只需要安装 daemons 和 agent 两个包,然后把/etc/cloudera-scm-agent/config.ini里的server_host改成 CM Server 的主机名或 IP:
server_host=cdh01.example.com再启动 agent。启动后去 CM Server 节点上看日志:
tail -f /var/log/cloudera-scm-server/cloudera-scm-server.log看到类似“Started Jetty server”的日志就说明 Server 起来了。如果一直卡在初始化阶段,大概率是数据库连接或者 JDBC 驱动的问题,回到第 4 章排查。
5.2 Parcel 仓库的放置、校验与 HTTP 分发
Parcel 是 CDH 分发组件的打包格式,它在 CM 界面里叫"Parcel",本质是一个.parcel文件加一个manifest.json。你需要下载 CDH-6.3.2 的 EL7 parcel 包,注意这里用的是el7.parcel,不是 el8 或 el6。
mkdir -p /opt/cloudera/parcel-repo cd /opt/cloudera/parcel-repo wget https://archive.cloudera.com/cdh6/cdh/6/CDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel wget https://archive.cloudera.com/cdh6/cdh/6/manifest.json chown cloudera-scm:cloudera-scm /opt/cloudera/parcel-repo/*放好之后,先用 sha256 校验一遍:
sha256sum CDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel把结果去manifest.json里搜一下,确认一致。不要跳过这步,很多内网用网盘转披的 parcel 文件容易被截断,校验不过直接激活失败,而且是那种毫无提示的失败。
接下来打开 CM 管理界面:主机 → Parcel → 添加新 Parcel,选择"本地仓库"路径,CM 会自动读取/opt/cloudera/parcel-repo下的文件。点击"下载"后 CM 会把 parcel 分发到所有 agent 节点的/opt/cloudera/parcels下。如果你节点很多,又走公网下载,速度会很感人。我的经验是在 CM Server 节点直接用 nginx 把 parcel-repo 目录暴露成 HTTP 服务,然后在 CM 界面填远程仓库 URL,这样内网节点之间走千兆网口,分分钟跑完。
dnf install -y nginx cat > /etc/nginx/conf.d/parcel.conf <<'EOF' server { listen 8080; root /opt/cloudera/parcel-repo; autoindex on; } EOF systemctl start nginx5.3 创建集群时容易被忽略的角色分配与目录权限
Parcel 激活之后,进入集群创建向导。这一步我见过太多人图省事一路下一步,结果后续全部返工。
几个关键点:
- 角色分配:建议把 NameNode、ResourceManager、ZooKeeper 分散到不同节点,避免单节点故障时整个集群管理面全挂。小规模集群可以接受一台物理机上多个角色,但至少把 HDFS NameNode 和 YARN ResourceManager 分开。
- 目录权限:HDFS 的数据目录最好单独创建,比如
/data/dfs/nn、/data/dfs/dn。CM 会提示目录为空、属主为hdfs:hdfs。如果是自己手动 mkdir,记得执行:
mkdir -p /data/dfs/nn /data/dfs/dn chown -R hdfs:hdfs /data/dfs/nn /data/dfs/dnHive Metastore 数据库配置:向导中让你填 Hive Metastore 数据库时,JDBC URL 按我在 4.2 提到的带
useSSL=false&allowPublicKeyRetrieval=true的格式填。很多人在这步卡到怀疑人生,其实就是连接串少了参数。Spark 日志目录:Spark on YARN 模式下,
spark.eventLog.dir建议配置为 HDFS 路径hdfs://cdh01:8020/user/spark/spark2History,并预先创建好 HDFS 目录,否则跑到第一个 Spark 作业时 History Server 各种报错。
6. 首次部署后必踩的高频问题与完整排查思路
6.1 从"角色启动失败"到 systemd 单元日志的分析链路
几乎每个第一次在 EL8 上装 CDH 的人,打开 CM 界面都会看到一堆角色是红色状态。这时候别慌,按下面的链路排查。
第一步,去/var/log/cloudera-scm-agent/cloudera-scm-agent.log看 Agent 的状态。如果 Agent 没正常连上 Server,CM 界面显示的主机状态就是"托管中"或"坏"。常见报错是Exec format error或者python2相关的 import 错误,前者多半是你没装 python2 或软链没建立,后者多半是系统python指到了 python3。
第二步,看具体角色的运行日志。比如 HDFS 的 DataNode 起不来,在 CM 界面点角色 → 查看日志,或直接翻/var/log/hadoop-hdfs/hadoop-hdfs-datanode-<hostname>.log。如果是libnsl.so.1: cannot open shared object file,就到节点上补装:
dnf install -y libnsl ncurses-compat-libs第三步,用 systemd 的 journal 看进程退出原因:
journalctl -u cloudera-scm-agent -n 200如果是权限问题,日志里会写Permission denied,大概率是 SELinux 没关或者/opt/cloudera目录属主不对。我遇到过一次特别隐蔽的情况:CM 升级后,/opt/cloudera/parcels下多了一层目录,导致 agent 读到两个 CDH 版本,手动把老目录删掉再systemctl restart cloudera-scm-agent就好了。
6.2 MySQL 连接失败、Redis 连不上的共同根因:端口与 hosts
很多人在集群刚搭好时,跑去验证某个独立组件,发现 Redis 连不上、MySQL 也连不上,第一反应是"是不是 CDH 影响了网络"。其实大多数情况下是端口监听和 hosts 解析的问题。
MySQL 连接失败的经典报错是Cannot connect to MySQL server (110)。这个 110 是Connection timed out的 errno,排查顺序:
- 看看 MySQL 是不是只监听 127.0.0.1:
ss -lntp | grep 3306如果是127.0.0.1:3306,那其他节点当然连不上。需要改/etc/my.cnf里的bind-address=0.0.0.0,重启 MySQL。
- 检查防火墙是否真的关干净了:
systemctl status firewalld firewall-cmd --state如果 firewalld 又在运行,先放行 3306 端口或再次彻底关闭。
Redis 连不上的逻辑完全一样。Redis 默认bind 127.0.0.1且启用protected-mode yes,只允许本机连。如果你要让 CDH 某台节点连接 Redis,必须改配置:
bind 0.0.0.0 protected-mode no然后重启 redis。这两个问题经常被当成"网络问题"去抓包,其实十分钟就能查完。
6.3 ulimit、swappiness、THP 对集群稳定性的影响
集群跑起来之后,真正影响稳定性的往往是那些"看起来无关紧要"的系统参数。
CM 界面的 Host Inspector 会提示 ulimit 值不满足,比如ulimit -n建议至少 65536。解决办法:
cat >> /etc/security/limits.conf <<'EOF' * soft nofile 65536 * hard nofile 65536 * soft nproc 65536 * hard nproc 65536 EOF但如果角色进程是通过 systemd 拉起,limits.conf可能不完全生效,需要给对应 service 单元加 override。不过 CDH 的角色由 CM 托管的进程管理,通常继承 agent 的 ulimit,所以把 agent 的 systemd 单元也加上限制:
mkdir -p /etc/systemd/system/cloudera-scm-agent.service.d cat > /etc/systemd/system/cloudera-scm-agent.service.d/limits.conf <<'EOF' [Service] LimitNOFILE=65536 LimitNPROC=65536 EOF systemctl daemon-reload systemctl restart cloudera-scm-agent再说到 THP,如果你没有按第 2 章的方法关闭透明大页,集群跑了几天后,DataNode 会频繁出现因为内存碎片导致的分配失败,特别是 Impala 这种大内存常驻进程,直接表现为进程反复 OOM。关闭 THP 后最好再重启一次集群角色,让内存重新统一切换到普通页表模式。
vm.swappiness的作用我在内核参数里提过,这里再补一句:如果节点内存不充裕,swappiness 调太低会让系统宁可回收页缓存也不换出内存,反而拖慢读写。所以不要无脑调到 0,建议 1 或 10 即可,CDH 默认建议是 10 以下。
7. 上线前的几个收尾动作
7.1 健康检查的第一轮该看什么
激活集群、所有服务变绿之后,先别急着上业务。我会按这个顺序做第一轮检查:
- 在 CM 首页看绿色/黄色告警,逐个点开,黄色的不用慌,红色的必须处理。最常见的黄色是"磁盘空间低于阈值"和"文件描述符数量过多",前者检查数据盘挂载,后者按 6.3 配置好 ulimit 即可。
- 跑一次 HDFS 自带的校验:
hdfs fsck / -files -blocks -locations重点看有没有损坏的块。如果不行,说明磁盘或网络有问题,趁早换盘。
- 跑一次简单的 MR 或 Spark 作业验证资源调度:
yarn jar /opt/cloudera/parcels/CDH/lib/hadoop-mapreduce/hadoop-mapreduce-examples.jar pi 4 1000如果 YARN 分配资源失败,去看 ResourceManager 日志和 NodeManager 日志,多半是内存配置超了物理机实际可用内存,回到 CM 的 YARN 配置里调低yarn.nodemanager.resource.memory-mb。
- Hive 验证一条简单查询,确认 Metastore 连接正常。不进查询界面,直接用 beeline:
/opt/cloudera/parcels/CDH/bin/beeline -u "jdbc:hive2://cdh01:10000" -e "show databases;"如果报数据库连接错误,优先回到 MySQL 授权和 JDBC 驱动上检查。
7.2 快照、备份与监控建议
正式环境接入业务前,我强烈建议做三件事:
第一,给所有节点打虚拟机快照。不用多说,CDH 最怕的是装到一半想回滚却发现没有还原点。
第二,备份 CM Server 的元数据库和配置。CM 的scm库里不仅有集群配置,还有租户信息、角色分配,丢失后恢复的代价极高。可以配置每天凌晨用mysqldump把scm、hive两个库导出来,保留最近 7 天即可。
第三,配置一套告警通道。即使你不用 CM 自带的邮件告警,也建议至少把监控端口暴露到 Zabbix/Prometheus 体系里。大集群里我踩过的坑是:某个 DataNode 磁盘满了,CM 有告警但没人及时看邮箱,最后整个 HDFS 进入安全模式。所以告警要接即时通信或短信通道,不要只靠邮件。
7.3 我个人的一点体会
这套 CDH 6.3.2 在 CentOS 8 / alinux3 上的安装方案,本质就是"版本伪装 + 兼容库补齐 + 数据库适配"三个动作的组合。跑通之后,只要不去做系统大版本升级、不重装 glibc、不乱删/etc/redhat-release,集群日常稳定性跟 CentOS 7 上没什么差别。
最后分享一个我自己留的小技巧:在所有节点上保留一份/etc/redhat-release.bak,同时在运维文档里写清楚哪个节点改过系统版本。否则过几个月你接手的人,看到系统版本显示 CentOS 7 但底层明明是 alinux3,会百思不得其解。
如果你刚好也在折腾这套东西,按照上面的顺序一步步来,大概率一天之内能把集群拉到全绿状态。要是遇到别的报错,先把日志看透再动手,别一上来就重装系统——至少我的经验里,绝大多数问题都不是系统本身的锅。