本文把 Hadoop 从概念到落地的内容合在一处:先用一节理清 HDFS、YARN、MapReduce 各自的角色,再给出两套完全不同的装法——用 Ambari + HDP 做向导式安装,或者用官方 tar 包手动安装(本地模式、单节点伪分布式、完全分布式 HA),最后是 JDK 11 升级踩到的坑和日常运维排错。
两套装法的操作系统层面准备工作是相同的,所以先集中写在「环境准备」一节,后面两章都从这里开始。HDFS 的 shell 命令细节见后面的 HDFS Shell 操作 一节;集群疑难问题和参数调优另见 大数据集群运维 的常见问题排查 与内存与 CPU 调优 。
概念速览 动手之前先把名词理顺,后面配置文件里的每一项基本都能对应到下面某个角色。
大数据与它的四个特征 大数据(Big Data)指的是无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,需要新的处理模式才能从中获得决策力、洞察发现力和流程优化能力。它有四个常被提到的特征:
Volume(大量)
Velocity(高速)
Variety(多样):既有结构化数据,也有非结构化数据
Value(低价值密度):单条数据的价值不高,如何快速把有价值的数据「提纯」出来,是大数据场景下的核心难题
Hadoop 是什么 Hadoop 是 Apache 基金会开发的一套分布式系统基础架构,主要解决海量数据的存储 和分析计算 两个问题。广义上说的 Hadoop 往往指的不是这几个进程,而是围绕它形成的整个 Hadoop 生态圈。
它被广泛使用的几个原因:
高可靠性:底层维护多个数据副本,某个计算元素或存储出现故障也不会丢数据
高扩展性:在集群间分配任务和数据,可以方便地扩展到数以千计的节点
高效性:在 MapReduce 的思想下并行工作,以加快任务处理速度
高容错性:能够自动将失败的任务重新分配
发行版本与版本演进 三大主流发行版本是 Apache、Cloudera、Hortonworks。Apache Hadoop 是原始版本,CDH 与 HDP 两个商业发行版在 Cloudera 与 Hortonworks 合并后也已经合并。
1.x:MapReduce 同时负责资源调度和计算
2.x:拆出 YARN 专门做资源调度,MapReduce 只负责计算
3.x:主要组成没有变化
HDFS Hadoop Distributed File System(HDFS)是一个分布式文件系统,非 HA 部署下有三类角色:
NameNode (nn):存储文件的元数据,如文件名、目录结构、文件属性(生成时间、副本数、文件权限),以及每个文件的块列表和块所在的 DataNode
DataNode (dn):在本地文件系统存储文件块数据以及块数据的校验和
Secondary NameNode (2nn):定期做 checkpoint ——把 NameNode 的 fsimage 和 editlog 拉过来合并成新的 fsimage 再推回去,目的是控制 editlog 的长度、缩短 NN 重启时回放日志的时间。它不是热备 :NN 挂了它顶不上,手里的 fsimage 也总是落后于 NN
如果按 HA 结构部署,就不再需要 Secondary NameNode,取而代之的是:
StandbyNameNode:NameNode 的备用节点,主节点出问题后主备倒换
JournalNode:主备 NameNode 之间共享数据的桥梁。NameNode 把元数据变动实时写入 JournalNode,StandbyNameNode 再实时读出来应用到自身,从而保持两边元数据同步
YARN Yet Another Resource Negotiator(YARN)是 Hadoop 的资源管理器,有两类角色:
ResourceManager(RM):全局资源管理器,集群里只有一个(HA 下一主一备),负责整个系统的资源管理和分配,包括处理客户端请求、启动并监控 ApplicationMaster、监控 NodeManager、资源的分配与调度等。它主要由调度器(Scheduler)和应用程序管理器(ApplicationsManager)两个组件构成
NodeManager(NM):负责单个节点上 CPU 与内存资源的使用,接收并处理来自 ApplicationMaster 的 Container 启动、停止等请求,管理本节点上 Container 的整个生命周期,并定时向 ResourceManager 汇报本节点资源使用情况和各 Container 的运行状态。它只管理 Container 本身,不关心 Container 里跑的是什么任务
MapReduce 与三者关系 MapReduce 把计算过程分成两个阶段:Map 阶段并行处理输入数据,Reduce 阶段对 Map 的结果做汇总。
生态体系一览
Sqoop:用于在 Hadoop、Hive 与传统数据库(MySQL、Oracle 等)之间传递数据,既能把关系库的数据导入 HDFS,也能把 HDFS 的数据导回关系库
Flume:高可用、高可靠的分布式海量日志采集、聚合和传输系统,支持在日志系统中定制各类数据发送方
Kafka:高吞吐量的分布式发布订阅消息系统
Spark:流行的开源大数据内存计算框架,可以基于 Hadoop 上存储的数据做计算
Flink:同为内存计算框架,用于实时计算的场景更多
Oozie:管理 Hadoop 作业(job)的工作流调度系统
HBase:分布式的、面向列的开源数据库,适合非结构化数据存储
Hive:基于 Hadoop 的数据仓库工具,把结构化数据文件映射成一张表并提供类 SQL 查询,SQL 会被翻译成 MapReduce 任务执行,学习成本低,适合数据仓库的统计分析
ZooKeeper:面向大型分布式系统的可靠协调系统,提供配置维护、名字服务、分布式同步、组服务等能力
环境准备 以下操作所有节点都要做 ,两种装法都以它为起点。部分服务器交付时可能已经做过,检查一遍即可。
全文用到两组实验机,命令里的主机名按自己的环境替换:
章节
主机名
IP
方式一(Ambari + HDP)
hdp01 / hdp02 / hdp03
192.168.100.101 / .102 / .103
方式二(手动部署)
hadoop01 / hadoop02 / hadoop03
192.168.2.241 / .242 / .243
关闭 selinux、防火墙与 swap 1 2 3 4 5 6 7 8 swapoff -a sed -ri 's/.*swap.*/#&/' /etc/fstab grep SELINUX= /etc/selinux/config | grep -v "#" sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config grep SELINUX= /etc/selinux/config | grep -v "#" setenforce 0 systemctl stop firewalld systemctl disable firewalld
时间同步 能连外网的集群不用管这一步。内网环境挑一台机器(这里用 hdp01,192.168.100.101)做 ntp 服务端,其余节点指向它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 yum -y install ntp cat >/etc/ntp.conf<<eof server 127.127.1.0 fudge 127.127.1.0 stratum 10 eof cat >/etc/ntp.conf<<eof server 192.168.100.101 eof systemctl enable --now ntpd.service ntpq -p
主机名与网络 按实际情况修改网卡配置,文件名与 NAME、DEVICE 要对应上,例如 /etc/sysconfig/network-scripts/ifcfg-ens32:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 TYPE =EthernetPROXY_METHOD =noneBROWSER_ONLY =no BOOTPROTO =static DEFROUTE =yes IPV4_FAILURE_FATAL =no IPV6INIT =yes IPV6_AUTOCONF =yes IPV6_DEFROUTE =yes IPV6_FAILURE_FATAL =no IPV6_ADDR_GEN_MODE =stable-privacyNAME =ens32 UUID =40 ae9247-96 ad-43 d0-8 c22-974897 f62a64DEVICE =ens32 ONBOOT =yes IPADDR =192.168 .100.101 GATEWAY =192.168 .100.1 DNS1 =8.8 .8.8 DNS2 =114.114 .114.114
改完重启网络、写 hosts、设主机名:
1 2 3 4 5 6 7 8 9 10 11 12 service network restart cat >/etc/hosts<<eof 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.100.101 hdp01 192.168.100.102 hdp02 192.168.100.103 hdp03 eof hostnamectl set-hostname hdp01
建立互信 每个节点生成密钥,再对所有节点 (含自己)分发公钥:
1 2 3 4 5 6 rm -rf ~/.sshssh-keygen -f ~/.ssh/id_rsa -N '' -t rsa -q -b 2048 ssh-copy-id -i ~/.ssh/id_rsa.pub hdp01 ssh-copy-id -i ~/.ssh/id_rsa.pub hdp02 ssh-copy-id -i ~/.ssh/id_rsa.pub hdp03
安装 JDK 下载地址:https://www.oracle.com/java/technologies/downloads/ 。这里用软链接 current 指向真实版本,后面换 JDK 只改软链接,不用动环境变量。
1 2 3 4 5 6 7 8 9 10 11 mkdir /opt/bigdata/javatar zxf jdk-*.tar.gz -C /opt/bigdata/java cd /opt/bigdata/javaln -s jdk* currentcat >/etc/profile.d/java_env.sh<<eof export JAVA_HOME=/opt/bigdata/java/current export CLASSPATH=.:\$JAVA_HOME/jre/lib/rt.jar:\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar export PATH=\$JAVA_HOME/bin:\$PATH eof source /etc/profilejava -version
用 Ambari 安装时,JDK 和数据库都可以交给 Ambari 自动下载,这一步以及后面的 MySQL 安装都可以跳过;只有需要自定义版本时才手动装。
方式一:Ambari + HDP 向导式部署 Ambari 负责把 HDP 里的各个组件推到所有节点上安装并统一管理,适合快速拉起一整套生态。这里用的是 hdp-3.1.5 的本地离线包 、jdk8 最新版,数据库选 MySQL。
⚠️ 注:Hortonworks 被 Cloudera 收购后,HDP 与 Ambari 的公开仓库已经关闭,新版本需要订阅账号才能下载,本节流程仅适用于手上已有离线包的情况。新集群更建议用原生 Apache 版本(见「方式二」)。
准备本地 yum 源 把四个离线 tar 包解开,生成指向本地目录的 repo 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 mkdir HDP3.1.5cd HDP3.1.5;install_dirname=`pwd ` cat >ambari.repo<<eof [HDP-3.1-repo-1] name=HDP-3.1-repo-1 baseurl=file://$install_dirname/HDP/centos7/3.1.5.0-152 path=/ enabled=1 gpgcheck=0 [HDP-3.1-GPL-repo-1] name=HDP-3.1-GPL-repo-1 baseurl=file://$install_dirname/HDP-GPL/centos7/3.1.5.0-152 path=/ enabled=1 gpgcheck=0 [HDP-UTILS-1.1.0.22-repo-1] name=HDP-UTILS-1.1.0.22-repo-1 baseurl=file://$install_dirname/HDP-UTILS/centos7/1.1.0.22 path=/ enabled=1 gpgcheck=0 [ambari-2.7.5-repo-1] name=ambari-2.7.5-repo-1 baseurl=file://$install_dirname/ambari/centos7/2.7.5.0-72 path=/ enabled=1 gpgcheck=0 eof cp ambari.repo /etc/yum.repos.d/echo "unzip packege, may take a little time" tar -zxf ../ambari-*-centos7.tar.gz -C $install_dirname tar -zxf ../HDP-3*-centos7-rpm.tar.gz -C $install_dirname tar -zxf ../HDP-GPL-3.1.5.0-*-gpl.tar.gz -C $install_dirname tar -zxf ../HDP-UTILS-1.1.0.22-centos7.tar.gz -C $install_dirname yum clean all yum makecache yum repolist
安装 MySQL 数据库只装在一台机器上即可(这里是 192.168.100.101)。yum 源 rpm 包可在 https://dev.mysql.com/downloads/repo/yum/ 找到:
1 2 3 4 rpm -ivh mysql*.noarch.rpm yum install -y mysql-server mysql systemctl enable --now mysqld
Ambari 自带的建库 SQL 在 8.0 上有语法问题,这里先用 mysql-5.7,包可在 https://downloads.mysql.com/archives/community/ 下载:
1 2 3 4 5 6 7 8 wget https://downloads.mysql.com/archives/get/p/23/file/mysql-community-server-5.7.36-1.el7.x86_64.rpm wget https://downloads.mysql.com/archives/get/p/23/file/mysql-community-client-5.7.36-1.el7.x86_64.rpm wget https://downloads.mysql.com/archives/get/p/23/file/mysql-community-common-5.7.36-1.el7.x86_64.rpm wget https://downloads.mysql.com/archives/get/p/23/file/mysql-community-libs-5.7.36-1.el7.x86_64.rpm rpm -ivh mysql-community-common-5.7.36-1.el7.x86_64.rpm rpm -ivh mysql-community-libs-5.7.36-1.el7.x86_64.rpm rpm -ivh mysql-community-client-5.7.36-1.el7.x86_64.rpm rpm -ivh mysql-community-server-5.7.36-1.el7.x86_64.rpm
初始化 MySQL 用 /var/log/mysqld.log 里的临时密码进入初始化向导:
1 /usr/bin/mysql_secure_installation
向导会依次问这些问题,按下面的答法即可:
Enter password for user root:填日志里的临时密码,随后被要求设置新密码(validate_password 组件开启时密码强度不能太低)
Change the password for root ?:y,再输入两遍新密码
Remove anonymous users?:y,匿名账号只适合测试环境
Disallow root login remotely?:n,Ambari 要从其他节点连过来;生产环境应改成 y 并单独建远程账号
Remove test database and access to it?:y
Reload privilege tables now?:y
准备 JDBC 驱动 需要 mysql-connector-java.jar,下载链接 https://dev.mysql.com/downloads/connector/j/ 。也可以直接 yum 装,但版本受限,推荐下 jar 包自己放:
1 2 yum install -y mysql-connector-java
创建 ambari / hive / oozie 库与账号 如果密码策略挡住了简单密码,可以先临时放宽(生产环境不建议):
1 2 3 SHOW VARIABLES LIKE 'validate_password%' ;set global validate_password_policy= LOW;set global validate_password_length= 4 ;
Ambari 自身的库。因为 Ambari 会分别以 %、localhost、主机名三种形式连接,三个授权都要建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 create database ambari character set utf8mb4;CREATE USER 'ambari' @'%' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'ambari' @'%' ;CREATE USER 'ambari' @'localhost' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'ambari' @'localhost' ;CREATE USER 'ambari' @'hdp01' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'ambari' @'hdp01' ;FLUSH PRIVILEGES; use ambari; source / var/ lib/ ambari- server/ resources/ Ambari- DDL- MySQL- CREATE.sql; show tables;use mysql; select host,user from user where user = 'ambari' ;
Hive 的库(用 MySQL 时必须先手工建好,PostgreSQL 内嵌模式下 Ambari 会自动处理):
1 2 3 4 5 6 7 8 9 CREATE DATABASE hive character set utf8mb4;use hive; CREATE USER 'hive' @'%' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'hive' @'%' ;CREATE USER 'hive' @'localhost' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'hive' @'localhost' ;CREATE USER 'hive' @'hdp01' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'hive' @'hdp01' ;FLUSH PRIVILEGES;
Oozie 的库,同样的套路:
1 2 3 4 5 6 7 8 9 CREATE DATABASE oozie character set utf8mb4;use oozie; CREATE USER 'oozie' @'%' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'oozie' @'%' ;CREATE USER 'oozie' @'localhost' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'oozie' @'localhost' ;CREATE USER 'oozie' @'hdp01' IDENTIFIED BY '<CHANGE_ME>' ;GRANT ALL PRIVILEGES ON * .* TO 'oozie' @'hdp01' ;FLUSH PRIVILEGES;
安装 ambari-server 与 ambari-agent 管理节点(192.168.100.101)装 server:
1 2 3 yum -y install ambari-server ambari-server setup ambari-server start
所有节点装 agent:
1 2 yum -y install ambari-agent systemctl start ambari-agent
ambari-server setup 交互过程 下面是选用自定义 JDK + 外部 MySQL 时的完整交互,注意最后的 DDL 提示:选 MySQL 时必须自己去数据库里 source 一遍建表 SQL(上一节已做),内嵌 PostgreSQL 则会自动完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 [root@hdp01 ~]# ambari-server setup Using python /usr/bin/python Setup ambari-server Checking SELinux... SELinux status is 'enabled' SELinux mode is 'permissive' WARNING: SELinux is set to 'permissive' mode and temporarily disabled. OK to continue [y/n] (y)? y Customize user account for ambari-server daemon [y/n] (n)? y Enter user account for ambari-server daemon (root):ambari Adjusting ambari-server permissions and ownership... Checking firewall status... Checking JDK... Do you want to change Oracle JDK [y/n] (n)? y [1] Oracle JDK 1.8 + Java Cryptography Extension (JCE) Policy Files 8 [2] Custom JDK ============================================================================== Enter choice (1): 2 WARNING: JDK must be installed on all hosts and JAVA_HOME must be valid on all hosts. WARNING: JCE Policy files are required for configuring Kerberos security. If you plan to use Kerberos,please make sure JCE Unlimited Strength Jurisdiction Policy Files are valid on all hosts. Path to JAVA_HOME: /usr/java/default Validating JDK on Ambari Server...done. Check JDK version for Ambari Server... JDK version found: 8 Minimum JDK version is 8 for Ambari. Skipping to setup different JDK for Ambari Server. Checking GPL software agreement... Completing setup... Configuring database... Enter advanced database configuration [y/n] (n)? y Configuring database... ============================================================================== Choose one of the following options: [1] - PostgreSQL (Embedded) [2] - Oracle [3] - MySQL / MariaDB [4] - PostgreSQL [5] - Microsoft SQL Server (Tech Preview) [6] - SQL Anywhere [7] - BDB ============================================================================== Enter choice (3): Hostname (localhost): Port (3306): Database name (ambari): Username (ambari): Enter Database Password (ambari): Configuring ambari database... Should ambari use existing default jdbc /usr/share/java/mysql-connector-java.jar [y/n] (y)? y Configuring remote database connection properties... WARNING: Before starting Ambari Server, you must run the following DDL directly from the database shell to create the schema: /var/lib/ambari-server/resources/Ambari-DDL-MySQL-CREATE.sql Proceed with configuring remote database connection properties [y/n] (y)? y Extracting system views... ambari-admin-2.7.5.0.72.jar .... Ambari repo file doesn't contain latest json url, skipping repoinfos modification Adjusting ambari-server permissions and ownership... Ambari Server 'setup' completed successfully.
网页向导安装 server 与 agent 都起来后,就可以在页面上完成剩下的工作。登录地址 http://hdp01:8080 ,默认管理员账号 admin,密码 admin(登录后立刻改掉)。向导过程中报错就看 /var/log/ambari-server/ 与 /var/log/ambari-agent/ 下的日志。
HDP 版本定义文件 向导里选择 stack 版本时会用到版本定义文件,离线安装可以把它保存成 HDP-3.1.5.0-152.xml 后手动指定,其中的 baseurl 换成自己的本地源地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <?xml version="1.0" ?> <repository-version xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="version_definition.xsd" > <release > <type > STANDARD</type > <stack-id > HDP-3.1</stack-id > <version > 3.1.5.0</version > <build > 152</build > <compatible-with > 3\.\d+\.\d+\.\d+</compatible-with > <release-notes > http://example.com</release-notes > <display > HDP-3.1.5.0</display > </release > <manifest > <service id ="ACCUMULO-170" name ="ACCUMULO" version ="1.7.0" /> <service id ="ATLAS-200" name ="ATLAS" version ="2.0.0" /> <service id ="DRUID-0121" name ="DRUID" version ="0.12.1" /> <service id ="HDFS-311" name ="HDFS" version ="3.1.1" /> <service id ="YARN-311" name ="YARN" version ="3.1.1" /> <service id ="MAPREDUCE2-311" name ="MAPREDUCE2" version ="3.1.1" /> <service id ="HBASE-216" name ="HBASE" version ="2.1.6" /> <service id ="HIVE-310" name ="HIVE" version ="3.1.0" /> <service id ="KAFKA-200" name ="KAFKA" version ="2.0.0" /> <service id ="KNOX-100" name ="KNOX" version ="1.0.0" /> <service id ="OOZIE-431" name ="OOZIE" version ="4.3.1" /> <service id ="PIG-0160" name ="PIG" version ="0.16.0" /> <service id ="RANGER-120" name ="RANGER" version ="1.2.0" /> <service id ="RANGER_KMS-120" name ="RANGER_KMS" version ="1.2.0" /> <service id ="SPARK2-232" name ="SPARK2" version ="2.3.2" /> <service id ="SQOOP-147" name ="SQOOP" version ="1.4.7" /> <service id ="STORM-121" name ="STORM" version ="1.2.1" /> <service id ="TEZ-091" name ="TEZ" version ="0.9.1" /> <service id ="ZEPPELIN-080" name ="ZEPPELIN" version ="0.8.0" /> <service id ="ZOOKEEPER-346" name ="ZOOKEEPER" version ="3.4.6" /> </manifest > <available-services /> <repository-info > <os family ="redhat7" > <package-version > 3_1_5_0_*</package-version > <repo > <baseurl > https://archive.cloudera.com/p/HDP/centos7/3.x/updates/3.1.5.0</baseurl > <repoid > HDP-3.1</repoid > <reponame > HDP</reponame > <unique > true</unique > </repo > <repo > <baseurl > https://archive.cloudera.com/p/HDP-GPL/centos7/3.x/updates/3.1.5.0</baseurl > <repoid > HDP-3.1-GPL</repoid > <reponame > HDP-GPL</reponame > <unique > true</unique > <tags > <tag > GPL</tag > </tags > </repo > <repo > <baseurl > https://archive.cloudera.com/p/HDP-UTILS-1.1.0.22/repos/centos7</baseurl > <repoid > HDP-UTILS-1.1.0.22</repoid > <reponame > HDP-UTILS</reponame > <unique > false</unique > </repo > </os > </repository-info > </repository-version >
方式二:官方 tar 包手动部署 这一节用原生 Apache Hadoop,按 本地运行模式 → 单节点伪分布式 → 完全分布式 HA 的顺序逐步加码:三种模式的软件安装完全一样,区别只在配置文件和启动哪些进程。实验机是 hadoop01-hadoop03(192.168.2.241-243),/etc/hosts 相应写成:
1 2 3 4 5 6 7 8 cat >/etc/hosts<<eof 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.2.241 hadoop01 192.168.2.242 hadoop02 192.168.2.243 hadoop03 eof
安装 Hadoop 与本地运行模式 下载地址 https://archive.apache.org/dist/hadoop/common/ 。解压后不改任何配置就是本地运行模式 :没有任何守护进程,读写本地文件系统,用来验证包和环境变量是否正确。配置文件单独放到 /etc/hadoop/conf 并用 HADOOP_CONF_DIR 指过去,升级换包时配置不用搬:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 useradd hadoop mkdir -p /opt/bigdata/hadoopwget --no-check-certificate https://archive.apache.org/dist/hadoop/common/hadoop-3.3.1/hadoop-3.3.1.tar.gz tar -zxvf hadoop-*.tar.gz -C /opt/bigdata/hadoop cd /opt/bigdata/hadoopln -s hadoop-* currentchown -R hadoop:hadoop /opt/bigdata/hadoopmkdir /etc/hadoop cp -r /opt/bigdata/hadoop/current/etc/hadoop /etc/hadoop/confchown -R hadoop:hadoop /etc/hadoopcat >/etc/profile.d/hadoop_env.sh<<-EOF #HADOOP_HOME export HADOOP_HOME=/opt/bigdata/hadoop/current export HADOOP_MAPRED_HOME=\${HADOOP_HOME} export HADOOP_COMMON_HOME=\${HADOOP_HOME} export HADOOP_HDFS_HOME=\${HADOOP_HOME} export HADOOP_YARN_HOME=\${HADOOP_HOME} export CATALINA_BASE=\${HTTPFS_CATALINA_HOME} export HADOOP_CONF_DIR=/etc/hadoop/conf export HTTPFS_CONFIG=/etc/hadoop/conf export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin EOF source /etc/profilehadoop version
验证本地运行模式 用自带的 wordcount 例子跑一遍,输入输出都在本地目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 su - hadoop cd /opt/bigdata/hadoop/currentmkdir wcinputcat > /opt/bigdata/hadoop/current/wcinput/demo.txt <<-EOF Linux Unix windows hadoop Linux spark hive hadoop Unix MapReduce hadoop Linux hive windows hadoop spark EOF hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount wcinput wcoutput
结果:
1 2 3 4 5 6 7 8 9 10 11 # ls wcoutput/ part-r-00000 _SUCCESS # cat wcoutput/part-r-00000 Linux 3 MapReduce 1 Unix 2 hadoop 4 hive 2 spark 2 windows 2
输出目录里两个文件的含义:_SUCCESS 是任务完成标识,表示执行成功;part-r-00000 才是结果文件,其中带 m 标识的是 mapper 输出、带 r 标识的是 reduce 输出,00000 是 reduce task(分区)编号 ——有 N 个 reducer 就有 part-r-00000 到 part-r-0000(N-1),job id 根本不出现在输出文件名里。
单节点伪分布式 伪分布式和完全分布式的步骤基本一致,差别只在配置文件,所以先在单节点上把各个进程的启动顺序走通。节点 192.168.2.231(hadoop231),前置操作和上面的安装已完成,配置基本用默认值,只把 fs.defaultFS 指到本机。
修改 core-site.xml /etc/hadoop/conf/core-site.xml,RPC 默认端口 8020:
1 2 3 4 <property > <name > fs.defaultFS</name > <value > hdfs://hadoop231</value > </property >
进程日志都在 /opt/bigdata/hadoop/current/logs/,起不来就先看日志。以下操作都用 hadoop 用户执行。
启动 HDFS 组件 格式化 NameNode 后启动它。格式化只在初次部署时做一次 ,重复格式化会导致 DataNode 认不出集群(见后文排错):
1 2 3 4 5 6 $ su - hadoop $ cd /opt/bigdata/hadoop/current/bin $ hdfs namenode -format $ hdfs --daemon start namenode $ jps|grep NameNode 27319 NameNode
打开 192.168.2.231:9870 就是 NameNode 的状态页面,此时 DataNode 还没起,页面上没有数据:
再启动 SecondaryNameNode(后面做 HA 的完全分布式集群不需要这个服务)和 DataNode:
1 2 3 4 5 6 7 $ hdfs --daemon start secondarynamenode $ jps|grep SecondaryNameNode 29705 SecondaryNameNode $ hdfs --daemon start datanode $ jps|grep DataNode 3876 DataNode
刷新 192.168.2.231:9870,可以看到已有活动的节点和容量信息:
启动 YARN 与 JobHistoryServer 先起 ResourceManager:
1 2 3 $ yarn --daemon start resourcemanager $ jps|grep ResourceManager 4726 ResourceManager
192.168.2.231:8088 是 ResourceManager 的状态页面。此时可用内存、CPU 资源数和活跃节点数都是 0,因为还没有 NodeManager:
补上 NodeManager:
1 2 3 $ yarn --daemon start nodemanager $ jps|grep NodeManager 8853 NodeManager
再看页面,资源数就有了:
最后是 JobHistoryServer,页面在 192.168.2.231:19888:
1 2 3 $ mapred --daemon start historyserver $ jps|grep JobHistoryServer 1027 JobHistoryServer
让 MapReduce 跑在 YARN 上 以上是最简配置,此时 mapreduce 的运行环境仍然是 local(本地),要让它提交到 yarn,需要改两个文件。
mapred-site.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <configuration > <property > <name > mapreduce.framework.name</name > <value > yarn</value > </property > <property > <name > yarn.app.mapreduce.am.env</name > <value > HADOOP_MAPRED_HOME=${HADOOP_HOME}</value > </property > <property > <name > mapreduce.map.env</name > <value > HADOOP_MAPRED_HOME=${HADOOP_HOME}</value > </property > <property > <name > mapreduce.reduce.env</name > <value > HADOOP_MAPRED_HOME=${HADOOP_HOME}</value > </property > </configuration >
yarn-site.xml:
1 2 3 4 <property > <name > yarn.nodemanager.aux-services</name > <value > mapreduce_shuffle</value > </property >
两个文件都改完再重启 ResourceManager 与 NodeManager,漏改 yarn-site.xml 会导致任务失败(见后文排错):
1 2 3 4 5 yarn --daemon stop resourcemanager yarn --daemon stop nodemanager yarn --daemon start resourcemanager yarn --daemon start nodemanager
在 HDFS 上跑一次 wordcount 和本地模式的例子相同,只是输入数据先传到 HDFS,任务也会提交到 YARN:
1 2 3 4 5 6 7 8 9 10 11 12 13 cat > /tmp/demo.txt <<-EOF Linux Unix windows hadoop Linux spark hive hadoop Unix MapReduce hadoop Linux hive windows hadoop spark EOF hadoop fs -mkdir /demo hadoop fs -put /tmp/demo.txt /demo hadoop jar /opt/bigdata/hadoop/current/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /demo /output hadoop fs -ls /output
结果与本地模式一致:
1 2 3 4 5 6 7 8 $ hadoop fs -text /output/part-r-00000 Linux 3 MapReduce 1 Unix 2 hadoop 4 hive 2 spark 2 windows 2
这次任务能在 JobHistoryServer 里看到记录:
完全分布式(HDFS HA) 所有节点先完成「环境准备」与上面「安装 Hadoop 与本地运行模式」的全部操作,然后按下面的规划改配置。
节点规划 一般情况下的规划原则:
NameNode 服务要独立部署
DataNode 和 NodeManager 建议部署在同一台服务器上
ResourceManager 要独立部署
JobHistoryServer 一般和 ResourceManager 放一起
ZooKeeper(QuorumPeerMain)和 JournalNode 集群可以放一起
zkfc(DFSZKFailoverController)负责对 NameNode 做资源仲裁,必须和 NameNode 运行在同一台机器上
当前只有三台机器,按下表安排:
节点
进程
hadoop01
QuorumPeerMain, JournalNode, NameNode, DFSZKFailoverController, DataNode, NodeManager
hadoop02
QuorumPeerMain, JournalNode, NameNode, DFSZKFailoverController, DataNode, NodeManager
hadoop03
QuorumPeerMain, JournalNode, DataNode, ResourceManager, NodeManager, JobHistoryServer
安装 ZooKeeper 官方下载页 https://zookeeper.apache.org/releases.html#download 。所有节点执行:
1 2 3 4 5 6 wget --no-check-certificate https://archive.apache.org/dist/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz mkdir -p /opt/bigdata/zookeepertar -zxvf apache-zookeeper-*-bin.tar.gz -C /opt/bigdata/zookeeper cd /opt/bigdata/zookeeperln -s apache-zookeeper-*-bin current
所有节点写配置并建目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cat > /opt/bigdata/zookeeper/current/conf/zoo.cfg <<-EOF tickTime=2000 initLimit=20 syncLimit=10 dataDir=/opt/bigdata/zookeeper/current/data dataLogDir=/opt/bigdata/zookeeper/current/dataLogDir clientPort=2181 quorumListenOnAllIPs=true server.1=hadoop01:2888:3888 server.2=hadoop02:2888:3888 server.3=hadoop03:2888:3888 admin.serverPort=8081 EOF mkdir -p /opt/bigdata/zookeeper/current/datamkdir -p /opt/bigdata/zookeeper/current/dataLogDir
三个端口的用途:2181 对 client 端提供服务,2888 集群内机器通信,3888 选举 leader。
myid 每个节点不同,要和 zoo.cfg 里 server.N 的编号对应,最后统一授权:
1 2 3 4 5 echo 1 > /opt/bigdata/zookeeper/current/data/myid echo 2 > /opt/bigdata/zookeeper/current/data/myid echo 3 > /opt/bigdata/zookeeper/current/data/myid chown -R hadoop:hadoop /opt/bigdata/zookeeper
启动并确认角色,日志在 /opt/bigdata/zookeeper/current/logs:
1 2 3 4 5 6 $ cd /opt/bigdata/zookeeper/current/bin $ ./zkServer.sh start $ jps 23097 QuorumPeerMain $ ./zkServer.sh status
修改 Hadoop 配置文件 配置文件路径 /etc/hadoop/conf,所有节点 都要改成一致。
core-site.xml,fs.defaultFS 指向 HA 的逻辑名 bigdata 而不是某台具体主机:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <configuration > <property > <name > fs.defaultFS</name > <value > hdfs://bigdata</value > </property > <property > <name > hadoop.tmp.dir</name > <value > /var/tmp/hadoop-${user.name}</value > </property > <property > <name > ha.zookeeper.quorum</name > <value > hadoop01,hadoop02,hadoop03</value > </property > <property > <name > fs.trash.interval</name > <value > 60</value > </property > </configuration >
hdfs-site.xml,两个 NameNode(nn1/nn2)、三个 JournalNode、自动故障转移,以及两块盘的数据目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 <configuration > <property > <name > dfs.nameservices</name > <value > bigdata</value > </property > <property > <name > dfs.ha.namenodes.bigdata</name > <value > nn1,nn2</value > </property > <property > <name > dfs.namenode.rpc-address.bigdata.nn1</name > <value > hadoop01:9000</value > </property > <property > <name > dfs.namenode.rpc-address.bigdata.nn2</name > <value > hadoop02:9000</value > </property > <property > <name > dfs.namenode.http-address.bigdata.nn1</name > <value > hadoop01:50070</value > </property > <property > <name > dfs.namenode.http-address.bigdata.nn2</name > <value > hadoop02:50070</value > </property > <property > <name > dfs.namenode.shared.edits.dir</name > <value > qjournal://hadoop01:8485;hadoop02:8485;hadoop03:8485/bigdata</value > </property > <property > <name > dfs.ha.automatic-failover.enabled.bigdata</name > <value > true</value > </property > <property > <name > dfs.client.failover.proxy.provider.bigdata</name > <value > org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value > </property > <property > <name > dfs.journalnode.edits.dir</name > <value > /data1/hadoop/dfs/jn</value > </property > <property > <name > dfs.replication</name > <value > 2</value > </property > <property > <name > dfs.ha.fencing.methods</name > <value > shell(/bin/true)</value > </property > <property > <name > dfs.namenode.name.dir</name > <value > file:///data1/hadoop/dfs/name,file:///data2/hadoop/dfs/name</value > <final > true</final > </property > <property > <name > dfs.datanode.data.dir</name > <value > file:///data1/hadoop/dfs/data,file:///data2/hadoop/dfs/data</value > <final > true</final > </property > <property > <name > dfs.block.size</name > <value > 134217728</value > </property > <property > <name > dfs.permissions</name > <value > true</value > </property > <property > <name > dfs.permissions.supergroup</name > <value > supergroup</value > </property > <property > <name > dfs.hosts</name > <value > /etc/hadoop/conf/hosts</value > </property > <property > <name > dfs.hosts.exclude</name > <value > /etc/hadoop/conf/hosts-exclude</value > </property > </configuration >
mapred-site.xml,JobHistoryServer 放在 hadoop03:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <configuration > <property > <name > mapreduce.framework.name</name > <value > yarn</value > </property > <property > <name > mapreduce.jobhistory.address</name > <value > hadoop03:10020</value > </property > <property > <name > mapreduce.jobhistory.webapp.address</name > <value > hadoop03:19888</value > </property > </configuration >
yarn-site.xml,ResourceManager 在 hadoop03,末尾两项按单节点可分配的内存与核数填:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 <configuration > <property > <name > yarn.resourcemanager.hostname</name > <value > hadoop03</value > </property > <property > <name > yarn.resourcemanager.scheduler.address</name > <value > hadoop03:8030</value > </property > <property > <name > yarn.resourcemanager.resource-tracker.address</name > <value > hadoop03:8031</value > </property > <property > <name > yarn.resourcemanager.address</name > <value > hadoop03:8032</value > </property > <property > <name > yarn.resourcemanager.admin.address</name > <value > hadoop03:8033</value > </property > <property > <name > yarn.resourcemanager.webapp.address</name > <value > hadoop03:8088</value > </property > <property > <name > yarn.nodemanager.aux-services</name > <value > mapreduce_shuffle,spark_shuffle</value > </property > <property > <name > yarn.nodemanager.aux-services.mapreduce_shuffle.class</name > <value > org.apache.hadoop.mapred.ShuffleHandler</value > </property > <property > <name > yarn.nodemanager.aux-services.spark_shuffle.class</name > <value > org.apache.spark.network.yarn.YarnShuffleService</value > </property > <property > <name > yarn.nodemanager.local-dirs</name > <value > file:///data1/hadoop/yarn/local,file:///data2/hadoop/yarn/local</value > </property > <property > <name > yarn.nodemanager.log-dirs</name > <value > file:///data1/hadoop/yarn/logs,file:///data2/hadoop/yarn/logs</value > </property > <property > <description > Classpath for typical applications.</description > <name > yarn.application.classpath</name > <value > $HADOOP_CONF_DIR, $HADOOP_COMMON_HOME/*,$HADOOP_COMMON_HOME/lib/*, $HADOOP_HDFS_HOME/*,$HADOOP_HDFS_HOME/lib/*, $HADOOP_MAPRED_HOME/*,$HADOOP_MAPRED_HOME/lib/*, $HADOOP_YARN_HOME/*,$HADOOP_YARN_HOME/lib/*, $HADOOP_HOME/share/hadoop/common/*, $HADOOP_COMMON_HOME/share/hadoop/common/lib/*, $HADOOP_HOME/share/hadoop/hdfs/*, $HADOOP_HOME/share/hadoop/hdfs/lib/*, $HADOOP_HOME/share/hadoop/mapreduce/*, $HADOOP_HOME/share/hadoop/mapreduce/lib/*, $HADOOP_HOME/share/hadoop/yarn/*, $HADOOP_YARN_HOME/share/hadoop/yarn/lib/*, $HIVE_HOME/lib/*, $HIVE_HOME/lib_aux/* </value > </property > <property > <name > yarn.nodemanager.resource.memory-mb</name > <value > 20480</value > </property > <property > <name > yarn.nodemanager.resource.cpu-vcores</name > <value > 8</value > </property > </configuration >
hdfs-site.xml 里 dfs.hosts 指向的白名单文件也要建出来:
1 2 3 4 5 cat >/etc/hadoop/conf/hosts<<-EOF hadoop01 hadoop02 hadoop03 EOF
创建数据目录 配置里用到 /data1、/data2 两块盘,所有节点都建好并授权:
1 2 3 4 mkdir -p /data1/hadoopmkdir -p /data2/hadoopchown -R hadoop:hadoop /data1/hadoopchown -R hadoop:hadoop /data2/hadoop
按顺序初始化并启动 首次启动的顺序不能随意调整,都用 hadoop 用户执行(su hadoop)。
启动 ZooKeeper 集群(所有节点)
1 2 3 4 $ cd /opt/bigdata/zookeeper/current/bin $ ./zkServer.sh start $ jps 2182 QuorumPeerMain
在 ZooKeeper 中格式化 HA 状态节点(仅 hadoop01)
启动 JournalNode 集群(所有节点),会生成 /data1/hadoop/dfs/jn
1 2 3 $ hdfs --daemon start journalnode $ jps 15187 JournalNode
格式化并启动主 NameNode(hadoop01),clusterId 可自行指定
1 2 3 4 $ hdfs namenode -format -clusterId bigdataserver $ hdfs --daemon start namenode $ jps 11724 NameNode
备节点同步元数据后启动(hadoop02)
1 2 3 4 $ hdfs namenode -bootstrapStandby $ hdfs --daemon start namenode $ jps 1880 NameNode
启动 zkfc(先 hadoop01,再 hadoop02)
1 2 3 $ hdfs --daemon start zkfc $ jps 1888 DFSZKFailoverController
启动 DataNode(所有节点)
1 2 3 $ hdfs --daemon start datanode $ jps 2880 DataNode
启动 YARN 与 JobHistoryServer
1 2 3 4 5 6 7 $ yarn --daemon start resourcemanager $ yarn --daemon start nodemanager $ mapred --daemon start historyserver $ jps 7986 ResourceManager 8246 NodeManager 8405 JobHistoryServer
验证 重复前面「在 HDFS 上跑一次 wordcount」的步骤即可,输出内容相同。页面上应该能看到一主一备的 NameNode、三个活跃的 DataNode 以及刚提交的任务:
升级到 JDK 11 版本信息:jdk11、hadoop-3.4.0-arm、hive 4.0。因为 JDK 是用软链接 /opt/bigdata/java/current 引入的,升级本身只是把软链接换到新版本,但会连带出下面两个问题。
1 2 3 4 5 6 7 [root@test-63 java]# pwd /opt/bigdata/java [root@test-63 java]# ls -l total 8 lrwxrwxrwx 1 root root 30 Jun 5 10:41 current -> /opt/bigdata/java/jdk-11.0.23 drwxr-xr-x 8 10143 10143 4096 Dec 16 2021 jdk1.8.0_321 drwxr-xr-x 8 root root 4096 Jun 5 10:19 jdk-11.0.23
ByteBuffer.position 报错 报错:java.lang.NoSuchMethodError: java.nio.ByteBuffer.position(I)Ljava/nio/ByteBuffer。
这是 JDK 8 里没有该返回类型的方法导致的,升级到 JDK 11 即可解决,也正是这次升级的起因。
Hive 在 JDK 11 下无法启动 报错:Exception in thread "main" java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader。
两种处理方式:
直接升级到 hive 4.0 及以上版本,原生支持 JDK 11
还在用 hive 3.x 的话,只能让 Hive 单独使用 JDK 8。Hive 读的是 Hadoop 侧的 Java 信息,手动改环境变量没用,仍然走 JDK 11,所以要在 /opt/bigdata/hive/current/bin/hive 开头插一段:进入时把 current 软链接临时切到 JDK 8,退出时再切回 JDK 11,用 HIVE_JAVA_SWITCHED 防止递归调用,trap 保证异常退出也能恢复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 if [ -z "$HIVE_JAVA_SWITCHED " ]; then CURRENT_JAVA=/opt/bigdata/java/jdk-11.0.23 ln -sfn /opt/bigdata/java/jdk1.8.0_321 /opt/bigdata/java/current if [ "$(readlink -f /opt/bigdata/java/current) " != "/opt/bigdata/java/jdk1.8.0_321" ]; then echo "Failed to update the Java soft link to java2" exit 1 fi export JAVA_HOME=/opt/bigdata/java/current export PATH=$JAVA_HOME /bin:$PATH export HIVE_HOME=/opt/bigdata/hive/current export HIVE_JAVA_SWITCHED=true function restore_java { ln -sfn /opt/bigdata/java/jdk-11.0.23 /opt/bigdata/java/current if [ "$(readlink -f /opt/bigdata/java/current) " != "/opt/bigdata/java/jdk-11.0.23" ]; then echo "Failed to restore the Java soft link to the original version" exit 1 fi } trap restore_java EXIT HUP INT TERM $HIVE_HOME /bin/hive "$@ " HIVE_EXIT_STATUS=$? restore_java exit $HIVE_EXIT_STATUS fi
⚠️ 注:这个软链接切换的做法是全局生效的,同一台机器上如果有其他作业正在用 current,会被短暂影响。多用户环境更建议给 Hive 单独设置 HADOOP_OPTS/JAVA_HOME,或者直接升级 Hive 版本。
HDFS Shell 操作 shell 操作 hadoop fs 等同于 hdfs dfs
HDFS 上的 Shell 操作命令跟 Linux 下的 Shell 命令基本类似,相关参数也基本相同
hdfs dfs -help : 查看命令的帮助信息
主要不同的点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ## 从本地上传 /localdemo10.tar.gz 文件到 hdfs 的 /logs/demo hadoop fs -copyFromLocal /localdemo10.tar.gz /logs/demo hadoop fs -put /localdemo10.tar.gz /logs/demo # 与上面相同,一般用 put hadoop fs -moveFromLocal /localdemo10.tar.gz /logs/demo # 移动,会删除本地文件 ## 下载 HDFS 文件到本地系统磁盘 /data hadoop fs -copyToLocal /logs/demo/localdemo10.tar.gz /data hadoop fs -get /logs/demo/localdemo10.tar.gz /data # 与上面相同,一般用 get ## 删除 hadoop fs -rm -r -skipTrash /tmp/hive_test # -skipTrash 直接删除,不放入回收站 hadoop fs -expunge # 让 Trash 里超过 fs.trash.interval 的旧 checkpoint 永久删除,并新建一个 checkpoint;刚删的、没到期的文件不会被清掉。要立刻清空得 hadoop fs -rm -r -skipTrash /user/<user>/.Trash ## 追加 本地 aa1.log 内容 到 hdfs /logs/aa.log (hdfs 上内容不能修改,只能追加) hadoop fs -appendToFile aa1.log /logs/aa.log
用户操作 将 root 加入 supergroup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 groupadd supergroup usermod -a -G supergroup root ## hdfs 用户是 supergroup su - hdfs -s /bin/bash -c "hdfs dfsadmin -refreshUserToGroupsMappings" ## HA 下要对每个 NameNode 分别刷新(用户组映射由 NameNode 本地 OS 解析,和 NodeManager 无关; ## groupadd/usermod 也要在 NameNode 所在机器上做): hdfs dfsadmin -fs hdfs://hadoop01:8020 -refreshUserToGroupsMappings hdfs dfsadmin -fs hdfs://hadoop02:8020 -refreshUserToGroupsMappings ## 顺便确认一下哪台是 active(这条只查状态,不刷新任何缓存) hdfs haadmin -getAllServiceState ## 验证 root 用户 hadoop fs -ls /user/hdfs
这两段示例背后的权限模型 这里有两个高频误区值得说清楚,否则照抄很容易得出”有时行有时不行”的结论。
一、进了 supergroup 就等于超级用户,后面的 chmod 是多余动作。 dfs.permissions.superusergroup 的默认值就是 supergroup,凡是属于这个组的用户,HDFS 的权限检查整体跳过 ——不看目录的 rwx 位,也不看属主。所以下面第二种写法里的 hadoop fs -chmod 770 /user/test 其实不起决定作用,真正让它能访问的是组身份。反过来说,如果你只想给某个用户开某个目录,就不该 把他塞进 supergroup,那是给了全局权限,用 chown/chmod/ACL 才对。
二、用户和组的解析发生在 NameNode 端,不在客户端。 这是最容易白折腾半天的一点:NameNode 拿到请求里的用户名后,用自己本机 的 id/getent group 去查这个用户属于哪些组(默认的 ShellBasedUnixGroupsMapping 就是 fork 一个 id -Gn)。所以
在客户端机器上 groupadd supergroup && usermod -a -G supergroup root 是无效的 ,NameNode 根本不看客户端的 /etc/group;
必须在每个 NameNode 所在的机器 上建组、加用户,HA 下两台都要做;
改完之后还要 -refreshUserToGroupsMappings 刷掉 NameNode 里的缓存(缓存时长由 hadoop.security.groups.cache.secs 控制,默认 300 秒,不刷就得等它过期)。
想确认 NameNode 到底认为某个用户属于哪些组,直接问它:
生产环境更常见的做法是把组解析接到 LDAP(hadoop.security.group.mapping 换成 LdapGroupsMapping),这样就不用在每台 NameNode 上维护本地组了。
另外一种
1 2 3 4 5 6 7 8 groupadd supergroup usermod -a -G supergroup root su - test -s /bin/bash -c "hdfs dfsadmin -refreshUserToGroupsMappings" su - test -s /bin/bash -c "hadoop fs -chmod 770 /user/test" su - root -s /bin/bash -c "hadoop fs -ls /user/test"
运维与排错 这一节汇总日常会用到的启停命令、日志位置与端口,以及部署过程中实际踩到的两个坑。
服务启停与日志位置 手动部署下没有一键脚本,单个进程用下面三条命令管理(stop 换掉 start 即可):
1 2 3 hdfs --daemon start namenode|secondarynamenode|datanode|journalnode|zkfc yarn --daemon start resourcemanager|nodemanager mapred --daemon start historyserver
排查问题时常看的几个位置:
Hadoop 各进程日志:/opt/bigdata/hadoop/current/logs/
ZooKeeper 日志:/opt/bigdata/zookeeper/current/logs
Ambari 日志:/var/log/ambari-server/、/var/log/ambari-agent/
MySQL 初始临时密码:/var/log/mysqld.log
常用 Web 与服务端口
组件
端口
说明
NameNode
9870
3.x 默认的 HTTP 页面端口,本文 HA 配置改成了 50070
NameNode
8020 / 9000
RPC,默认 8020,本文 HA 配置写成 9000
JournalNode
8485
主备之间同步 edits
ResourceManager
8088
YARN 页面
JobHistoryServer
19888
历史任务页面
ZooKeeper
2181 / 2888 / 3888
客户端 / 集群通信 / 选举
Ambari Server
8080
管理页面
NameNode 与 DataNode 的 VERSION 冲突 服务器重启后又执行了一次 hdfs namenode -format,NameNode 生成了新的 clusterID,而 DataNode 数据目录里的 VERSION 还是旧的,两边对不上,DataNode 起不来:
处理办法是备份后删除 DataNode 的 data、tmp 目录再启动。所以格式化命令只在初次部署时执行,之后重启集群直接 start 即可。
改用 YARN 后忘记同步 yarn-site.xml mapred-site.xml 已经把 mapreduce.framework.name 改成 yarn,但 yarn-site.xml 里没有配 yarn.nodemanager.aux-services,任务提交后报错:
补上配置并重启 ResourceManager、NodeManager,重跑任务即恢复正常: