聊到CDH及软件安装部署,我脑海里最先冒出来的不是安装成功后的绿色对勾,而是去年在一家客户现场,整整一周都在和parcel下载较劲的那个画面。当时机房没有外网,安装包是拷进内网的,结果agent连上Cloudera Manager后,界面一直显示“正在下载分布式软件包”,进度条半天不动,那种焦虑做过的人都懂。本文就是围绕CDH及软件安装部署这件事,把我从环境准备、安装链路、验证排错到上线调优的完整过程写出来。适合准备自建大数据平台的数据工程师、运维同学,也适合只在网上看过别人搭集群、自己还没完整走一遍的初学者。
1. 为什么我把核心组件选型压在了CDH这套发行版上
1.1 版本碎片化带来的兼容性成本
早期搭Hadoop集群,最痛苦的其实不是安装本身,而是把一堆开源组件拼在一起。今天拉一个Hadoop 2.7的包,明天装一个Hive 2.1的版本,后天再遇到Spark和Hive的shaded版本冲突,整个集群就像一辆每个零件都来自不同厂商的拼装车,跑起来也不知道什么时候会散。我见过不少人花了一周时间把组件全都装好,最后卡在Spark读取Hive元数据时的类冲突上,光是排查compatible版本就用了三天。
CDH这套发行版解决的,正是这个问题。它把Hadoop生态里的HDFS、YARN、Hive、HBase、Impala、Kafka等组件统一打成一个大版本包,官方已经把相互之间的依赖关系仲裁过了。你装CDH 6.3.x的时候,拿到的Hive、HDFS、Spark、ZooKeeper等都是一套经过验证的版本组合,不用自己逐个去查兼容性矩阵。
1.2 CDH的核心价值在于“版本仲裁”和统一管理
很多人以为CDH就是“把开源软件打了个包”,其实不止。它真正值钱的地方是两个:一个是上面说的版本仲裁,另一个是Cloudera Manager这套管理工具。CM会把所有节点的Agent统一连接起来,组件安装、配置下发、角色启停、监控报警、滚动升级都可以在Web界面上完成。
举个例子,你手动部署三台节点的HDFS,要改core-site.xml、hdfs-site.xml、slaves文件,还要一台台同步、一台台重启。在CM里,你在界面上改完配置点“应用”,它会自动下发到集群中所有相关主机并重启受影响角色,省掉的不只是敲命令的时间,更重要的是避免了“某一台漏改”的低级错误。parcel的分发机制也很有意思,它把所有组件打包成一个二进制分发单元,CM把包分发到每台节点后统一解压,这样就能保证所有主机上跑的是完全一致的组件版本。
1.3 什么场景适合、什么场景不建议
我做了几个项目后的判断是,CDH非常适合三类场景:
- 传统企业内网或私网环境,下载外网包不方便,需要离线部署;
- 业务方要求快速交付、稳定优先,不希望团队成员花大量时间搞版本仲裁;
- 已有的自建集群需要平滑升级,用CM的滚动升级能减少业务中断时间。
但也有不适合的情况。如果你所在团队是深度定制Hadoop源码、要改底层内核,或者整个基础设施已经全面容器化,倾向直接用Kubernetes来管理,那么原生开源组件搭配自动化运维工具可能更顺手。CDH在容器上跑不是不行,但毕竟它的管理优势是围绕物理机和虚拟机设计出来的,硬搬到容器里反而会浪费掉一部分能力。
工具选型这件事,不是越“新”越好,而是越适合现状越好。
| 对比维度 | CDH发行版 | 自编译/原生组件拼装 |
|---|---|---|
| 组件兼容性 | 官方仲裁过,省心 | 需要自己逐个验证 |
| 安装运维 | CM统一管理,界面操作 | 手动配置,脚本维护 |
| 离线部署 | 支持,parcel机制成熟 | 依赖镜像制作水平 |
| 二次开发 | 改动源码困难 | 自由但维护成本高 |
| 适合规模 | 几台到几百台都能覆盖 | 更适合强定制小规模 |
2. 部署前四个决定成败的细节:硬件、JDK、外部数据库、离线仓库
2.1 硬件规划与系统初始化:先关掉那些“看不见的坑”
规划阶段最容易被忽视的,不是CPU和内存,而是系统底层的默认参数。CDH对操作系统的要求不算苛刻,生产环境我用过CentOS 7.6和7.9,内核版本保持默认都没有问题。但有几个参数必须提前处理,否则安装到一半会莫名其妙出故障。
首先关闭SELinux。安装部署阶段如果开着SELinux,agent和server之间的通信经常会因为策略限制出现奇怪的问题,比如parcel解压权限失败、进程无法监听端口等。折腾一圈发现是SELinux拦截,非常浪费时间。
其次是防火墙。内网环境如果确定没有外部访问需求,最简单的做法就是禁掉firewalld;如果公司安全要求必须开着,那就把必需的端口放行。7180是CM前端Web页面端口,7182是agent和server通信端口,8020或9000是NameNode RPC端口,50070(HDFS 2.x)或9870(HDFS 3.x)是NameNode Web UI,8088是YARN的ResourceManager Web UI。
还有个很容易被忽略的透明大页(THP)问题。CDH的官方文档明确建议关闭THP,因为大数据组件大量使用内存映射文件,THP的内存合并策略会让类似HBase这类延迟敏感型服务的响应时间变得很不稳定。执行方式很简单:
echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag不过这个修改重启后会失效,需要写进/etc/rc.local,确保开机自动设置。
swap也要调整。建议把vm.swappiness设为1或直接关掉,否则节点内存紧张时系统会频繁把进程换到swap分区,最直接的表现就是DataNode或NodeManager的响应延迟突增。
最后是时间同步。很多初学者会忽略NTP,但Kerberos、HDFS租约、CM的健康检查全都依赖一致的时间。集群里哪怕只有一台节点时间偏差超过几十秒,都会看到一堆莫名其妙的“连接超时”或“块丢失”告警。部署前把所有节点的chrony或ntpd配置好、确认时间源可用,这个步骤一定要排在前面。
硬件方面,我的建议是CM Server节点单独放一台机器,不要和NameNode挤在一起。CM Server本身不承担计算任务,但它需要和所有agent保持长连接,还要维护大量监控数据,内存建议16GB起步。NameNode节点内存要按元数据量估算,如果集群里有几十万个文件、上百万个Block,堆内存给到32GB并不过分。DataNode节点内存可以稍微宽松,但每台至少8GB以上,同时数据磁盘建议单独挂载。
2.2 JDK版本:别再让系统自带Java捣乱
CDH对JDK版本有明确要求,我用的CDH 6.x系列标配JDK 8,CDH 7.x部分组件也能跟上JDK 11,但为了避免麻烦,我在CDH 6.x上统一使用Oracle JDK 8或OpenJDK 8。
常见问题出在系统预装的OpenJDK上。CentOS默认会装OpenJDK,但版本可能是1.7或1.11,直接拿来跑Cloudera Manager很可能起不来。更麻烦的是,有些机器上存在多个Java版本,JAVA_HOME指向不统一,CM的各个服务启动时各找各的Java,环境变量互相打架。
我的操作习惯是:先卸载系统自带的OpenJDK,然后手动安装JDK 8到统一目录,比如/usr/local/java/jdk1.8.0_xxx。同时会用alternatives命令把java、javac指向新安装的路径。还有一个地方容易漏,就是/etc/profile和/etc/environment里的JAVA_HOME,必须全局生效,不要只在某个用户的.bashrc里写。
判断Java是否准备好,不要只看java -version,还要检查javac版本和编译工具完整性。因为Cloudera Manager的许多组件初始化时会调用javac编译临时代码,缺了编译环境会触发一些比较隐蔽的错误。
2.3 外部数据库:CM的“大脑存储”
CDH安装向导中会让你选择数据库类型,CM默认支持内嵌的PostgreSQL或者外置的MySQL/MariaDB。我强烈建议用外置MySQL,不要用默认的内嵌数据库。原因是CM不仅存配置信息,还有大量监控数据、历史告警、报告数据都落在库里,默认的Derby或者内嵌PostgreSQL在这种压力下表现不好,而且数据量大了以后几乎没法迁移。
数据库规划时,我习惯在一台单独的机器上安装MySQL 5.7。CDH 7.x也支持MySQL 8,但6.x时代我用的都是5.7,稳定。部署前需要为CM创建对应的账号和数据库。我通常会创建名为cm的数据库和一个具有全部权限的cmadmin账号,密码强度别设得太复杂,因为安装脚本会在命令行参数里出现,复杂的特殊字符反而容易让命令解析出错。
MySQL安装完成后,记得下载MySQL JDBC驱动,把mysql-connector-java.jar放到CM Server节点的/usr/share/java/目录下,并重命名成public class匹配的mysql-connector-java.jar。很多部署失败的问题就是漏了这一步,CM Server找不到JDBC驱动,数据库初始化时直接报“No suitable driver found”。
2.4 离线仓库:没有公网环境时必须提前完成的事情
经历过一次“在线安装卡在parcel下载”之后,我再也不指望安装时现场下载。CDH的parcel包动辄几个GB,在学校或企业内网这种网络环境不稳定的场景下,中断几次就得从头再来,体验非常糟糕。
正确的做法是在有外网的机器上提前下载好:
- CDH的parcel包,例如CDH-6.3.2-1.cdh6.3.2.p0.1605554-el7.parcel;
- 同名但后缀为.sha1或.sha256的校验文件;
- 如果有Hive、Spark、Kafka等组件需要,也一并下载对应parcel版本。
然后把所有文件放到CM Server主节点的/opt/cloudera/parcel-repo目录下。CM启动后会自动扫描这个目录,识别parcel和对应的校验文件,后续通过Web界面安装时就不再从外网下载,而是直接从这个目录分发到各台agent。
如果你有多台机器需要分发,最简单的方式是在CM Server节点上用nginx或python的http.server把/opt/cloudera/parcel-repo目录暴露出去,agent从同一个地址拉取。实际操作中我会把parcel-repo放在独立的大分区里,因为一个版本CDH加上几个常用组件的parcel,总容量可能超过20GB,磁盘太小的节点会很尴尬。
3. 从Cloudera Manager Server到Agent:安装流程每一步在做什么
3.1 安装顺序背后的逻辑
接触过CDH的人都会发现它的安装顺序是:先装Server端组件,再装Agent,最后在Web界面里添加主机。这个顺序背后有它的逻辑:CM Server是整个集群的“大脑”,需要先把大脑和数据存储准备好,agent才有地方上报心跳。如果你先把agent装好并启动,它默认连的server_host还是localhost,虽然不会造成太大问题,但会造成后续重新配置的麻烦。
Server和Agent最好在一台机器上先安装完成,然后通过Web向导批量部署到其他节点。这样能避免手动到每台机器上配config文件、启动服务,省时且减少出错。CDH本身支持的模板批量添加让我一般不在其他节点上手动安装agent,而是靠CM首批添加主机时的安装过程来分发。
3.2 配置CM仓库并安装主节点组件
最简单的方式是使用系统包管理器安装。需要先创建YUM仓库文件,例如/etc/yum.repos.d/cloudera-manager.repo,里面指向CDH版本的repo地址。如果是离线环境,需要准备RPM包和依赖包构建本地仓库。
[cloudera-manager] name=Cloudera Manager baseurl=http://实际仓库地址/cm/6.3.x/ gpgcheck=0 enabled=1我习惯把gpgcheck设为0,因为离线环境下导入GPG密钥经常会引入额外风险,公司内网又没有暴露给外部的风险,校验问题不大。如果你对安全有更高要求,可以在线导入官方密钥再把gpgcheck调成1。
然后执行安装:
yum -y install cloudera-manager-daemons cloudera-manager-agent cloudera-manager-server这个命令会把daemons、agent和server三个包都装上。安装完成后,agent的配置文件位于/etc/cloudera-scm-agent/config.ini,需要把server_host改成CM Server的主机名或IP,否则agent会一直去找本地端口。
3.3 初始化数据库并启动服务
数据库初始化是整个安装过程中最容易被“想当然”的部分。我见过有人在MySQL里手动建了好几个库,结果跑到最后发现每个服务的库都没有对应的初始表,其实是应该用官方脚本统一完成初始化。
CDH提供了初始化脚本,用法大致如下:
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql -h 数据库主机名 cm cmadmin 密码脚本执行成功后会自动创建CM所需的schema和初始表,包括各个服务的配置表、任务表、审计表等。执行完成后建议立刻在mysql客户端里查看一下是否有cm库,并检查一下关键表是否存在。
接着启动agent和server:
systemctl start cloudera-scm-agent systemctl start cloudera-scm-server启动之后别急着看界面,先用日志确认服务正常。CM Server的日志位置在/var/log/cloudera-scm-server/cloudera-scm-server.log。你可以tail -f观察日志,直到出现类似“Started Jetty server”的信息,才说明Web服务真正起来了。首次启动可能需要几分钟,因为CM要初始化大量配置,并做自动探测,别一看界面打不开就重复重启,反而让初始化进程互相打断。
3.4 浏览器端安装向导与角色分配
浏览器访问http://CM-Server:7180,默认账号密码都是admin。首次登录会进入安装向导,就像普通软件安装一样,按提示走,但有几个地方要格外小心。
添加主机时,CM会让你输入一组主机的IP或主机名。它会通过SSH自动在这些主机上安装agent。这里要求CM Server能通过SSH免密登录到目标主机,同时目标主机要提前装好Python和pssh依赖,否则自动化流程会失败。
接下来选择“使用Parcel”安装组件时,就应该选择我们之前准备好的CDH版本。如果之前把parcel和校验文件放到了/opt/cloudera/parcel-repo目录,CM会识别到“已下载”状态,只需要在线分发就可以了。分发和校验阶段耗时较长,通常是整个安装过程中最长的等待期,但它是一次性的,后面扩容和升级都能复用。
角色分配时,我通常在界面上手动规划,不太依赖默认分配。NameNode建议放在CM Server之外的独立机器上,Standby NameNode放另一台,这样单点故障时不会同时挂掉。ZooKeeper尽量分配奇数台节点,至少3台。ResourceManager也放到物理机上单独部署。Hive和Hue可以共存在同一台机器上,因为它们对资源的占用模式和NameNode不太一样。
4. 服务部署完之后先别急着交差:验证与踩坑实录
4.1 部署完成后的第一轮验证清单
集群安装完成只是一个开始,很多人看到界面上所有角色变绿就觉得大功告成,我一般会再做一轮完整的验证,避免“漂亮的界面下藏着不可用服务”。
我会先检查进程:
jps在每台节点上确认对应角色进程已经跑起来。HDFS的NameNode进程、DataNode进程、YARN的ResourceManager和NodeManager、ZooKeeper的QuorumPeerMain,如果这些进程都在,说明基础服务正常。
然后做命令级验证:
hdfs dfsadmin -report yarn node -list hdfs dfs -mkdir /test hdfs dfs -put testfile /test hdfs dfs -cat /test/testfile如果文件能正常写入和读取,HDFS链路才算真正打通。NameNode的Web UI、YARN的ResourceManager UI也都要扫一眼,确认能够访问。这些验证步骤看起来基础,但真的能发现很多问题,比如DataNode因为磁盘空间不足而无法上报、YARN队列配置错误导致任务提交被拒绝等。
4.2 踩坑一:Parcel校验异常或长时间卡在下载
最常见的是parcel一直被卡在“下载”状态,进度条长时间没有任何变化。如果你确认CM Server节点根本无法访问外网,那基本可以断定是parcel仓库里缺少校验文件或者CM识别不到本地parcel。
排查时先看目录:
ls -lh /opt/cloudera/parcel-repo/正常情况应同时存在parcel文件、对应的.sha1或.sha256文件,以及manifest.json文件。sha文件内容是一个哈希值,CM会用它来校验parcel包完整性。很多人只把parcel复制进去,忘了复制sha文件,CM就会一直尝试自己计算校验值,甚至会触发重新下载。
另一种情况是磁盘空间或inode不足。parcel解压需要原文件将近两倍的空间,因为要先解压到/opt/cloudera/parcels,再生成符号链接。我在一台只有60GB磁盘的节点上遇到过解压到一半提示空间不足,CM界面却显示“正在分发”的情况,最后检查日志才发现是磁盘满了。
4.3 踩坑二:主机名/FQDN不一致导致Agent失联
添加主机时可以成功安装agent,但在分配角色时却提示“主机尚未完成运行”,或者agent明明在运行但CM界面上一直显示“主机运行状态未知”。这类问题十有八九是主机名和/etc/hosts配置不一致导致的。
CM对FQDN比较敏感。比如一台主机hostname设置成node01,但/etc/hosts里写的是node01.internal格式的域名,agent上报的主机名就会和CM预期的不匹配,心跳注册就会失败。后来我在所有节点上统一只使用短主机名,并保证/etc/hosts中每一行都同时写清楚短主机名和完整域名,之后再没有出现过这种问题。
如果已经卡在这种状态,重装agent不一定有效。正确做法是先把/etc/hosts、/etc/sysconfig/network里所有主机名统一,然后重启agent,等它重新上报新主机名后再在CM里删除旧主机、重新添加。
4.4 踩坑三:HDFS元数据clusterID冲突
这个坑很容易发生在“加了新节点”或者“重新初始化NameNode”之后的集群上。现象是新加的DataNode启动后反复刷Connection refused,或者NameNode Web UI里DataNode一直显示“未知”状态。打开DataNode日志通常会看到类似“Incompatible clusterIDs in .../VERSION”的信息。
原因也很简单:NameNode格式化时生成一个clusterID存到fsimage元数据中,DataNode首次启动时如果数据目录里已经有旧的VERSION文件,就会带着旧clusterID上报。新老clusterID不一致,NameNode直接拒绝注册。
解决办法也比较直接:找到新DataNode的datanode数据目录,备份后删除VERSION文件,重新启动DataNode,让它从NameNode获取当前集群的clusterID。如果你是新装集群遇到这个问题,最常见的原因是复制了模板虚拟机,所有节点的datanode数据目录带着同一个clusterID,这时需要逐一清理DataNode的数据目录。
4.5 踩坑四:外部数据库连接反复报错
一次Hive服务部署后,Hive metastore一直起不来,日志报“Unable to connect to MySQL”。排查时发现CM配置的hive-site.xml里javax.jdo.option.ConnectionURL写的是jdbc:mysql://localhost:3306/hive,直接把localhost替换成了真正部署MySQL的主机名,连接就通了。
这类问题的根源通常在于:安装向导让你输入数据库主机名时,默认值可能是localhost,但你真正安装的元数据库在另一台机器上。等到CM把配置文件下发到远端节点后,让各agent通过这些配置去连接localhhost指向的IP地址,自然就无法连接。
另外,JDBC驱动也必须同时放在所有运行metastore服务的节点上,不只是CM Server。Hive metastore进程启动时需要加载JDBC驱动类,如果路径不对或类名不匹配,同样会报“No suitable driver found”。部署前我会在所有相关节点上统一放一份mysql-connector-java.jar并设置正确权限,这一步能省掉后续很多麻烦。
5. 角色参数调优与小集群运维建议
5.1 默认参数为什么“不够用”
集群跑起来之后,各项服务的默认参数基本都是CDH官方给出的保守值,它能保证服务稳定运行,但离“好用”还有一段距离。默认配置最大的问题有两个:一是各角色的Java堆内存设置偏保守,二是YARN的资源估算未必贴合你节点的实际硬件。
比如HDFS的DataNode和NameNode的堆大小,CM默认可能只有1GB到2GB。如果你的集群有几十个节点、每天写入几千万个文件,NameNode很快就需要更多堆内存来维护文件系统元数据,否则就会出现Full GC频繁、NameNode进入SafeMode或响应卡顿。
5.2 三个最值得先调的内存参数
我最先调的参数通常有三个:
- NameNode堆内存:建议设为物理内存的一半再稍微留一点,比如32GB物理内存的机器,NameNode堆设16GB比较稳妥。如果机器主要只跑NameNode,也可以考虑20~24GB。
- DataNode堆内存:主要用于维护数据块和流式读写,堆一般不需要太大,8GB以内通常够用,更关键的是留给Page Cache足够的内存。
- YARN容器内存:在yarn-site.xml里,yarn.nodemanager.resource.memory-mb要基于每台节点的实际内存来配置。例如节点内存64GB,系统本身和其他服务预留16GB,那给YARN的资源就可以是48GB。
除了这三个,我还会调整yarn.scheduler.maximum-allocation-mb,默认值通常只有8GB左右,如果跑Spark任务需要更大的executor,就会触发“容器内存超出限额”的报错。把这些参数改完后再跑一轮基准测试,观察YARN的resource界面和日志,看是否存在频繁重试或内存溢出。
5.3 日常运维与备份习惯
CDH装好之后,日常维护的核心不是“会不会装”,而是“别让问题发生到不可挽回”。
我每次做完初始部署,第一件事就是在CM里配置好自动备份Cloudera Manager Server的数据库。CM的配置信息、集群定义、健康检查状态都在这套数据库里,如果数据库丢了,安装就算白干。备份策略我用每天一次mysqldump,保留近7天即可,同时把/opt/cloudera/parcel-repo里已经用到的parcel和sha文件也做一次快照,后续扩容或重装时直接拿来用。
磁盘监控也很关键。HDFS数据节点的数据盘要盯inode和空间使用率,达到85%就要开始规划扩容。我遇到过一次DataNode因为inode耗尽无法创建新块,那个问题界面上根本看不出来,只有看日志和df -i才能发现。
日志轮转也要提前配置。Cloudera Manager本身自带日志管理,但HDFS的namenode日志、datanode日志、YARN的container日志如果不轮转,半年后就能吃掉上百GB磁盘空间。建议用logrotate统一管理,每周轮转一次,保留4到8周即可。
5.4 后续扩展思路
CDH集群不是装完就算完,运维期的扩展往往比安装期更重要。扩容节点时,只需要保证新节点满足同样的系统初始化要求,包括关闭THP、配置hosts、时间同步等,然后在CM里通过“添加主机”引导它安装agent,再分配角色就行。只要parcel在CM仓库里完整可用,新增节点会自动从既有仓库拉取对应组件包,不需要再单独拷文件。
版本升级方面,CDH 6.x升级到7.x,我的经验是先在一个测试环境完整演练一遍,再对生产环境做滚动升级。过程中要特别关注Hive和Hue的兼容性问题,因为这两个组件的配置结构变化比较大,升级脚本可能会改写hive-site.xml,导致表结构不兼容。升级前一定要备份CM数据库,并在测试环境跑通Hive的所有核心查询再做生产迁移。
如果你想在这个集群上增加其他组件,比如Kafka、Kudu或Impala,直接在CM的组件列表里添加对应parcel并分配角色就可以了。由于一切都由CM统一管理,后续就算有人误改了配置文件,也可以通过CM的“部署客户端配置”一键恢复。
最后再分享一个小经验:安装完CDH后,先把/opt/cloudera/parcel-repo目录整体做一个归档备份,放到独立的存储里。下次无论是扩容、重装节点还是搭建第二个环境,你都能直接复用这份离线仓库。我因为这个习惯,帮自己和团队省下了好多次在无外网环境下重新下载parcel的折磨,也算是在CDH及软件安装部署这条路上走了几趟之后最想提醒大家的一件事。