目录
11.2. 上传Zookeeper安装包到/data目录 9
11.6. 创建和修改conf/zookeeper-env.sh 10
11.7. 修改conf/log4j.properties 11
11.10. 修改Zookeeper的配置文件zoo.cfg 11
11.11.2. Crontab自动启动Zookeeper 13
16.1. 查看节点列表:yarn node -list 44
16.2. 查看节点状态:yarn node -status 44
16.3. 查看状态:yarn rmadmin -getServiceState rm1 45
16.4. 人工切换:yarn rmadmin -transitionToStandby rm1 45
16.5. 查看应用列表:yarn application --list 45
16.6. 查看作业列表:hadoop job -list 45
3)JVM GC(Garbage Collection,垃圾回收) 49
截至本文撰写时(2019/9/17日),Hadoop最高版本为3.2.0,但适用于生产环境的为3.1.2(9月22日发布了可用于生产环境的3.2.1版本),本文只介绍3.1.2版本的分布式安装,不包含单机版安装。适用于Hadoop-3.1.3版本,所操作的环境为CentOS-7.2,对应的Linux内核版本为3.10,不同的Linux可能略有区别。
为提升安装效率,本文的安装过程使用了批量命令工具和批量上传文件工具。批量操作工具的下载和使用,请参见《附2:批量操作工具》。
缩略语 | 全写 | 说明 |
JVM | Java Virtual Matchine | Java虚拟机 |
jps | JVM Process Status | Java虚拟机进程状态工具 |
HDFS | Hadoop Distributed File System | Hadoop分布式文件系统 |
NN | NameNode | 名字节点 |
DN | DataNode | 数据节点 |
JN | JournalNode | 日志节点 |
YARN | YetAnother Resource Negotiator |
|
RM | Resource Manager | YARN的资源管理器 |
AM | Application Master |
|
RS | Resource Scheduler | 资源调度器 |
MR | MapReduce |
|
zk | Zookeeper |
|
RFA | RollingFileAppender | Log4j的一种日志器类型,文件大小到达指定大小时产生一个新的文件 |
DRFA | DailyRollingFileAppender | Log4j的一种日志器类型,每天产生一个日志文件 |
安装步骤可分解为以下几大步:
- 下载安装包
- 设置批量操作参数
- 环境准备
- 创建安装用户组和用户
- 安装JDK
- 安装Zookeeper
- 安装Hadoop
每一大步又可分解为几个小步,具体有哪些小步参见各大步的说明。推荐使用批量命令工具mooon_ssh和批量上传文件工具mooon_upload完成各步安装。
从零安装Hadoop,需要下载三个安装包,按照先后顺序分别是:
| 版本 | 下载链接 | 说明 |
批量工具 |
| 批量命令工具和批量上传文件工具 | |
JDK | 1.8 | 下载需要登录Oracle帐号 | |
Zookeeper | 3.5.5 | 官方推荐用于生产环境的最新版本 | |
Hadoop | 3.1.2 | Hadoop依赖Zookeeper |
以7台机器为本文的操作示例:
序号 | IP | 主机名 | 角色 | 备注 |
1 | 192.168.1.21 | hadoop-001 | Master | 这2台用来做Master,部署HDFS的NameNode和YARN的ResourceManager,如果机器数不够,则Master可和Slave共用相同机器。 |
2 | 192.168.1.22 | hadoop-002 | ||
3 | 192.168.1.23 | hadoop-003 | Slave | 这5台用来做HDFS的DataNode,以及组成5台机器组成的Zookeeper集群和5台机器组成的JournalNode集群。 |
4 | 192.168.1.24 | hadoop-004 | ||
5 | 192.168.1.25 | hadoop-005 | ||
6 | 192.168.1.26 | hadoop-006 | ||
7 | 192.168.1.27 | hadoop-007 |
如果不使用批量工具mooon_ssh和mooon_upload,则可用其它熟悉的工具替代,或者手工一台台操作。
export U=root # 以root用户安装JDK,否则没的操作目录/usr/local权限 export P='123456' # 用户root的密码 export H='192.168.1.21,192.168.1.22,192.168.1.23,192.168.1.24,192.168.1.25,192.168.1.26,192.168.1.27' # 逗号分隔的目标机器列表,注意Zookeeper和JournalNode只涉及其中5个 export THR=0 # 可选设置,但设置THR为0可多台机器并行操作 |
环境准备包含的子步骤:
这一步也不是必须的,可执行命令“ulimit -n”查看当前值是多少,如果值偏小则建议调大些,比如64G内存机器可设置为100000(甚至更大的值),但一般1024有点偏小。
修改方法是编辑文件/etc/security/limits.conf,调整其中的“soft nofile”和“hard nofile”两项值,如果此两项值不存在则应新增,可以limits.conf文件尾部新增这两项。
* soft nofile 100000 * hard nofile 100000
# End of file |
上述的“*”表示对所有用户运行的进程有效,也可限定只对运行Hadoop的用户有效,比如运行Hadoop的用户名为hadoop,则可如下这样设置:
hadoop soft nofile 100000 hadoop hard nofile 100000
# End of file |
limits.conf如何生效,请参见博文《源码解读Linux的limits.conf文件》,博文链接为:https://blog.csdn.net/Aquester/article/details/86694644,最省事的生效方法是重启系统。
这一步也不是必须的,但一般建议将/proc/sys/vm/overcommit_memory值设置为1,以关闭系统的Overcommit,注意并不是关闭OOM,OOM由/proc/sys/vm/panic_on_oom控制。关于OOM更深入的介绍,可浏览博文《Linux OOM一二三》,对应的博文链接为:https://blog.csdn.net/Aquester/article/details/100543346。
# cat /proc/sys/vm/overcommit_memory 0 |
设置方法为编辑文件/etc/sysctl.conf,添加以下内容:
vm.overcommit_memory=1 |
修改好后再执行命令“sysctl -p”以使生效。
这一步也不是必须的,有关设置可参考下列四篇博文,如果不知道是什么SSH,可执行“ssh -V”可看。
但进建议同一集群内的NameNode间可互免密码登录,以方便设置dfs.ha.fencing.methods及相关参数。
两个openssh间免密码登录 | |
两个SSH2间免密码登录 | |
SSH2免密码登录OpenSSH | |
OpenSSH免密码登录SSH2 |
这一步不是必须的,只有主机名不满足Hadoop要求时才必须执行,不过建议同一Hadoop集群内的主机名有统一的命名规范,以方便运维和管理。
Hadoop要求主机名不能包含下划线,所以这一步需要解决这个问题。主机名的修改分临时修改和永久修改,临时修改在系统重启后失效,而永久修改在系统重启后依然有效。
使用系统自带的命令hostname即可临时性修改主机名,比如将主机名改为hadoop001,只需执行下列命令即可:
hostname hadoop001 |
为保证系统重启后依旧有效,永久修改是必须的。对于CentOS,永久性修改主机名的方法是编辑文件/etc/hostname,将新的主机名写入到此文件中,如:
# cat /etc/hostname Hadoop001 |
注意,不是所有的Linux发行版本都是修改/etc/hostname文件,比如SuSE对应的是/etc/HOSTNAME。如果不做临时修改,则在修改/etc/hostname后需要重启系统,否则不会生效。
当机器数量多时,一台台修改主机名效率低,也容易出错。可使用工具set_hostname.sh批量修改。set_hostname.sh通过修改文件/etc/hostname来修改主机名,如果主机名文件不是hostname,则应当修改set_hostsname.sh后再用,将set_hostname.sh中的变量hostname_file修改为合适的值即可,比如如果是SuSE:hostname_file=/etc/HOSTNAME。
使用set_hostname.sh前,需准备一个IP和主机名映射文件,可命名为hosts.name如:
# cat hosts.name 192.168.1.21 hadoop-001 192.168.1.22 hadoop-002 192.168.1.23 hadoop-003 192.168.1.24 hadoop-004 192.168.1.25 hadoop-005 192.168.1.26 hadoop-006 192.168.1.27 hadoop-007 |
将工具文件set_hostname.sh和映射文件hosts.name都上传到目标机器的tmp目录。
mooon_upload -d=/tmp -s=hosts.name,set_hostname.sh |
批量远程执行set_hostname.sh,完成主机名的修改。
mooon_ssh -c='/tmp/set_hostname.sh /tmp/hosts.name' |
查看修改结果:
mooon_ssh -c='hostname' |
IP和主机名的映射关系需写入到文件/etc/hosts中,推荐在一台机器完成后,再批量发布到其它机器。
建议JDK用root用户安装,Zookeeper用名为zk的用户安装,Hadoop用名为hadoop的用户安装,hbase用名为hbase的用户安装。同时,可以考虑建一个名为supergroup的用户组,将zk、hadoop和hbase都置于该用户组中,以方便管理。或者修改dfs.permissions.supergroup,以变更用户组名。
为方便管理,创建用户组hadoop,并分别为Zookeeper和Hadoop创建用户名zk和hadoop。注意用户名字符数不要超过8个,否则ps等命令将显示用户ID,而不是用户名,因此不能取名zookeeper。
以root用户,批量创建即可:
mooon_ssh -c='groupadd supergroup' # 创建用户组supergroup,建议这个名和hdfs-site.xml中的dfs.permissions.supergroup值一致 mooon_ssh -c='useradd -g supergroup -m zk' # 创建Zookeeper运行用户zk mooon_ssh -c='useradd -g supergroup -m hadoop' # 创建Hadoop运行用户hadoop mooon_ssh -c='echo "zk:123456"|chpasswd' # 设置用户zk的密码为123456 mooon_ssh -c='echo "hadoop:123456"|chpasswd' # 设置用户hadoop的密码为123456 |
如果使用不同的用户运行HBase,则最好保持相同的用户组,这样不容易遇到权限问题。
本文使用的JDK安装包文件名为jdk-8u221-linux-x64.tar.gz,推荐将安装包文件上传到目标机器的/usr/local目录。
- 批量上传jdk安装包到目标机器的/usr/local目录
mooon_upload -s=jdk-8u221-linux-x64.tar.gz -d=/usr/local |
- 解压和安装JDK
mooon_ssh -c='cd /usr/local;tar xzf jdk-8u221-linux-x64.tar.gz;ln -s jdk1.8.0_221 jdk' |
- 添加和更新环境变量
不建议直接修改/etc/profile文件,而应采取在目录/etc/profile.d下新建一文件方式,可将这文件命名为jdk.sh,文件内容如下:
$ cat jdk.sh JAVA_HOME=/usr/local/jdk export CLASSPATH=$JAVA_HOME/lib/tools.jar export PATH=$JAVA_HOME/bin:$PATH |
可先在操作机上创建好jdk.sh,可不添加可执行权限。然后用批量工具上传到目标机器的/etc/profile.d目录,如:
mooon_upload -s=jdk.sh -d=/etc/profile.d |
注意,重新登录环境变量才会生效。按照步骤来,这一步一般不会有什么问题。至此,JDK的安装顺利完成。
Hadoop依赖Zookeeper,所以在安装Hadoop前需先安装好Zookeeper。不推荐将Zookeeper和Hadoop也安装在/usr/local目录,因为生产环境的机器该目录所在分区不一定足够大,本文操作将Zookeeper安装到/data目录。
如果Zookeeper的机器和JDK机器不完全一致,则应当重新设置环境变量H,或者批量工具参数“-h”指定Zookeeper机器列表。
由于Zookeeper的ZAB协议是一个多数派协议,因此组成集群的节点数应当为奇数个,且不少于三个节点组成(四个节点和三个节点的容灾效果相同,但反而降低了效率)。
# 只涉及7个中的5个 export H='192.168.1.23,192.168.1.24,192.168.1.25,192.168.1.26,192.168.1.27' |
mooon_upload -s=apache-zookeeper-3.5.5-bin.tar.gz -d=/data |
mooon_ssh -c='cd /data;tar xzf apache-zookeeper-3.5.5-bin.tar.gz' # 解压 mooon_ssh -c='cd /data;ln -s apache-zookeeper-3.5.5-bin zookeeper' # 建立软链接 mooon_ssh -c='cd /data;chown -R zk:supergroup zookeeper apache-zookeeper-3.5.5-bin' |
以下步骤切换到zk用户操作。
export U=zk # 运行Zookeeper的用户zk export P='123456' # 用户zk的密码 |
mooon_ssh -c='mkdir /data/zookeeper/data' mooon_ssh -c='mkdir /data/zookeeper/datalog' mooon_ssh -c='mkdir /data/zookeeper/logs' |
每个Zookeeper节点都需要一个不同的取值范围为1~255的myid值,建议将myid文件放在Zookeeper的数据目录下。由于每个节点的myid值不同,因此无法简单的批量操作,但可借助工具set_zookeeper_id.sh实现批量操作,下载链接:https://github.com/eyjian/libmooon/blob/master/shell/set_zookeeper_id.sh。
在使用之前,需要先准备好IP和myid值映射文件,以本文的为例:
$ cat hosts.id 192.168.1.23 3 192.168.1.24 4 192.168.1.25 5 192.168.1.26 6 192.168.1.27 7 |
确保工具文件set_zookeeper_id.sh有可执行权限,映射文件可命名为hosts.id,将映射文件hosts.id和工具文件set_zookeeper_id.sh都上传到目标机器的/tmp目录。
mooon_upload -d=/tmp -s=hosts.id,set_zookeeper_id.sh |
批量远程执行set_zookeeper_id.sh。
mooon_ssh -c='/tmp/set_zookeeper_id.sh /tmp/hosts.id /data/zookeeper/data/myid' |
查看设置执行结果:
mooon_ssh -c='cat /data/zookeeper/data/myid' |
以下修改可在Zookeeper集群中一台机器进行,完成后批量发布到集群中的其它机器或节点。当然也可以在操作机上完成,然后再批量发布到集群所有机器或节点。
不要直接修改bin/zkEnv.sh,因为zkEnv.sh会调用conf/zookeeper-env.sh,所以不必再修改zkEnv.sh。
zookeeper-env.sh文件内容:
export ZOO_LOG_DIR=/data/zookeeper/log export ZOO_LOG4J_PROP="INFO,ROLLINGFILE" |
修改ZOO_LOG4J_PROP的目的是让日志不输出到zookeeper.out,而是写入到日志文件。
主要修改如下三项:
zookeeper.log.dir=/data/zookeeper/log log4j.appender.ROLLINGFILE.MaxFileSize=100MB log4j.appender.ROLLINGFILE.MaxBackupIndex=10 |
设置日志文件目录为/data/zookeeper/log,每个日志文件大小MaxFileSize为100M,文件滚动个数MaxBackupIndex为10个。
打开文件bin/zkEnv.sh,可以看到它有引用conf/java.env。可以在java.env中设置JAVA_HOME这个环境变量,如:export JAVA_HOME=/usr/local/jdk。
仅在/etc/profile等处设置JAVA_HOME,可能并不管用。如果不管用,查看log/zookeeper.out,可以看到错误“nohup: failed to run command 'java': No such file or directory”。
这步不是必须的,但是推荐将zookeeper/bin加入到环境变量PATH,这样操作zookeeper会方便些,如:export PATH=/data/zookeeper/bin:$PATH。
建议采取在目录/etc/profile.d下新建文件zookeeper.sh方式,文件内容为:
export ZOOKEEPER_HOME=/data/zookeeper export PATH=$ZOOKEEPER_HOME/bin:$PATH |
当然也可以直接修改/etc/profile文件,不过不推荐也不建议,但可以修改zk用户自己的.bashrc文件方式。
解压Zookeeper安装包后,在目录conf中可找到Zookeeper模板配置文件zoo_sample.cfg,重命名为zoo.cfg,修改后内容如下。
$ cat zoo.cfg # The number of milliseconds of each tick tickTime=2000
# The number of ticks that the initial # synchronization phase can take initLimit=10
# The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5
# the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/data/zookeeper/data dataLogDir=/data/zookeeper/datalog
# the port at which the clients will connect clientPort=2181
# the maximum number of client connections. # increase this if you need to handle more clients maxClientCnxns=1000
# Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir autopurge.snapRetainCount=20
# Purge task interval in hours # Set to "0" to disable auto purge feature autopurge.purgeInterval=24
# Zookeeper cluster nodes Server.3=hadoop-003:2888:3888 Server.4=hadoop-004:2888:3888 Server.5=hadoop-005:2888:3888 Server.6=hadoop-006:2888:3888 Server.7=hadoop-007:2888:3888 |
从Zookeeper -3.5开始,默认会启动一个内嵌的Jetty服务,默认端口号为8080,在zoo.cfg中的相关配置如下(设置enableServer值为false可关闭内嵌的Jetty):
# The port the embedded Jetty server listens on. Defaults to 8080 admin.serverPort=8080
# The address the embedded Jetty server listens on. Defaults to 0.0.0.0 admin.serverAddress=0.0.0.0
# Set to "false" to disable the AdminServer. By default the AdminServer is enabled admin.enableServer=false
# The URL for listing and issuing commands relative to the root URL. Defaults to "/commands" admin.commandURL="/commands"
# Set the maximum idle time in milliseconds that a connection can wait before sending or receiving data. Defaults to 30000 ms admin.idleTimeout=30000 |
准备好后,将zoo.cfg批量上传到Zookeeper的配置文件目录/data/zookeeper/conf。Zoo.cfg中使用了主机名,注意务必已在/etc/hosts中配置好。
至此,Zookeeper已经安装和配置完毕,可启动Zookeeper了。推荐使用进程监控工具process_monitor.sh拉起Zookeeper,并且建议将process_monitor.sh放在Crontab中,一旦Zookeeper进程不在,process_monitor.sh可在几秒内重拉起Zookeeper。Process_monitor.sh的下载链接为https://github.com/eyjian/libmooon/blob/master/shell/process_monitor.sh。
mooon_ssh -c='nohup /data/zookeeper/bin/zkServer.sh start > /dev/null 2>&1 &' |
建议先在一台机器上启动,查看是否能够正常启动,没有问题再启动整个集群。
JAVA_HOME=/usr/local/jdk ZOOKEEPER_HOME=/data/zookeeper PMONITOR=/usr/local/bin/process_monitor.sh * * * * * $PMONITOR "$JAVA_HOME/bin/java -Dzookeeper" "$ZOOKEEPER_HOME/bin/zkServer.sh start" |
执行下列语句验证安装:
mooon_ssh -c='/data/zookeeper/bin/zkServer.sh status' |
如果正常,则Leader节点会输出:
Client port found: 2181. Client address: localhost. Mode: leader |
Follower节点会输出:
Client port found: 2181. Client address: localhost. Mode: follower |
一个集群内有且只有一个Leader,而且必须有一个Leader。
Hadoop的安装要比Zookeeper复杂许多,本节主要参考3.1.2版本的官方安装指南:https://hadoop.apache.org/docs/r3.1.2/hadoop-project-dist/hadoop-common/ClusterSetup.html。
# 涉及到所有,保持Master和Slave的配置文件相同,以简化管理 export H='192.168.1.21,192.168.1.22,192.168.1.23,192.168.1.24,192.168.1.25,192.168.1.26,192.168.1.27' |
mooon_upload -s=hadoop-3.1.2.tar.gz -d=/data |
mooon_ssh -c='cd /data;tar xzf hadoop-3.1.2.tar.gz' # 解压 mooon_ssh -c='cd /data;ln -s hadoop-3.1.2 hadoop' # 建立软链接 mooon_ssh -c='cd /data;chown -R hadoop:supergroup hadoop-3.1.2 hadoop' |
以下步骤切换到hadoop用户操作。
export U=hadoop # 运行Hadoop的用户hadoop export P='123456' # 用户hadoop的密码 |
修改所有节点上的$HADOOP_HOME/etc/hadoop/hadoop-env.sh文件,找到JAVA_HOME,设置其值为:export JAVA_HOME=/usr/local/jdk;找到HADOOP_HOME,设置其值为:export HADOOP_HOME=/data/hadoop。
特别说明下,虽然在/etc/profile.d/jdk.sh已经添加了JAVA_HOME,但仍然得修改所有节点上的hadoop-env.sh,否则启动时,报如下所示的错误(比如jdk.sh对Crontab拉起的无效):
192.168.1.21: Error: JAVA_HOME is not set and could not be found. 192.168.1.22: Error: JAVA_HOME is not set and could not be found. 192.168.1.23: Error: JAVA_HOME is not set and could not be found. |
除JAVA_HOME之外,再添加或修改:
export HADOOP_HOME=/data/hadoop/ export HADOOP_CONF_DIR=${HADOOP_HOME}/etc/hadoop export HADOOP_ROOT_LOGGER=INFO,console |
其它可选设置:
export HADOOP_HEAPSIZE_MAX= # 针对“Java -Xmx”,如果不指定单位,默认为“MB” export HADOOP_HEAPSIZE_MIN= # 针对“Java -Xms”,如果不指定单位,默认为“MB” export HADOOP_OPTS="-Djava.library.path=${HADOOP_HOME}/lib/native" exort HADOOP_CLIENT_OPTS= # HADOOP_OPTS的组成部分,针对Hadoop命令或客户端(如hdfs)的额外Java运行时选项 export HADOOP_COMMON_LIB_NATIVE_DIR= |
建议将“${HADOOP_HOME}/lib/native”加入到HADOOP_OPTS(尝试设置HADOOP_COMMON_LIB_NATIVE_DIR未生效,检查只在文件bin/hadoop中有引用HADOOP_COMMON_LIB_NATIVE_DIR,但并未有实际使用)中,不然会在日志中见到如下内容:
WARN [main] util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable |
如果想关闭执行“hdfs dfs”命令时的屏幕日志,可修改hadoop-env.sh中的HADOOP_ROOT_LOGGER,这样就不会打屏INFO和WARN两个级别的日志了。
# export HADOOP_ROOT_LOGGER=INFO,console export HADOOP_ROOT_LOGGER=OFF,console |
很多安装教程都有这一步,但并非必须的。文件格式同/etc/hosts,但全为slaves节点。如果只使用hadoop-daemon.sh启动和停止Hadoop,而不使用hadoop-daemons.sh、start-all.sh、stop-all.sh、start-dfs.sh、stop-dfs.sh等,就用不到slaves文件,所以说它不是必须的。
可不修改log4j.properties,但建议修改以下几项:
hadoop.log.dir=/data/hadoop/log Hadoop.log.maxbackupindex=10 |
解压后的$HADOOP_HOME/etc/hadoop目录下的core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml、httpfs-site.xml和kms-site.xml都是空的配置文件,所以不能直接使用。
而目录$HADOOP_HOME/share/doc/hadoop存了可用的模板配置文件,执行以下操作将这些模板配置文件复制到$HADOOP_HOME/etc/hadoop目录下。
cd $HADOOP_HOME # cd /data/hadoop cp ./share/doc/hadoop/hadoop-project-dist/hadoop-common/core-default.xml ./etc/hadoop/core-site.xml cp ./share/doc/hadoop/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml ./etc/hadoop/hdfs-site.xml cp ./share/doc/hadoop/hadoop-yarn/hadoop-yarn-common/yarn-default.xml ./etc/hadoop/yarn-site.xml cp ./share/doc/hadoop/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml ./etc/hadoop/mapred-site.xml |
然后可以开始绞刑修改各配置文件了。
按照下列表格完成对core-site.xml的修改:
属性名 | 属性值 | 说明 |
fs.defaultFS | hdfs://hdfs-cluster | HDFS集群名,应当取不同于其它HDFS集群的名称。如果有多个集群,可以考虑名称带上机房名。注意,必须为hdfs-site.xml中的dfs.nameservices定义的值之一。 |
hadoop.tmp.dir | /data/hadoop/tmp/${user.name} | 这是一个本地目录,注意根据实际选择空间足够的目录。仅Slaves有使用,比如YARN的yarn.nodemanager.local-dirs基于hadoop.tmp.dir。 |
hadoop.zk.address | hadoop-003:2181,hadoop-004:2181,hadoop-005:2181,hadoop-006:2181,hadoop-007:2181 | YARN会用到这个配置项,用于存储状态和Leader选举,参考来源:https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html。 |
ha.zookeeper.quorum | hadoop-003:2181,hadoop-004:2181,hadoop-005:2181,hadoop-006:2181,hadoop-007:2181 | ZKFailoverController会用到这个配置项 |
ha.zookeeper.parent-znode | /hadoop-ha | 在Zookeeper上的根目录,该目录用来做NameNode选举。不需要指定nameservice ID,会自动使用nameservice ID作为/hadoop-ha的子目录 |
io.seqfile.local.dir |
| 默认值为${hadoop.tmp.dir}/io/local |
fs.s3.buffer.dir |
| 默认值为${hadoop.tmp.dir}/s3 |
fs.s3a.buffer.dir |
| 默认值为${hadoop.tmp.dir}/s3a |
io.file.buffer.size | 131072 | 默认值为4096 |
注意启动之前,需要将配置的目录创建好,如创建好/data/hadoop/current/tmp目录。详细可参考:
http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/core-default.xml。
HDFS由NameNode和DataNode组成,加上JournalNode共三部分。其中JournalNode是独立集群,用于主从NameNode是同步数据。
按照下列表格完成对hdfs-site.xml的修改,NameNode和DataNode的hdfs-site.xml可完全相同,以方便统一维护:
属性名 | 属性值 | 说明 |
dfs.nameservices | hdfs-cluster (如果有多个,需以逗号分隔) | HDFS集群名,注意core-site.xml中的fs.defaultFS值需要在dfs.nameservices中,建议取一个有意义的名字,以方便管理。如果有多个nameservices,则以逗号分隔,如:hdfs-cluster1,hdfs-cluster2。 |
dfs.ha.namenodes.hdfs-cluster | nn1,nn2 | 同一nameservice下,可配置一或多个NameNode,“nn”为NameNode的缩写。 |
dfs.namenode.rpc-address.hdfs-cluster.nn1 | hadoop-001:8020 |
|
dfs.namenode.rpc-address.hdfs-cluster.nn2 | hadoop-002-204:8020 |
|
dfs.namenode.http-address.hdfs-cluster.nn1 | hadoop-001:9870 |
|
dfs.namenode.http-address.hdfs-cluster.nn2 | hadoop-002:9870 |
|
dfs.namenode.servicerpc-address |
| 配置了dfs.namenode.rpc-address,这个可以不配 |
dfs.blocksize | 134217728 | HDFS的块大小,值可加上后缀k、m、g、t、p、e,如128m即为134217728 |
以下为JournalNode相关配置项 | ||
dfs.journalnode.edits.dir | /data/hadoop/dfs/journalnode/ | 这个不要带前缀“file://”,JournalNode存储其本地状态的位置,在JouralNode机器上的绝对路径,JNs的edits和其他本地状态将被存储在此处。此处如果带前缀,则会报“Journal dir should be an absolute path” |
dfs.journalnode.rpc-address | 0.0.0.0:8485 | 配置JournalNode的RPC端口号,默认为0.0.0.0:8485,可以不用修改 |
以下为NameNode相关配置项 | ||
dfs.image.compress | false | 是否压缩image文件 |
dfs.namenode.name.dir | file:///data/hadoop/dfs/namenode | 请带上前缀“file://”,NameNode元数据存放目录,默认值为file://${hadoop.tmp.dir}/dfs/name,也就是在临时目录下,可以考虑放到数据目录下,多个目录时使用逗号分隔 |
dfs.namenode.shared.edits.dir | qjournal://hadoop-003:8485;hadoop-004:8485;hadoop-005:8485;hadoop-006:8485;hadoop-007:8485/hdfs-cluster | 至少三台Quorum Journal节点配置,注意分隔符是分号,而不是逗号。如果使用逗号,在格式化NameNode时将报错“Multiple shared edits directories are not yet supported”。 |
dfs.namenode.checkpoint.dir | file://${hadoop.tmp.dir}/dfs/namesecondary | 默认值为file://${hadoop.tmp.dir}/dfs/namesecondary,但如果没有启用SecondaryNameNode,则不需要 |
dfs.namenode.handler.count | 10 | NameNode的处理来源Clients的RPC请求线程数,未配置dfs.namenode.servicerpc-address才有效 |
dfs.namenode.service.handler.count | 10 | NameNode的处理来源DataNode的RPC请求线程数,区别于dfs.namenode.handler.count,只有配置了dfs.namenode.servicerpc-address才有效 |
dfs.hosts | /data/hadoop/etc/hadoop/dfs.hosts.permitted | 可选配置,但建议配置,以防止其它DataNode无意中连接进来。用于配置DataNode白名单,只有在白名单中的DataNode才能连接NameNode。dfs.hosts的值为一本地文件绝对路径,如:/data/hadoop/etc/hadoop/dfs.hosts.permitted,只需NameNode上有此文件 |
dfs.hosts.exclude | /data/hadoop/etc/hadoop/dfs.hosts.excluded | 正常不要填写,需要下线DataNode时用到。dfs.hosts.exclude的值为本地文件的绝对路径,文件内容为每行一个需要下线的DataNode主机名或IP地址,如:/data/hadoop/etc/hadoop/dfs.hosts.excluded,只需NameNode上有此文件 |
dfs.namenode.num.checkpoints.retained | 2 | 默认为2,指定NameNode保存fsImage文件的个数 |
dfs.namenode.num.extra.edits.retained | 1000000 | 额外保留Edit日志文件数 |
dfs.namenode.max.extra.edits.segments.retained | 10000 |
|
以下为DataNode相关配置项 | ||
dfs.datanode.data.dir | file:///data/hadoop/dfs/data | 请带上前缀“file://”,不要全配置成SSD类型,否则写文件时会遇到错误“Failed to place enough replicas”,多个目录时使用逗号分隔 |
dfs.datanode.max.transfer.threads | 12288 | DataNode用于传输数据的线程数,值不能太小,在Hadoop1.X中,此配置项名为dfs.datanode.max.xcievers。如果运行HBase,则该值应当调整到至少4096或者更大的值。 |
dfs.datanode.http.address | 9864 | DataNode的HTTP端口 |
dfs.datanode.https.address | 9865 | DataNode的HTTPS端口 |
dfs.datanode.du.reserved | 0 | 预留磁盘空间大小,单位为字节 |
dfs.datanode.scan.period.hours |
| 默认为504小时 |
dfs.blockreport.intervalMsec |
| DataNode向NameNode报告块信息的时间间隔,默认值为21600000毫秒 |
dfs.datanode.directoryscan.interval |
| DataNode进行内存和磁盘数据集块校验,更新内存中的信息和磁盘中信息的不一致情况,默认值为21600秒 |
dfs.heartbeat.interval | 3s | 向NameNode发心跳的间隔,单位:秒 |
以下为HA相关配置项 | ||
dfs.ha.automatic-failover.enabled | true | 自动主备切换 |
dfs.ha.fencing.methods | 可取值sshfence或shell,比如:sshfence(hadoop:36000)
如果配置为sshfence,当主NameNode异常时,使用ssh登录到主NameNode,然后使用fuser将主NameNode杀死,因此需要确保所有NameNode上可以使用fuser。 | 用来保证同一时刻只有一个主NameNode,以防止脑裂。可带用户名和端口参数,格式示例:sshfence([[username][:port]]);值还可以为shell脚本,格式示例: shell(/path/to/my/script.sh arg1 arg2 ...),如: shell(/bin/true)
如果sshd不是默认的22端口时,就需要指定。建议填写杀死NameNode的命令,以防止出现脑裂。参考来源:https://hadoop.apache.org/docs/r3.1.2/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html。 |
dfs.ha.fencing.ssh.private-key-files | /home/hadoop/.ssh2/id_dsa_2048_a | 如果dfs.ha.fencing.methods值为sshfence时需指定。 用于指定私钥,如果是OpenSSL,则值为/home/hadoop/.ssh/id_rsa,如有多个私钥,则以逗号分隔。 |
dfs.ha.fencing.ssh.connect-timeout | 30000 | 可选的配置 |
以下为权限相关配置项 | ||
dfs.permissions.supergroup | supergroup | 超级用户组名,建议创建同名的本地用户组 |
dfs.permissions | true | 为true表示开启权限检查 |
fs.permissions.umask-mode | 022 | 权限掩码 |
dfs.namenode.acls.enabled | false | NameNode是否开启ACL(Access Control Lists) |
dfs.cluster.administrators |
| 管理员列表 |
dfs.web.ugi | webuser,webgroup | WEB使用的用户名和用户组 |
以下为Client相关配置项 | ||
dfs.client.datanode-restart.timeout | 30 | 单位为秒,不要写成“30s”,否则HBase会报错“java.lang.NumberFormatException: For input string: "30s"” |
dfs.client.failover.proxy.provider.hdfs-cluster | org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider | 客户端通过它来找主NameNode |
详细配置可参考:
http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml。
如果没有配置dfs.namenode.rpc-address,则启动时报如下错误:
Incorrect configuration: namenode address dfs.namenode.servicerpc-address or dfs.namenode.rpc-address is not configured. |
这里需要指定IP和端口,如果只指定了IP,如<value>192.168.1.22</value>,则启动时输出如下:
Starting namenodes on [] |
改成“<value>hadoop-002:8020</value>”后,则启动时输出为:
Starting namenodes on [192.168.1.22] |
在YARN中,内存、CPU和磁盘等被抽象为资源。YARN由ResourceManager和NodeManager两部分组成,ResourceManager中的调度器负责资源(内存和CPU)分配,NodeManager负责资源的供给和隔离。其中,ResourceManager又由ApplicationsManager和ResourceScheduler两个部分组成。
按照下列表格完成对yarn-site.xml的修改,ResourceManager和NodeManager的yarn-site.xml可完全相同,以方便统一维护:
属性名 | 属性值 | 说明 |
yarn.resourcemanager.cluster-id | yarn-cluster | YARN集群名 |
|
| HA模式可不配置,但由于其它配置项可能有引用它,建议保持值为0.0.0.0,如果没有被引用到,则可不配置。 |
yarn.resourcemanager.address | ${yarn.resourcemanager.hostname}:8032 | ResourceManager的RPC地址 |
yarn.nodemanager.hostname | 0.0.0.0 | 一般不用修改,保持为“0.0.0.0”即可,以方便所有节点配置统一。 |
yarn.nodemanager.resource.detect-hardware-capabilities | false | 如果为true,则自动检查硬件资源 |
以下为HA相关的配置,包括自动切换(可仅可在ResourceManager节点上配置) | ||
yarn.resourcemanager.ha.enabled | true | 启用HA |
yarn.resourcemanager.ha.automatic-failover.enabled | true | RM是否自动故障切换 |
yarn.resourcemanager.ha.rm-ids | rm1,rm2 | 注意NodeManager要和ResourceManager一样配置 |
yarn.resourcemanager.hostname.rm1 | hadoop-001 |
|
yarn.resourcemanager.hostname.rm2 | hadoop-002 |
|
yarn.resourcemanager.webapp.address.rm1 | ${yarn.resourcemanager.hostname.rm1}:8088 |
|
yarn.resourcemanager.webapp.address.rm2 | ${yarn.resourcemanager.hostname.rm2}:8088 |
|
|
| 这个已被core-site.xml中的hadoop.zk.address所取代 |
yarn.resourcemanager.ha.automatic-failover.enable | true | 可不配置,因为当yarn.resourcemanager.ha.enabled为true时,它的默认值即为true |
以下为NodeManager配置 | ||
yarn.nodemanager.aux-services | mapreduce_shuffle | MapReduce Application的混洗服务 |
yarn.nodemanager.resource.cpu-vcores | 8 | NodeManager总的可用虚拟CPU个数,默认值为8,值为-1表示自动,值不能超过实际的CPU核数 |
yarn.nodemanager.pmem-check-enabled | true | 是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认是true |
yarn.nodemanager.vmem-check-enabled | true | 是否启动一个线程检查每个任务正使用的虚拟内存量,如果任务超出分配值,则直接将其杀掉,默认是true,64位系统可以考虑设置为false。 |
yarn.nodemanager.resource.memory-mb | 8192 | 该节点上YARN可使用的物理内存总量(包含所有任务的),默认是8192(MB),该值不能大于实际物理内存大小。如果值为-1,并且yarn.nodemanager.resource.detect-hardware-capabilities值为true,则自动计算。 |
yarn.nodemanager.vmem-pmem-ratio | 2.1 | 每使用1MB物理内存,最多可用的虚拟内存数,默认值为2.1。在运行spark-sql时如果遇到“Yarn application has already exited with state FINISHED”,则应当检查NodeManager的日志,以查看是否该配置偏小原因。该值偏小,也可能导致错误“running beyond virtual memory limits”。64位系统,该值可以调大一点。 |
yarn.nodemanager.local-dirs | ${hadoop.tmp.dir}/nm-local-dir | NodeManager中间文件存放的本地目录,可用逗号分隔填写多个目录 |
yarn.nodemanager.log-dirs | ${yarn.log.dir}/userlogs | NodeManager容器日志文件存放的本地目录,可用逗号分隔填写多个目录,默认为${yarn.log.dir}/userlogs,“yarn.log.dir”是一个JAVA属性,使用“-D”指定 |
yarn.nodemanager.log.retain-seconds |
| 当不启用日志聚合时,日志文件保留在本地的时长,注意区分yarn.log-aggregation.retain-seconds |
yarn.nodemanager.env-whitelist |
| 从NodeManager继承的环境变量 |
yarn.nodemanager.delete.debug-delay-sec |
| Application执行结束后延迟多少秒后删除本地文件及日志 |
以下为聚合日志配置 | ||
yarn.log-aggregation-enable | false | 值true表示开启日志聚合功能,此项功能会把各NodeManager上的Application的所有盘上的Container聚合保存到HDFS |
yarn.nodemanager.remote-app-log-dir | /app-logs | 聚合日志在HDFS上的存放目录 |
yarn.nodemanager.remote-app-log-dir-suffix | logs | 聚合日志文件实际存放的HDFS目录:${yarn.nodemanager.remote-app-log-dir}/${user}/${thisParam} |
yarn.log-aggregation.retain-seconds | -1 | 聚合日志保留在HDFS上的时长,注意区分yarn.nodemanager.log.retain-seconds,值-1表示一直保留不删除 |
yarn.log-aggregation.retain-check-interval-seconds | -1 | 间隔多久检查一次聚合日志,并将满足条件的删除 |
以下配置,用于NodeManager检测NodeManager是否健康 | ||
yarn.nodemanager.health-checker.script.path |
| 检查节点健康状态的脚本 |
yarn.nodemanager.health-checker.script.opts |
| 传递给检查节点健康状态的脚本的参数 |
yarn.nodemanager.health-checker.interval-ms | 600000 | 检查节点健康状态频率,单位:毫秒 |
yarn.nodemanager.health-checker.script.timeout-ms | 1200000 | 检查节点健康状态的脚本执行超时时长,单位:毫秒 |
以下为ResourceManager配置 | ||
yarn.scheduler.minimum-allocation-vcores | 1 | 单个任务可申请的最少虚拟CPU个数,默认为1 |
yarn.scheduler.maximum-allocation-vcores | 32 | 单个任务可申请的最多虚拟CPU个数,默认为32 |
yarn.scheduler.minimum-allocation-mb | 1024 | 单位:MB,单个任务可申请的最小物理内存量 |
yarn.scheduler.maximum-allocation-mb | 8192 | 注意区别yarn.nodemanager.resource.memory-mb。单位:MB,单个任务可申请的最大物理内存量。可通过YARN的WEB查看内存使用情况:http://192.168.1.21:8088/cluster/nodes(这里的192.168.1.21:8088为ResourceManager的WEB地址)。 |
yarn.resourcemanager.nodes.include-path | /data/hadoop/etc/hadoop/yarn.hosts.permitted | 指定NodeManager白名单文件,文件的每行一个NodeManager主机名件,只需ResourceManager上有此文件 |
yarn.resourcemanager.nodes.exclude-path | /data/hadoop/etc/hadoop/yarn.hosts.excluded | 指定NodeManager黑名单文件,只需ResourceManager上有此文件 |
ACL控制配置 | ||
yarn.acl.enable | false | 是否开启ACLs,默认为false |
yarn.admin.acl |
| 逗号分隔的管理员列表,“*”表示不限定 |
yarn.nodemanager.hostname如果配置成具体的IP,如192.168.1.22,则会导致每个NodeManager的配置不同。详细配置可参考:
http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-common/yarn-default.xml。
Yarn HA的配置可以参考:
https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html。
执行下列操作之前,确保已启动好Zookeeper,并且Zookeeper状态正常可用。请按照顺序完成下列操作,虽然有部分步骤可调换顺序,但按照顺序操作相对简单省事。
按照下列表格完成对mapred-site.xml的修改(注意不是修改NodeManager上的,而应修改ResourceManager上的mapred-site.xml才有效):
属性名 | 属性值 | 说明 |
mapreduce.framework.name | yarn | 所有mapreduce节点 |
mapreduce.job.heap.memory-mb.ratio | 0.8 |
|
mapreduce.map.memory.mb | 1536 | 值过小,在MR时可能遇到错误“Java heap space”。 如果未指定或为负值,则使用“mapreduce.map.java.opts”和“mapreduce.job.heap.memory-mb.ratio”定义的值;如果 mapreduce.map.java.opts也未设置,则默认为1024。 |
mapreduce.map.java.opts | -Xmx1024M |
|
mapreduce.reduce.memory.mb | 3072 | 如果未指定或为负值,则使用“mapreduce.reduce.java.opts”和“mapreduce.job.heap.memory-mb.ratio”定义的值;如果 mapreduce.reduce.java.opts也未设置,则默认为1024。 |
mapreduce.reduce.java.opts | -Xmx2560M |
|
mapreduce.task.io.sort.mb | 512 |
|
mapreduce.task.io.sort.factor | 100 |
|
mapreduce.reduce.shuffle.parallelcopies | 50 |
|
yarn.app.mapreduce.am.env | HADOOP_MAPRED_HOME=$HADOOP_HOME |
|
mapred.child.env | HADOOP_MAPRED_HOME=$HADOOP_HOME | 传递给MR任务的环境变量 |
mapred.child.java.opts | -Xmx1024m | 设置任务的Java选项,如果没有设置-Xmx,则使用“mapreduce.{map|reduce}.memory.mb”定义的值。如果值过小,在执行MR时可能报错“Error: Java heap space”或“running beyond virtual memory limits”。 如果mapred.child.java.opts值大于yarn.scheduler.maximum-allocation-mb的值,则会报错“The required MAP capability is more than the supported max container capability in the cluster”。 |
mapreduce.map.env | HADOOP_MAPRED_HOME=$HADOOP_HOME | 已废弃 |
mapreduce.reduce.env | HADOOP_MAPRED_HOME=$HADOOP_HOME | 已废弃 |
以下为针对 MapReduce JobHistory Server 的配置 (yarn-site.xml中的yarn.log-aggregation-enable值为true和设置了mapreduce.jobhistory.address才会开启)
启动HistoryServer: bin/mapred --daemon start historyserver 停止HistoryServer: bin/mapred --daemon stop historyserver
在集群中的任意一台或多台机器启动即可,以下中的“AM”为“ApplicationMaster”的缩写。 | ||
mapreduce.jobhistory.address | 0.0.0.0:10020 | MapReduce JobHistory Server的RPC服务地址,默认值为0.0.0.0:10020 |
mapreduce.jobhistory.webapp.address | 0.0.0.0:19888 | MapReduce JobHistory Server的WEB服务地址,默认值为0.0.0.0:19888 |
yarn.app.mapreduce.am.staging-dir | /tmp/yarn/staging | 注意这是一个HDFS目录,不是本地目录,默认值为/tmp/hadoop-yarn/staging。ApplicationMaster运行时,将日志写到目录${yarn.app.mapreduce.am.staging-dir}/${user.name}/.staging/job_XXXXX_XXX下,其中后缀为“.jhist”的文件为Job的运行日志。 |
mapreduce.jobhistory.intermediate-done-dir | ${yarn.app.mapreduce.am.staging-dir}/history/done_intermediate | 这也是一个HDFS目录,存放正在运行的Jobs日志文件等 |
mapreduce.jobhistory.done-dir | ${yarn.app.mapreduce.am.staging-dir}/history/done | 也是一个HDFS目录,存放历史(即已完成的)Jobs的日志文件等 |
mapreduce.map.log.level | INFO | MAP任务的日志级别,默认为INFO,其它可选有:OFF/FATAL/ERROR/WARN/INFO/DEBUG/TRACE/ALL |
mapreduce.reduce.log.level |
|
|
mapreduce.shuffle.max.threads | 0 | 混洗线程数,为0表示为CPU核数的两倍 |
详细配置可参考:
这一步是不必须的,但可方便运维管理。建议在目录/etc/profile.d下新建文件hadoop.sh,文件内容如下(最重要的是HADOOP_HOME):
export HADOOP_HOME=/data/hadoop export HADOOP_COMMON_HOME=$HADOOP_HOME export HADOOP_HDFS_HOME=$HADOOP_HOME export HADOOP_YARN_HOME=$HADOOP_HOME export HADOOP_MAPRED_HOME=$HADOOP_HOME #export PATH=$HADOOP_HOME/bin:$PATH # 非必须,但建议也加上 |
当然也可只修改Hadoop用户自己的,比如在~/.bashrc或~/.bash_profile等文件中新增以上内容。
在执行其它操作之前,需要完成以下目录的创建:
配置项 | 本地目录 | 范围 |
hadoop.tmp.dir | /data/hadoop/tmp | 所有机器 |
dfs.journalnode.edits.dir | /data/hadoop/dfs/journalnode/ | 所有JournalNode机器 |
dfs.datanode.data.dir | /data/hadoop/dfs/data | 所有DataNode机器 |
dfs.namenode.name.dir | /data/hadoop/dfs/namenode | 所有NameNode机器 |
这一步必须在其它步骤之前先完成,实际为Zookeeper操作,而且只需要任意一台NameNode上操作。进入NameNode的bin目录,然后执行:
$HADOOP_HOME/bin/hdfs zkfc -formatZK |
如果运行没有出错信息,就表示成功:
2019-09-23 15:11:58,587 INFO tools.DFSZKFailoverController: registered UNIX signal handlers for [TERM, HUP, INT] 2019-09-23 15:11:58,844 INFO tools.DFSZKFailoverController: Failover controller configured for NameNode NameNode at hadoop-001/192.168.1.21:8020 2019-09-23 15:11:58,933 INFO zookeeper.ZooKeeper: Client environment:zookeeper.version=3.4.13-2d71af4dbe22557fda74f9a9b4309b15a7487f03, built on 06/29/2018 00:39 GMT 2019-09-23 15:11:58,933 INFO zookeeper.ZooKeeper: Client environment:host.name=hadoop-001 2019-09-23 15:11:58,933 INFO zookeeper.ZooKeeper: Client environment:java.version=1.8.0_221 2019-09-23 15:11:58,933 INFO zookeeper.ZooKeeper: Client environment:java.vendor=Oracle Corporation 2019-09-23 15:11:58,933 INFO zookeeper.ZooKeeper: Client environment:java.home=/usr/local/jdk1.8.0_221/jre 2019-09-23 15:11:58,933 INFO zookeeper.ZooKeeper: Client environment:java.class.path=/data/hadoop/etc/hadoop: 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:java.library.path=/data/hadoop/lib/native 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:java.io.tmpdir=/tmp 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:java.compiler=<NA> 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:os.name=Linux 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:os.arch=amd64 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:os.version=3.10.107-1-tlinux2-0046 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:user.name=hadoop 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:user.home=/home/hadoop 2019-09-23 15:11:58,934 INFO zookeeper.ZooKeeper: Client environment:user.dir=/data/hadoop-3.1.2/bin 2019-09-23 15:11:58,935 INFO zookeeper.ZooKeeper: Initiating client connection, connectString=hadoop-003:2181,hadoop-004:2181,hadoop-005:2181,hadoop-006:2181,hadoop-007:2181 sessionTimeout=10000 watcher=org.apache.hadoop.ha.ActiveStandbyElector$WatcherWithClientRef@7722c3c3 2019-09-23 15:11:58,948 INFO zookeeper.ClientCnxn: Opening socket connection to server hadoop10111/9.2.167.183:2181. Will not attempt to authenticate using SASL (unknown error) 2019-09-23 15:11:58,952 INFO zookeeper.ClientCnxn: Socket connection established to hadoop-003/9.2.167.183:2181, initiating session 2019-09-23 15:11:58,960 INFO zookeeper.ClientCnxn: Session establishment complete on server hadoop10111/9.2.167.183:2181, sessionid = 0xb086f1716e10000, negotiated timeout = 10000 2019-09-23 15:11:58,962 INFO ha.ActiveStandbyElector: Session connected. 2019-09-23 15:11:58,979 INFO ha.ActiveStandbyElector: Successfully created /hadoop-ha/hdfs-cluster in ZK. 2019-09-23 15:11:58,981 INFO zookeeper.ZooKeeper: Session: 0xb086f1716e10000 closed 2019-09-23 15:11:58,982 INFO zookeeper.ClientCnxn: EventThread shut down for session: 0xb086f1716e10000 2019-09-23 15:11:58,982 INFO tools.DFSZKFailoverController: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down DFSZKFailoverController at hadoop-001/192.168.1.21 ************************************************************/ |
格式化成功后,会在ZooKeeper上创建core-site.xml中ha.zookeeper.parent-znode指定的路径。
[zk: localhost:2181(CONNECTED) 1] ls / [hadoop-ha, zookeeper] [zk: localhost:2181(CONNECTED) 2] ls /hadoop-ha [SHBX-hdfs-cluster] [zk: localhost:2181(CONNECTED) 3] ls /hadoop-ha/SHBX-hdfs-cluster [] |
如果有修改hdfs-site.xml中的dfs.ha.namenodes.hdfs-cluster值,则需要重新做一次formatZK,否则自动主备NameNode切换将失效。zkfc进程的日志文件将发现如下信息(假设nm1改成了nn1):
Unable to determine service address for namenode 'nm1' |
另外需注意,如果有修改dfs.ha.namenodes.hdfs-cluster,上层的HBase等依赖HBase的也需要重启。
查看格式化后的Zookeeper变化:
$ ./zkCli.sh Connecting to localhost:2181 Welcome to ZooKeeper! JLine support is enabled
WATCHER::
WatchedEvent state:SyncConnected type:None path:null [zk: localhost:2181(CONNECTED) 0] ls / [zookeeper, hadoop-ha] [zk: localhost:2181(CONNECTED) 1] ls /hadoop-ha [hdfs-cluster] [zk: localhost:2181(CONNECTED) 2] get /hadoop-ha/hdfs-cluster
cZxid = 0x200000005 ctime = Thu Oct 11 17:16:25 CST 2018 mZxid = 0x200000005 mtime = Thu Oct 11 17:16:25 CST 2018 pZxid = 0x200000005 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 0 numChildren = 0 |
NameNode将元数据操作日志记录在JournalNode上,主备NameNode通过记录在JouralNode上的日志完成元数据同步。
在所有JournalNode上执行(注意不是$HADOOP_HOME/bin/hadoop-daemon.sh start journalnode):
$HADOOP_HOME/bin/hdfs --daemon start journalnode |
这一步必须在格式化NameNode之前执行,因为格式化NameNode会操作JournalNode集群。
在主NameNode上执行以下命令(注意只能在主NameNode上执行):
$HADOOP_HOME/bin/hdfs namenode -format hdfs-cluster |
如果进行顺利,输出内容如下所示:
[hadoop@hadoop-001 /data/hadoop/bin]$ ls /data/hadoop/dfs/namenode/ [hadoop@hadoop-001 /data/hadoop/bin]$ ./hdfs namenode -format hdfs-cluster WARNING: /data/hadoop/logs does not exist. Creating. ************************************************************/ 2019-09-23 15:57:20,747 INFO namenode.NameNode: registered UNIX signal handlers for [TERM, HUP, INT] 2019-09-23 15:57:20,824 INFO namenode.NameNode: createNameNode [-format, hdfs-cluster] Formatting using clusterid: CID-6cf9848f-9744-4582-b7bf-a0f22458bfc1 2019-09-23 15:57:21,251 INFO namenode.FSEditLog: Edit logging is async:true 2019-09-23 15:57:21,265 INFO namenode.FSNamesystem: KeyProvider: null 2019-09-23 15:57:21,266 INFO namenode.FSNamesystem: fsLock is fair: true 2019-09-23 15:57:21,267 INFO namenode.FSNamesystem: Detailed lock hold time metrics enabled: false 2019-09-23 15:57:21,272 INFO namenode.FSNamesystem: fsOwner = hadoop (auth:SIMPLE) 2019-09-23 15:57:21,272 INFO namenode.FSNamesystem: supergroup = supergroup 2019-09-23 15:57:21,272 INFO namenode.FSNamesystem: isPermissionEnabled = true 2019-09-23 15:57:21,272 INFO namenode.FSNamesystem: Determined nameservice ID: hdfs-cluster 2019-09-23 15:57:21,272 INFO namenode.FSNamesystem: HA Enabled: true 。。。。。。 2019-09-23 15:57:23,781 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at hadoop-001/192.168.1.21 ************************************************************/ [hadoop@hadoop-001 /data/hadoop/bin]$ ls /data/hadoop/dfs/namenode/ current |
格式化成功后,可在该NameNode的数据目录下看到如下内容(由hdfs-site.xml中的dfs.namenode.name.dir决定):
[hadoop@hadoop-001 /data/hadoop/bin]$ ls /data/hadoop/dfs/namenode/current/ fsimage_0000000000000000000 fsimage_0000000000000000000.md5 seen_txid VERSION |
这个时候的fsimage_0000000000000000000实际是空的,只有个文件头。
在进行格式化时,如果没有在/etc/hosts文件中添加主机名和IP的映射:“192.168.1.21 hadoop-001”,则会报如下所示错误:
23/09/1003:44:09 WARN net.DNS: Unable to determine local hostname -falling back to "localhost" java.net.UnknownHostException: hadoop-001: hadoop-001: unknown error at java.net.InetAddress.getLocalHost(InetAddress.java:1484) at org.apache.hadoop.net.DNS.resolveLocalHostname(DNS.java:264) at org.apache.hadoop.net.DNS.<clinit>(DNS.java:57) at org.apache.hadoop.hdfs.server.namenode.NNStorage.newBlockPoolID(NNStorage.java:945) at org.apache.hadoop.hdfs.server.namenode.NNStorage.newNamespaceInfo(NNStorage.java:573) at org.apache.hadoop.hdfs.server.namenode.FSImage.format(FSImage.java:144) at org.apache.hadoop.hdfs.server.namenode.NameNode.format(NameNode.java:845) at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1256) at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1370) Caused by: java.net.UnknownHostException: hadoop-001: unknown error at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method) at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:907) at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1302) at java.net.InetAddress.getLocalHost(InetAddress.java:1479) ... 8 more
|
格式化NameNode产生的版本信息存储在文件VERSION中:
[hadoop@hadoop-001 /data/hadoop/bin]$ cat /data/hadoop/dfs/namenode/current/VERSION #Mon Sep 23 15:57:22 CST 2019 namespaceID=1732498488 clusterID=CID-6cf9848f-9744-4582-b7bf-a0f22458bfc1 cTime=1569225442971 storageType=NAME_NODE blockpoolID=BP-1854934288-192.168.1.21-1569225442971 layoutVersion=-64 |
注意cTime值的单位是毫秒而不是秒,转成人类可读时间如下:
[hadoop@hadoop-001 /data/hadoop/bin]$ date --date='@1569225442' '+%Y-%m-%d %H:%M:%S' 2019-09-23 15:57:22 |
如果hdfs-site.xml中配置为自动主备切换,则主NameNode起来时,实际是备状态(standby)。
启动NameNode命令:
$HADOOP_HOME/bin/hdfs --daemon start namenode |
使用jps查看NameNode进程是否已经拉起来:
[hadoop@hadoop-001 /data/hadoop/bin]$ jps 160097 NameNode 160185 Jps |
查看NameNode的监听端口是否起来了(以NameNode的IP为192.168.1.21为例,为NameNode的RPC端口为8020,NameNode的HTTP端口为9870):
[hadoop@hadoop-001 /data/hadoop/bin]$ jps 160097 NameNode 161149 Jps [hadoop@hadoop10102 /data/hadoop/bin]$ netstat -lpnt|grep 160097 (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp 0 0 192.168.1.21:8020 0.0.0.0:* LISTEN 160097/java tcp 0 0 192.168.1.21:9870 0.0.0.0:* LISTEN 160097/java |
主NameNode启动时,会在Zookeeper的路径“${ha.zookeeper.parent-znode}/${dfs.nameservices}”下分别创建一个临时节点ActiveStandbyElectorLock和永久节点ActiveBreadCrumb。
当临时节点ActiveStandbyElectorLock消失时,备NameNode会尝试竞争为主NameNode。永久节点ActiveBreadCrumb用来防止脑裂,ZKFC通过它来做Fencing,ActiveBreadCrumb保存了主NameNoded的地址信息。
这个时候如果还没启动主备切换进程,查看NameNode状态时,可看到为standy状态,即备状态:
[hadoop@hadoop-001 /data/hadoop/bin]$ ./hdfs haadmin -getServiceState nn1 standby |
由于当前还没有一个主NameNode,所以刚启动的NameNode会以备NameNode身份尝试连接主NameNode。当hdfs-site.xml的dfs.ha.namenodes.hdfs-cluster配置了两个或更多NameNode时,会尝试连接自身之外的另一个NameNode。日志文件会出现如下内容:
2019-09-23 16:18:20,570 WARN org.apache.hadoop.hdfs.server.namenode.ha.EditLogTailer: Exception from remote name node RemoteNameNodeInfo [nnId=nn2, ipcAddress=hadoop-002/192.168.1.22:8020, httpAddress=http://hadoop-002:9870], try next. java.net.ConnectException: Call From hadoop-002/192.168.1.21 to 192.168.1.22:8020 failed on connection exception: java.net.ConnectException: 拒绝连接; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.apache.hadoop.net.NetUtils.wrapWithMessage(NetUtils.java:831) at org.apache.hadoop.net.NetUtils.wrapException(NetUtils.java:755) at org.apache.hadoop.ipc.Client.getRpcResponse(Client.java:1515) at org.apache.hadoop.ipc.Client.call(Client.java:1457) at org.apache.hadoop.ipc.Client.call(Client.java:1367) at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:228) at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:116) at com.sun.proxy.$Proxy19.rollEditLog(Unknown Source) at org.apache.hadoop.hdfs.protocolPB.NamenodeProtocolTranslatorPB.rollEditLog(NamenodeProtocolTranslatorPB.java:150) at org.apache.hadoop.hdfs.server.namenode.ha.EditLogTailer$2.doWork(EditLogTailer.java:365) at org.apache.hadoop.hdfs.server.namenode.ha.EditLogTailer$2.doWork(EditLogTailer.java:362) at org.apache.hadoop.hdfs.server.namenode.ha.EditLogTailer$MultipleNameNodeProxy.call(EditLogTailer.java:504) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.net.ConnectException: 拒绝连接 |
-
- 启动主备切换进程zkfc
zkfc是zookeeper failover controller的缩写,负责NameNode的主备切换,只需在NameNode上执行,而且这一步可在“启动主NameNode”前。为启动主备切换进程,执行以下命令:
$HADOOP_HOME/bin/hdfs --daemon start zkfc |
只有启动了主备切换进程DFSZKFailoverController,NameNode才能自动切换主备。
$ ./hdfs haadmin -getServiceState nn1 active |
如果先将两个NameNode启动好,再启动主备切换进程,则哪个为主NameNode是不确定的。
多个备NameNode启动步骤和方式相同,第一次启动一个备NameNode前,需要先在这个备NameNode上执行:
$HADOOP_HOME/bin/hdfs namenode -bootstrapStandby |
这一步的作用是同步主NameNode上的fsimage文件,注意只有第一次启动NameNode才需要。
[hadoop@hadoop-002 /data/hadoop/bin]$ ls /data/hadoop/dfs/namenode/ [hadoop@hadoop-002 /data/hadoop/bin]$ ./hdfs namenode -bootstrapStandby [hadoop@hadoop-002 /data/hadoop/bin]$ ls /data/hadoop/dfs/namenode/ current |
然后和启动主NameNode方式相同启动备NameNode:
$HADOOP_HOME/bin/hdfs --daemon start namenode |
如果没有执行第1步,直接启动会遇到如下错误:
No valid image files found |
或者在该NameNode日志会发现如下错误:
2019-09-23 16:08:39,745 WARN org.apache.hadoop.hdfs.server.namenode.FSNamesystem: Encountered exception loading fsimage java.io.IOException: NameNode is not formatted. |
注意,在备NameNode上也需要启动“主备切换进程zkfc”,这样当主NameNode异常时,备NameNode才能变成主NameNode。
查看NameNode主备状态:
[hadoop@hadoop-001 /data/hadoop/bin]$ ./hdfs haadmin -getServiceState nn1 active [hadoop@hadoop-001 /data/hadoop/bin]$ ./hdfs haadmin -getServiceState nn2 standby |
HDFS集群就差DataNode没有启动了,这一步将所有DataNode启动起来。方法同样十分简单,只需在所有DataNode上执行下述命令:
$HADOOP_HOME/bin/hdfs --daemon start datanode |
批量启动DataNode:
mooon_ssh -c='/data/hadoop/bin/hdfs --daemon start datanode' -u=hadoop -p='123456' -h='' |
如果有发现DataNode进程并没有起来,可以试试删除logs目录下的DataNode日志,再得启看看。
执行命令“hdfs dfsadmin -report”检查DataNode状态,以确定DataNode是否启动成功。正常应看到如下内容:
[hadoop@hadoop-001 /data/hadoop/bin]$ ./hdfs dfsadmin -report Configured Capacity: 42518699704320 (38.67 TB) Present Capacity: 40066804686848 (36.44 TB) DFS Remaining: 40066804097024 (36.44 TB) DFS Used: 589824 (576 KB) DFS Used%: 0.00% Replicated Blocks: Under replicated blocks: 0 Blocks with corrupt replicas: 0 Missing blocks: 0 Missing blocks (with replication factor 1): 0 Low redundancy blocks with highest priority to recover: 0 Pending deletion blocks: 0 Erasure Coded Block Groups: Low redundancy block groups: 0 Block groups with corrupt internal blocks: 0 Missing block groups: 0 Low redundancy blocks with highest priority to recover: 0 Pending deletion blocks: 0
------------------------------------------------- Live datanodes (5): |
执行下命令即可完成手动切换,以将nn2切换为主NameNode为例,只需要执行:
$HADOOP_HOME/bin/hdfs haadmin -transitionToActive nn2 |
强制切换,使用如下命令(自动切换模式不支持):
hdfs haadmin -failover --forcefence --forceactive nn1 nn2 # 让nn2成为主NameNode |
在所有ResourceManager机器或节点上执行以下命令启动ResourceManager:
$HADOOP_HOME/bin/yarn --daemon start resourcemanager |
如果ResourceManager不能自动主备切换,检查下是否有其它的ResourceManager正占用着Zookeeper。
在所有NodeManager机器或节点上执行以下命令启动NodeManager:
$HADOOP_HOME/bin/yarn --daemon start nodemanager |
正常情况下,可执行“yarn --daemon stop nodemanager”来停掉NodeManager,但如果执行时遇到错误“no nodemanager to stop”,则可通过如下方式:
kill `/usr/local/jdk/bin/jps | awk '/NodeManager/{print $1}' ` |
对应的批量操作:
mooon_ssh -c="kill \`/usr/local/jdk/bin/jps | awk '/NodeManager/{print \$1}' \`" |
在集群中的任意一台或多台机器启动即可,并不需要在每一台机器上都启动HistoryServer。
HistoryServer的默认Web端口为19888,由mapred-site.xml中的mapreduce.jobhistory.webapp.address控制。假设在192.168.1.21上启动了HistoryServer,则可浏览器打开“http://192.168.1.21:19888”查看。
如果有防火墙挡住了端口19888,则应修改mapreduce.jobhistory.webapp.address的值,或者使用rinetd或sshd等工具转发到19888。
bin/mapred --daemon start historyserver |
bin/mapred --daemon stop historyserver |
“hdfs dfs -ls”带一个参数,如果参数以“hdfs://URI”打头表示访问HDFS,否则相当于ls。其中URI为NameNode的IP或主机名,可以包含端口号,即hdfs-site.xml中“dfs.namenode.rpc-address”指定的值。
“hdfs dfs -ls”要求默认端口为8020,如果配置成9000,则需要指定端口号,否则不用指定端口,这一点类似于浏览器访问一个URL。示例:
> hdfs dfs -ls hdfs:///192.168.1.21:9001/ |
9001后面的斜杠/是和必须的,否则被当作文件。如果不指定端口号9001,则使用默认的8020,“192.168.1.21:9001”由hdfs-site.xml中“dfs.namenode.rpc-address”指定。
不难看出“hdfs dfs -ls”可以操作不同的HDFS集群,只需要指定不同的URI。
文件上传后,被存储在DataNode的data目录下(由DataNode的hdfs-site.xml中的属性“dfs.datanode.data.dir”指定),如:
$HADOOP_HOME/data/current/BP-139798373-192.168.1.21-1397735615751/current/finalized/blk_1073741825
文件名中的“blk”是block,即块的意思,默认情况下blk_1073741825即为文件的一个完整块,Hadoop未对它进额外处理。
上传文件命令,示例:
> hdfs dfs -put /etc/SuSE-release hdfs:///192.168.1.21:9001/ |
删除文件命令,示例:
> hdfs dfs -rm hdfs://192.168.1.21:9001/SuSE-release Deleted hdfs://192.168.1.21:9001/SuSE-release |
hdfs fsck hdfs:///tmp/slaves -files -locations -blocks |
hdfs dfsadmin -safemode leave |
hdfs fsck -delete |
在扩容过程中,有可能遇到DataNode启动时未向NameNode上报block信息。正常时,NameNode都会通过心跳响应的方式告诉DataNode上报block,但当NameNode和DataNode版本不一致等时,可能会使这个机制失效。搜索DataNode的日志文件,将搜索不到上报信息日志“sent block report”。
这个时候,一旦重启NameNode,就会出现大量“missing block”。幸好HDFS提供了工具,可以直接强制DataNode上报block,方法为:
hdfs dfsadmin -triggerBlockReport '192.168.1.21:50020 |
上述'192.168.1.21为DataNode的IP地址,50020为DataNode的RPC端口。最终应当保持DataNode和NameNode版本一致,不然得每次做一下这个操作,而且可能还有其它问题存在。
如果是扩容,将已有JournalNode的current目录打包到新机器的“dfs.journalnode.edits.dir”指定的相同位置下。
为保证扩容和缩容JournalNode成功,需要先将NameNode和JournalNode全停止掉,再修改配置,然后在启动JournalNode成功后(日志停留在“IPC Server listener on 8485: starting”处),再启动NameNode,否则可能遇到如下这样的错误:
org.apache.hadoop.hdfs.qjournal.protocol.JournalOutOfSyncException: Can't write, no segment open |
找一台已有JournalNode节点,修改它的hdfs-site.xml,将新增的Journal包含进来,如在
<value>qjournal://hadoop-003:8485;hadoop-004:8485;hadoop-005:8485/test</value>
的基础上新增hadoop-033和hadoop-034两个JournalNode:
<value>qjournal://hadoop-003:8485;hadoop-004:8485;hadoop-005:8485;hadoop-006:8485;hadoop-007:8485/test</value>
然后将安装目录和数据目录(hdfs-site.xml中的dfs.journalnode.edits.dir指定的目录)都复制到新的节点。
如果不复制JournalNode的数据目录,则新节点上的JournalNode可能会报错“Journal Storage Directory /data/journal/test not formatted”,将来的版本可能会实现自动同步。ZooKeeper的扩容不需要复制已有节点的data和datalog,而且也不能这样操作。
接下来,就可以在新节点上启动好JournalNode(不需要做什么初始化),并重启下NameNode。注意观察JournalNode日志,查看是否启动成功,当日志显示为以下这样的INFO级别日志则表示启动成功:
2019-09-26 10:31:11,160 INFO org.apache.hadoop.hdfs.server.namenode.FileJournalManager: Finalizing edits file /data/journal/test/current/edits_inprogress_0000000000000194269 -> /data/journal/test/current/edits_0000000000000194269-0000000000000194270
但只能出现如下的日志,才表示工作正常:
2019-09-18 15:22:42,901 INFO org.apache.hadoop.ipc.Server: IPC Server listener on 8485: starting 2019-09-18 15:23:27,028 INFO org.apache.hadoop.hdfs.qjournal.server.JournalNode: Initializing journal in directory /data/journal/data/test 2019-09-18 15:23:27,042 INFO org.apache.hadoop.hdfs.server.common.Storage: Lock on /data/journal/data/test/in_use.lock acquired by nodename 15259@hadoop-003 2019-09-18 15:23:27,057 INFO org.apache.hadoop.hdfs.qjournal.server.Journal: Scanning storage FileJournalManager(root=/data/journal/data/test) 2019-09-18 15:23:27,152 INFO org.apache.hadoop.hdfs.qjournal.server.Journal: Latest log is EditLogFile(file=/data/journal/data/test/current/edits_inprogress_0000000000027248811,first=0000000000027248811,last=0000000000027248811,inProgress=true,hasCorruptHeader=false) |
-
-
- 新增NameNode
-
记得更换NameNode后,需要重新执行“hdfs zkfc -formatZK”,否则将不能自动主备切换。
当有NameNode机器损坏时,必然存在新NameNode来替代。把配置修改成指向新NameNode,然后以备机形式启动新NameNode,这样新的NameNode即加入到Cluster中:
|
记启动主备切换进程DFSZKFailoverController,否则将不能自动做主备切换!!!
新的NameNode通过bootstrapStandby操作从主NameNode拉取fsImage(hadoop-001:50070为主NameNode):
19/09/24 14:25:32 INFO namenode.TransferFsImage: Opening connection to http://hadoop-002:50070/imagetransfer?getimage=1&txid=2768127&storageInfo=-63:2009831148:1492719902489:CID-5b2992bb-4dcb-4211-8070-6934f4d232a8&bootstrapstandby=true 19/09/24 14:25:32 INFO namenode.TransferFsImage: Image Transfer timeout configured to 60000 milliseconds 19/09/24 14:25:32 INFO namenode.TransferFsImage: Transfer took 0.01s at 28461.54 KB/s 19/09/24 14:25:32 INFO namenode.TransferFsImage: Downloaded file fsimage.ckpt_0000000000002768127 size 379293 bytes. |
如果没有足够多的DataNode连接到NameNode,则NameNode也会进入safe模式,下面的信息显示只有0台DataNodes连接到了NameNode。
原因有可能是因为修改了dfs.ha.namenodes.hdfs-cluster的值,导致DataNode不认识,比如将nm1改成了nn1等,这个时候还需要重新formatZK,否则自动主备切换将失效。
如果DataNode上的配置也同步修改了,但修改后未重启,则需要重启DataNode:
Safe mode is ON. The reported blocks 0 needs additional 12891 blocks to reach the threshold 0.9990 of total blocks 12904. The number of live datanodes 0 has reached the minimum number 0. Safe mode will be turned off automatically once the thresholds have been reached. |
-
-
- 扩容DataNode
-
兼容的版本可跨版本扩容,比如由Hadoop-3.1.1扩容Hadoop-3.1.2。扩容方法为在新增的机器上安装和配置好DataNode,在成功启动DataNode后,在主NameNode上执行命令:bin/hdfs dfsadmin -refreshNodes,即完成扩容。如果有配置dfs.hosts,则在执行refreshNodes前,需先加新扩的DataNode加入到dfs.hosts指向的文件中。
如要数据均衡到新加入的机器,执行命令:sbin/start-balancer.sh,可带参数-threshold,默认值为10,如:sbin/start-balancer.sh -threshold 5。参数-threshold的取值范围为0~100。
balancer命令可在NameNode和DataNode上执行,但最好在新增机器或空闲机器上执行。
参数-threshold的值表示节点存储使用率和集群存储使用率间的关系,如果节点的存储使用率小于集群存储的使用率,则执行balance操作。
-
-
- 下线DataNode
-
本操作需在主NameNode上进行,即状态为active的NameNode上进行!!!如果备NameNode也运行着,建议备的hdfs-site.xml也做同样修改,以防止下线过程中发现主备NameNode切换,或者干脆停掉备NameNode。
下线完成后,记得将hdfs-site.xml修改回来(即将dfs.hosts.exclude值恢复为空值),如果不修改回来,那被下线掉的DataNode将一直处于Decommissioned状态,同时还得做一次“/data/hadoop/bin/hdfs dfsadmin -refreshNodes”,否则被下线的DataNode一直处于Decommissioned状态。
下线后,只要配置了dfs.hosts,即使被下线的DataNode进程未停掉,也不会再连接进来,而且这是推荐的方式,以防止外部的DataNode无意中连接进来。
但在将dfs.hosts.exclude值恢复为空值之前,需要将已下线的所有DataNode进程停掉,最好还设置hdfs-site.xml中的dfs.hosts值,以限制可以连接NameNode的DataNode,不然一不小心,被下线的DataNode又连接上来了,切记!另外注意,如果有用到slaves文件,也需要slaves同步修改。
修改主NameNode的hdfs-site.xml,设置dfs.hosts.exclude的值,值为一文件的全路径,如:/data/hadoop/etc/hadoop/hosts.exclude。文件内容为需要下线(即删除)的DataNode的机器名或IP,每行一个机器名或IP(注意暂不要将下线的DataNode从slaves中剔除)。
修改完hdfs-site.xml后,在主NameNode上执行:bin/hdfs dfsadmin -refreshNodes,以刷新DataNode,下线完成后可同扩容一样做下balance。
使用命令bin/hdfs dfsadmin -report或web界面可以观察下线的DataNode退役(Decommissioning)状态。完成后,将下线的DataNode从slaves中剔除。
下线前的状态:
$ hdfs dfsadmin -report Name: 192.168.1.21:50010 (hadoop-001) Hostname: hadoop-001 Decommission Status : Normal Configured Capacity: 3247462653952 (2.95 TB) DFS Used: 297339283 (283.56 MB) Non DFS Used: 165960652397 (154.56 GB) DFS Remaining: 3081204662272 (2.80 TB) DFS Used%: 0.01% DFS Remaining%: 94.88% Configured Cache Capacity: 0 (0 B) Cache Used: 0 (0 B) Cache Remaining: 0 (0 B) Cache Used%: 100.00% Cache Remaining%: 0.00% Xceivers: 1 Last contact: Wed Apr 19 18:03:33 CST 2017 |
下线进行中的的状态:
$ hdfs dfsadmin -report Name: 192.168.1.21:50010 (hadoop-001) Hostname: hadoop-001 Decommission Status : Decommission in progress Configured Capacity: 3247462653952 (2.95 TB) DFS Used: 297339283 (283.56 MB) Non DFS Used: 165960652397 (154.56 GB) DFS Remaining: 3081204662272 (2.80 TB) DFS Used%: 0.01% DFS Remaining%: 94.88% Configured Cache Capacity: 0 (0 B) Cache Used: 0 (0 B) Cache Remaining: 0 (0 B) Cache Used%: 100.00% Cache Remaining%: 0.00% Xceivers: 16 Last contact: Thu Apr 20 09:00:48 CST 2017 |
下线完成后的状态:
$ hdfs dfsadmin -report Name: 192.168.1.21:50010 (hadoop-001) Hostname: hadoop-001 Decommission Status : Decommissioned Configured Capacity: 1935079350272 (1.76 TB) DFS Used: 257292167968 (239.62 GB) Non DFS Used: 99063741175 (92.26 GB) DFS Remaining: 1578723441129 (1.44 TB) DFS Used%: 13.30% DFS Remaining%: 81.58% Configured Cache Capacity: 0 (0 B) Cache Used: 0 (0 B) Cache Remaining: 0 (0 B) Cache Used%: 100.00% Cache Remaining%: 0.00% Xceivers: 13 Last contact: Thu Apr 20 09:29:00 CST 2017 |
如果长时间处于“Decommission In Progress”状态,而不能转换成Decommissioned状态,这个时候可用“hdfs fsck”检查下。
成功下线后,还需要将该节点从slaves中删除,以及dfs.hosts.exclude中剔除,然后再做一下:bin/hdfs dfsadmin -refreshNodes。
- YARN命令
- 查看节点列表:yarn node -list
列举YARN集群中的所有NodeManager,如(注意参数间的空格,直接执行yarn可以看到使用帮助):
> yarn node -list Total Nodes:3 Node-Id Node-State Node-Http-Address Number-of-Running-Containers localhost:45980 RUNNING localhost:8042 0 localhost:47551 RUNNING localhost:8042 0 localhost:58394 RUNNING localhost:8042 0 |
-
- 查看节点状态:yarn node -status
查看指定NodeManager的状态,如:
> yarn node -status localhost:47551 Node Report : Node-Id : localhost:47551 Rack : /default-rack Node-State : RUNNING Node-Http-Address : localhost:8042 Last-Health-Update : 星期五 18/四月/14 01:45:41:555GMT Health-Report : Containers : 0 Memory-Used : 0MB Memory-Capacity : 8192MB CPU-Used : 0 vcores CPU-Capacity : 8 vcores |
-
- 查看状态:yarn rmadmin -getServiceState rm1
查看rm1的主备状态,即查看它是主(active)还是备(standby)。
-
- 人工切换:yarn rmadmin -transitionToStandby rm1
将rm1从主切为备,更多的yarn命令可以参考:
https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/YarnCommands.html。
不带参数执行“yarn application”,可显示帮助信息,使用“yarn application”还可杀死或优雅停止指定的应用(Application),以及显示应用状态等。
不带参数执行“hadoop job”,可显示帮助信息,使用“hadoop job”还可杀死指定的作业(Job),以及显示作业状态等。
在安装目录的share/hadoop/mapreduce子目录下,有现存的示例程序:
~/hadoop> ls share/hadoop/mapreduce hadoop-mapreduce-client-app-3.1.2.jar hadoop-mapreduce-client-hs-plugins-3.1.2.jar hadoop-mapreduce-client-shuffle-3.1.2.jar lib hadoop-mapreduce-client-common-3.1.2.jar hadoop-mapreduce-client-jobclient-3.1.2-tests.jar hadoop-mapreduce-client-uploader-3.1.2.jar lib-examples hadoop-mapreduce-client-core-3.1.2.jar hadoop-mapreduce-client-jobclient-3.1.2.jar hadoop-mapreduce-examples-3.1.2.jar sources hadoop-mapreduce-client-hs-3.1.2.jar hadoop-mapreduce-client-nativetask-3.1.2.jar jdiff |
跑一个示例程序试试:
hdfs dfs -put /etc/hosts hdfs:///test/in/ hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar wordcount hdfs:///test/in/ hdfs:///test/out/ |
运行过程中,使用java的jps命令,可以看到yarn启动了名为YarnChild的进程。
wordcount运行完成后,结果会保存在out目录下,保存结果的文件名类似于“part-r-00000”。另外,跑这个示例程序有两个需求注意的点:
- in目录下要有文本文件,或in即为被统计的文本文件,可以为HDFS上的文件或目录,也可以为本地文件或目录
- out目录不能存在,程序会自动去创建它,如果已经存在则会报错。
包hadoop-mapreduce-examples-3.1.2.jar中含有多个示例程序,不带参数运行,即可看到用法:
> hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar wordcount Usage: wordcount <in> <out>
> hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar An example program must be given as the first argument. Valid program names are: aggregatewordcount: An Aggregate based map/reduce program that counts the words in the input files. aggregatewordhist: An Aggregate based map/reduce program that computes the histogram of the words in the input files. bbp: A map/reduce program that uses Bailey-Borwein-Plouffe to compute exact digits of Pi. dbcount: An example job that count the pageview counts from a database. distbbp: A map/reduce program that uses a BBP-type formula to compute exact bits of Pi. grep: A map/reduce program that counts the matches of a regex in the input. join: A job that effects a join over sorted, equally partitioned datasets multifilewc: A job that counts words from several files. pentomino: A map/reduce tile laying program to find solutions to pentomino problems. pi: A map/reduce program that estimates Pi using a quasi-Monte Carlo method. randomtextwriter: A map/reduce program that writes 10GB of random textual data per node. randomwriter: A map/reduce program that writes 10GB of random data per node. secondarysort: An example defining a secondary sort to the reduce. sort: A map/reduce program that sorts the data written by the random writer. sudoku: A sudoku solver. teragen: Generate data for the terasort terasort: Run the terasort teravalidate: Checking results of terasort wordcount: A map/reduce program that counts the words in the input files. wordmean: A map/reduce program that counts the average length of the words in the input files. wordmedian: A map/reduce program that counts the median length of the words in the input files. wordstandarddeviation: A map/reduce program that counts the standard deviation of the length of the words in the input files. |
修改日志级别为DEBBUG,并打屏:
export HADOOP_ROOT_LOGGER=DEBUG,console |
附1:log4j日志级别
Log4j日志分成以下几个级别:
级别名 | 级别说明 |
OFF | 不打印任何日志 |
ALL | 打印所有日志 |
TRACE | 比DEBUG更详细的日志,一般用于开发测试或定位问题 |
DEBUG | 调试日志,一般用于开发测试或定位问题 |
INFO | 基本信息级别日志 |
WARN | 警告类日志 |
ERROR | 出错日志 |
FATAL | 致命日志 |
日志级别排序:
ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF |
附2:crontab监控脚本
使用这种方法,不需要在Master和Slaves节点间建立免密码登录关系,因为相关进程由crontab拉起,并不需要显示调用start-all.sh、start-dfs.sh、start-yarn.sh、start-hbase.sh等。
- 监控工具下载:
https://github.com/eyjian/libmooon/blob/master/shell/process_monitor.sh
- 监控工具使用示例:
PMONITOR=/usr/local/bin/process_monitor.sh JAVA=/usr/local/jdk/bin/java ZK_SERVER=/data/zookeeper/bin/zkServer.sh HDFS=/data/hadoop/bin/hdfs YARN=/data/hadoop/bin/yarn HBASE_DAEMON=/data/hbase/bin/hbase-daemon.sh
# 监控 ZooKeeper * * * * * $PMONITOR "$JAVA -Dzookeeper" "$ZK_SERVER start"
# 监控 HDFS NameNode(仅在 Master 上启动) * * * * * $PMONITOR "$JAVA -Dproc_namenode" "$HDFS --daemon start namenode"
# 监控 HDFS 切换主备 NameNode 程序(仅在 Master 上启动) * * * * * $PMONITOR "$JAVA -Dproc_zkfc" "$HDFS --daemon start zkfc"
# 监控 HDFS JournalNode(仅在 JournalNode 上启动) #* * * * * $PMONITOR "$JAVA -Dproc_journalnode" "$HDFS --daemon start journalnode"
# 监控 HDFS DataNode(仅在 DataNode 上启动) #* * * * * $PMONITOR "$JAVA -Dproc_datanode" "$HDFS --daemon start datanode"
# 监控 YARN ResourceManager(仅在 Master 上启动) * * * * * $PMONITOR "$JAVA -Dproc_resourcemanager" "$YARN --daemon start resourcemanager"
# 监控 YARN NodeManager(一般和 DataNode 共享相同机器) #* * * * * $PMONITOR "$JAVA -Dproc_nodemanager" "$YARN --daemon start nodemanager"
# 监控HBase Master(仅在 Master 上启动) #* * * * * $PMONITOR "$JAVA -Dproc_master" "$HBASE_DAEMON start master"
# 监控HBase regionserver(仅在 RegionServer 上启动) #* * * * * $PMONITOR "$JAVA -Dproc_regionserver" "$HBASE_DAEMON start regionserver"
# 监控HBase thrift2(一般和 RegionServer 共享相同机器) #* * * * * $PMONITOR "$JAVA -Dproc_thrift2" "$HBASE_DAEMON start thrift2 --framed -nonblocking" |
附3:批量操作工具
- 批量操作工具下载:
https://github.com/eyjian/libmooon/releases
其中,mooon_ssh为批量命令工具,mooon_upload为批量上传文件工具。
- 批量操作工具使用示例:
# 设置环境变量 export H='192.168.1.21,192.168.1.22,192.168.1.23,192.168.1.24,192.168.1.25,192.168.1.26' export U=root export P=password export PORT=201810
# 上传/etc/hosts和/etc/profile到:192.168.31.12,192.168.31.13,192.168.31.14,192.168.31.15 mooon_upload -s=/etc/hosts,/etc/profile -d=/etc
# 检查/etc/profile文件是否一致 mooon_ssh -c='md5sum /etc/hosts' |
附4:JVM基础知识
1)JPS命令
当执行jps命令时,如果看不到运行中的Java进程。假设用户名为test,则检查目录/tmp/hsperfdata_test的Owner和权限是否正确,如果权限不正确,则jps将看不到运行中的Java进程。
2)JVM内存
JVM内存由3部分组成:
| 作用 | 说明 |
新生代(Young) | 存活时间较短,一般存储刚生成的一些对象 | 又分为一个伊甸园(Eden)区,和两个Survivor区,两个Survivor区总有一个是空的。对新生代的垃圾回收叫做Minor GC,特点是次数频繁,但每次回收时间较短。 对象在Survivor每经历一次Minor GC,年龄就增长1岁,默认增长到15岁时就晋升到Old代。 |
老年代(Tenured) | 也叫旧生成(Old),存活时间较长,主要存储在应用程序中生命周期较长的对象 | 对象优先在Eden上分配,但大对象直接在Old上分配。对老年代的垃圾回收叫做MajorGC或Full GC,特点是次数相对少,每次回收时间较长。 |
永久代(Perm) | 存储meta和class的信息,JDK8已删除永久代 | 永久代垃圾回收比较少,效率也比较低。因为在JDK8中已无永久代,所以JVM参数“-XX:PermSize”和 “-XX:MaxPermSize”已作废,代替的参数分别为“-XX:MetaspaceSiz”和“-XX:MaxMetaspaceSize”。 |
3)JVM GC(Garbage Collection,垃圾回收)
当Eden空间不足时,即触发Minor GC。Full GC的触发条件为:Old空间不足;Perm空间不足;统计得到的Minor GC晋升到Old的平均大小大于Old的剩余空间。
回收策略 |
|
|
Serial | 串行收集器 | 串行单线程处理所有垃圾回收工作,适合小数据量的回收,使用“-XX:+UseSerialGC”打开。 |
Parrallel New Collector | 并行收集器 | Serial的多线程版本,并行多线程处理,使用“-XX:+UseParallelOldGC”打开,用“-XX:ParallelGCThreads=<N>”指定垃圾回收线程数。 |
CMS(Concurrent Mark Sweep) | 并发收集器,响应时间优先回收器 | 并发多线程处理,使用“-XX:+UseConcMarkSweepGC”打开,只针对老年代。 |
4)并行和并发
并行 | Parallel | 多条垃圾收集线程并行工作,应用线程处于等待状态 |
并发 | Concurrent | 垃圾收集线程与应用线程一段时间内同时工作,不是并行而是交替执行 |
5)JVM的CMS垃圾回收
CMS(Concurrent Mark Sweep)是一个并发使用标记的GC,以牺牲CPU吞吐量为代价获得最短回收停顿时间的垃圾回收器。
CMS不对堆(Heap)进行整理和压缩,节约了垃圾回收停顿时间,但产生了空间碎片,增加了堆空间的浪费。
CMS虽然是老生代的GC,但仍然需要扫描新生代。
启用方式:JVM参数加上“XX:+UseConcMarkSweepGC”,这个参数表示对于老年代的回收采用CMS,CMS采用“标记—清除”算法。
CMS分成以下几个过程:
- 初始标记(STW initial mark)
需暂停JVM,官方的叫法STW(Stop The Word),这个过程虽然暂停了JVM,但很快完成。这个过程只标记GC ROOT可直接关联的对象,不包括间接关联的对象。
- 并发标记(Concurrent marking)
无停顿,应用程序的线程和并发标记的线程并发执行,本过程标记所有可达对象,通过GC ROOT TRACING可达到的对象是活着的对象。
- 并发预清理(Concurrent precleaning)
无停顿,这个过程也是并发的。
- 重新标记(STW remark)
这个过程也会暂停JVM,重新扫描堆中的对象,标记活着的对象,包含子过程Rescan。
- 并发清理(Concurrent sweeping)
无停顿,应用程序线程和收集器线程并发执行。
- 并发重置(Concurrent reset)
无停顿,重置CMS收集器的数据结构,等待下一次垃圾回收。
6)JVM内存参数
执行命令“java -X”可看到相关参数的说明,不同版本的JDK默认值不一定相同,可执行命令“java -XX:+PrintFlagsFinal -version | grep HeapSize”查看默认值。
参数名 | 参数说明 | 示例 |
-Xms | 初始Java堆大小,JVM启动时分配的内存 | -Xms256m |
-Xmx | 最大Java堆大小,运行时可分配的最大内存 | -Xmx2048m |
-Xss | Java线程堆栈大小,每个线程分配的内存大小 | -Xss128m |
| ||
-XX:OnOutOfMemoryError | 内存溢出时的动作 | -XX:OnOutOfMemoryError='kill -9 %p' |
-XX:+UseConcMarkSweepGC | 设置并发垃圾收集器 | -XX:+UseConcMarkSweepGC |
-XX:+UseParallelGC | 设置并行垃圾收集器,同时运行在多CPU上,独占式收集器(收集过程中进程暂停STW),不能与CMS收集器一起。使用这个参数,新生代为并行回收,老年代为串行回收。 | -XX:+UseParallelGC |
-XX:+UseSerialGC | 设置串行垃圾收集器,也是独占式收集器。使用这个参数,新生代和老年代都为串行回收。 | -XX:+UseSerialGC |
-XX:+UseParNewGC | 设置并发串行收集器,实际是串行垃圾回收器的多线程化,即串行垃圾回收器的多线程版本,也是独占式收集器。使用这个参数时,新生代为并行回收,老年代仍是串行回收。 | -XX:+UseParNewGC |
-XX:+UseParallelOldGC | 新生代和老年代都使用并行收集器 | -XX:+UseParallelOldGC |
-XX:+UseConcMarkSweepGC | 老年代回收器,停顿(STW)减少,但吞吐量会降低。 | -XX:+UseConcMarkSweepGC |
-XX:ParallelGCThreads | 设置并行收集线程数 | -XX:ParallelGCThreads=10 |