Hadoop 组成
Hadoop 用来存储和分析海量数据,其组件为:
HDFS: 负责数据存储。一个NameNode管理多个DataNode,Second NameNode负责辅助NameNode。
Yarn: 负责资源调度。一个ResourceManager(RM)管理多个NodeManager。RM管理整个集群的内存和cpu。每个NodeManager上可以有多个container,用于运行任务。如果一个NodeManager上有2个cpu核心,则这个NM上最多可以同时运行2个container(这种说法严格来讲不准确)。
MapReduce: 负责计算。Map阶段并行处理输入数据,Reduce阶段汇总结果。MapReduce好像用于离线计算,Spark可以用于内存计算。MapReduce的上层有Hive支持,Spark的上层有Spark MLlib、Spark SQL、Spark Streaming等支持。
虚拟机配置
硬件
我的联想电脑的CPU核心数为12。虚拟机运行数量
*
每个虚拟机CPU数
* 每个CPU核心数
不要超过12。
IP
设置VMWare的IP地址
VMWare中,点击编辑
->虚拟网络编辑器
,会看见VMnet1和VMnet8。选中VMnet8,点击更改设置
。再次点击编辑
->虚拟网络编辑器
,会看见VMnet0,VMnet1和VMnet8。选中VMnet8,可以将子网IP第三个八位字节设置为10(如192.168.10.0)。点击NAT设置,将网关IP也同样设置(网关IP的第四个八位字节一般是2)。最后,点击虚拟网络编辑器
中的确定。
本机Windows中设置VMnet8的地址
在本机中,点击以太网
->更改适配器选项
->VMWare Network Adapter VMnet8
->属性
->Internet协议版本 4
。按照下图配置。
虚拟机内部设置IP地址
打开文件。如果识别不出vim命令,则需要下载apt install vim
。
su root
sudo vim /etc/netplan/01-network-manager-all.yaml
键入i
进入编辑模式。
network:
version: 2
renderer: networkd
ethernets:
ens33:
dhcp4: no
addresses:
- 192.168.10.100/24
gateway4: 192.168.10.2
nameservers:
addresses:
- 192.168.10.2
按Esc
,再键入:wq
可以保存修改的内容。
应用更改:
sudo netplan apply
修改主机名称:
vim /etc/hostname
建立IP地址与主机名的映射关系:
sudo vim /etc/hosts
增加下述内容:
192.168.10.100 hadoop100
192.168.10.101 hadoop101
192.168.10.102 hadoop102
192.168.10.103 hadoop103
192.168.10.104 hadoop104
192.168.10.105 hadoop105
192.168.10.106 hadoop106
192.168.10.107 hadoop107
192.168.10.108 hadoop108
使用
ifconfig
检查ens33部分的内容,查看inet是否为192.168.10.100
。然后再
ping www.baidu.com
看看是否能访问外网。hostname
查看主机名称是否为hadoop100
在克隆出的新的虚拟机中,需要修改01-netcfg.yaml
中的ens33
的 addresses
为192.168.10.102
、192.168.10.103
等,以及修改主机名即可。
Hadoop准备
安装Hadoop、JDK
安装JDK
安装JDK需要注意下载操作系统对应的版本,例如64位的Ubantu系统需要对应安装64位的JDK。如果错误地安装JDK版本,操作系统运行java
命令会报错找不到对应文件。通过uname -m
,如果显示x86_64则说明当前Ubantu系统是64位的。
解压文件,在压缩包路径下运行下述命令,-C参数指定解压路劲。
tar -zxvf jdk-22_linux-x64_bin.tar.gz -C /opt/JDK17
配置Java环境变量,创建一个环境文件my_env.sh
:
cd /etc/profile.d
sudo vim my_env.sh
编写Java环境变量
#JAVA_HOME
export JAVA_HOME=/opt/JDK17/jdk-22.0.1
export PATH=$PATH:$JAVA_HOME/bin
刷新
source /etc/profile
java -version
# 查看Ubantu机环境变量
echo $PATH
安装Hadoop
参照安装JDK,解压->打开my_env.sh
,编写环境:
#HADOOP_HOME
export HADOOP_HOME=/opt/Hadoop336/hadoop-3.3.6
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin
source /etc/profile
Hadoop本地模式
新建一个.txt文档如下:
aa bb
cc aa
运行下述命令:
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount myinput/word.txt myoutput
输出文件会被保存在新创建的文件夹myoutput中,myoutput文件夹须由hadoop创建,该文件夹不能预先存在。
节点文件同步和SSH免密登录
scp复制文件到其他节点
使用scp
命令复制文件到其他节点上。
# 从hadoop102拷贝jdk-22.0.1到hadoop103相同目录下
scp -r /opt/JDK17/jdk-22.0.1 zt@hadoop103:/opt/JDK17
# 从hadoop103拉取hadoop102的hadoop-3.3.6
scp -r zt@hadoop102:/opt/Hadoop336/hadoop-3.3.6 ./
# 在hadoop103执行命令将hadoop102的jdk-22.0.1和hadoop-3.3.6拷贝到hadoop104上
scp -r zt@hadoop102:/opt/* zt@hadoop104:/opt
上述代码在hadoop103将“公钥-私钥”对创建好了发送公钥给hadoop104后,才能够被成功执行。
rsync同步文件夹
rsync -av /opt/Hadoop336/hadoop-3.3.6 zt@hadoop104:/opt/Hadoop336/hadoop-3.3.6
循环复制文件到所有节点的相同目录下
使用自定义命令。
#在/root/bin目录下(没有则创建mkdir bin)
vim xsync
在xsync中写入:
if [ $# -lt 1 ]; then
echo "Not Enough Argument!"
exit;
fi
for host in "hadoop102" "hadoop103" "hadoop104"; do
echo "============ $host ============"
for file in "$@"; do
if [ -e "$file" ]; then
pdir=$(cd -P $(dirname "$file"); pwd)
fname=$(basename "$file")
ssh "$host" "mkdir -p \"$pdir\""
rsync -av "$pdir/$fname" "$host:$pdir"
else
echo "$file does not exist!"
fi
done
done
然后执行chmod 777 xsync
。
然后在/root/bin
目录下运行:xsync /bin
即可将/bin
文件夹及其内容同步到hadoop103和hadoop104的/bin
中了。
注意该命令为用户自建命令。如果在root用户下执行该命令时要给该命令加上绝对路径,让root用户能找到该命令。
SSH免密登录
在hadoop103上创建一个“公钥-私钥对”。将公钥发送给hadoop104。当hadoop103发送用私钥加密的数据到hadoop104时,hadoop104会通过hadoop103的公钥将数据解密。hadoop104要给hadoop103发送响应时,也会使用hadoop103的公钥加密数据,hadoop103接收数据后通过私钥解密。
# 在.ssh目录下执行下述命令,之后输入三次回车,会在.ssh目录下生成id_rsa私钥和id_rsa.pub公钥两个文件
ssh-keygen -t rsa
# 通过下述命令可以将本地的公钥和密钥发送到hadoop103上,之后即可通过ssh hadoop103对hadoop 103无密访问。
ssh-copy-id hadoop103
在.ssh/authorized_keys
中可以看到哪些节点可以无密访问本节点。
注意“公钥-私钥”对对于每一个用户都是不同的。比如在zt用户下配置了本节点的公钥-密钥且传送到了hadoop104,但是切换到root用户后,依然不能对hadoop104进行无密访问。
hadoop102也需要自己对自己设置无密访问。
配置Hadoop集群
目标配置情况
hadoop102 | hadoop103 | hadoop104 | |
HDFS | NameNode, DataNode | DataNode | SecondaryNameNode, DataNode |
YARN | NodeManager | ResourceManager, NodeManager | NodeManager |
寻找默认配置文件:
在
~/Hadoop336/hadoop-3.3.6/share/hadoop/common/
中执行unzip hadoop-common-3.3.6.jar
,可以在相同文件夹下得到文件core-default.xml
在
~/Hadoop336/hadoop-3.3.6/share/hadoop/hdfs/
中执行unzip hadoop-hdfs-3.3.6.jar
,可以在相同文件夹下得到文件hdfs-default.xml
在
~/Hadoop336/hadoop-3.3.6/share/hadoop/mapreduce/
中执行unzip hadoop-mapreduce-client-core-3.3.6.jar
,可以在相同文件夹下得到文件mapred-default.xml
在
~/Hadoop336/hadoop-3.3.6/share/hadoop/yarn/
中执行unzip hadoop-yarn-common-3.3.6.jar
,可以在相同文件夹下得到文件yarn-default.xml
可用户自定义的配置文件存在于$HADOOP_HOME/etc/hadoop
中,分别为:core-site.xml
,
hdfs-site.xml
, mapred-site.xml
,
yarn-site.xml
。
-site.xml配置文件,
core配置
vim $HADOOP_HOME/etc/hadoop/core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 指定NameNode的地址 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop102:8020</value>
</property>
<!-- 指定hadoop数据的存储目录。dfs.namenode.name.dir和dfs.datanode.data.dir会被自动设置到${hadoop.tmp.dir}/dfs/name和${hadoop.tmp.dir}/dfs/data中。dfs.namenode.checkpoint.dir和dfs.namenode.checkpoint.edits.dir路径则会被设置在${hadoop.tmp.dir}/dfs/namesecondary中。而 yarn.nodemanager.local-dirs会被自动设置在${hadoop.tmp.dir}/nm-local-dir中 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/Hadoop336/hadoop-3.3.6/data</value>
</property>
<!-- 配置HDFS网页登录使用的静态用户为hdfs_user -->
<property>
<name>hadoop.http.staticuser.user</name>
<value>hdfs_user</value>
</property>
</configuration>
HDFS配置
$HADOOP_HOME/etc/hadoop/hdfs-site.xml
HDFS中的NameNode与DataNode通信的默认监听端口为8020。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 暴露NameNode的Web访问地址 -->
<property>
<name>dfs.namenode.http-address</name>
<value>hadoop102:9870</value>
</property>
<!-- 暴露Secondary NameNode的Web访问地址 -->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop104:9868</value>
</property>
</configuration>
YARN配置
$HADOOP_HOME/etc/hadoop/yarn-site.xml
YARN中的ResourceManager与NodeManager通信的默认监听端口为8032(这可以在YARN的web页面的conf路径下找到)。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 指定MR走Shuffle -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- 指定ResourceManaer的地址 -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop103</value>
</property>
<!-- 环境变量的继承 -->
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
<!-- 指定存储NodeManager聚合后的日志的HDFS路径 -->
<property>
<name>yarn.nodemanager.remote-app-log-dir</name>
<value>/nmLogs</value>
</property>
</configuration>
MapReduce配置文件
$HADOOP_HOME/etc/hadoop/mapred-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 指定MapReduce运行在YARN上 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<!-- 下述两个配置是设置mapreduce程序的执行过程的HDFS上的临时文件目录-->
<property>
<name>mapreduce.jobhistory.intermediate-done-dir</name>
<value>/tmp/hadoop-yarn/staging/history/done_intermediate</value>
</property>
<property>
<name>mapreduce.jobhistory.done-dir</name>
<value>/tmp/hadoop-yarn/staging/history/done</value>
</property>
</configuration>
配置hadoop系统的JAVA_HOME
在$HADOOP_HOME/etc/hadoop/hadoop-env.sh
中追加下述内容,指定hadoop系统使用JAVA
8。这样做的好处是:即使我的系统JAVA_HOME是Java其他版本,也不会影响hadoop进程对Java
8的使用。
export JAVA_HOME=/opt/JDK8/jdk1.8.0_202
分发上述这个文件。
配置历史服务器和日志聚集
在$HADOOP_HOME/etc/hadoop/mapred-site.xml
中加入下述property,然后分发到其他节点。通过在$HADOOP_HOME/bin
下执行命令mapred -daemon start historyserver
运行历史服务器。在http://hadoop102:19888/jobhistory查看历史服务器的Web。
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop102:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop102:19888</value>
</property>
通过历史服务器可以查看YARN任务的配置参数、任务细节、运行时间、程序运行的日志等。
在$HADOOP_HOME/etc/hadoop/mapred-site.xml
中加入下述property。然后分发到其他节点。通过这种方式配置日志聚集,使得可以在历史服务器中看到程序的运行日志。
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log.server.url</name>
<value>http://hadoop102:19888/jobhistory/logs</value>
</property>
<!--设置日志的保留时间为7天 -->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
启动和测试集群
启动集群
配置data和logs文件夹
在集群启动前配置Linux用户hdfs_user:hadoop。今后一切与hadoop相关的操作都需要切换到hadoop用户组。
groupadd hadoop
useradd -g hadoop -m hdfs_user
usermod -s /bin/bash hdfs_user
下述两个文件夹必须提前配置好。
# 在root用户下执行下述所有代码:
ssh hadoop102 mkdir $HADOOP_HOME/data
ssh hadoop102 chown hdfs_user:hadoop $HADOOP_HOME/data
ssh hadoop102 chmod 770 $HADOOP_HOME/data
ssh hadoop103 mkdir $HADOOP_HOME/data
ssh hadoop103 chown hdfs_user:hadoop $HADOOP_HOME/data
ssh hadoop103 chmod 770 $HADOOP_HOME/data
ssh hadoop104 mkdir $HADOOP_HOME/data
ssh hadoop104 chown hdfs_user:hadoop $HADOOP_HOME/data
ssh hadoop104 chmod 770 $HADOOP_HOME/data
ssh hadoop102 mkdir $HADOOP_HOME/logs
ssh hadoop102 chown hdfs_user:hadoop $HADOOP_HOME/logs
ssh hadoop102 chmod 770 $HADOOP_HOME/logs
ssh hadoop103 mkdir $HADOOP_HOME/logs
ssh hadoop103 chown hdfs_user:hadoop $HADOOP_HOME/logs
ssh hadoop103 chmod 770 $HADOOP_HOME/logs
ssh hadoop104 mkdir $HADOOP_HOME/logs
ssh hadoop104 chown hdfs_user:hadoop $HADOOP_HOME/logs
ssh hadoop104 chmod 770 $HADOOP_HOME/logs
另外再对hadoop这个用户组配置container-executor的权限(这一步在Kerberos安全模式的部分也有说明):
ssh hadoop102 chown root:hadoop $HADOOP_HOME/bin/container-executor
ssh hadoop102 chmod 6050 $HADOOP_HOME/bin/container-executor
ssh hadoop103 chown root:hadoop $HADOOP_HOME/bin/container-executor
ssh hadoop103 chmod 6050 $HADOOP_HOME/bin/container-executor
ssh hadoop104 chown root:hadoop $HADOOP_HOME/bin/container-executor
ssh hadoop104 chmod 6050 $HADOOP_HOME/bin/container-executor
集群初始化
在$HADOOP_HOME/etc/hadoop/workers
中将localhost修改为:
hadoop102
hadoop103
hadoop104
在hdfs_user用户下执行命令hdfs namenode -format
初始化。初始化过程会生成data和logs两个文件夹。在前置步骤中已经配置过这两个文件夹,这是更好的做法。
启动HDFS
在hadoop102节点上执行下述命令启动HDFS系统:
$HADOOP_HOME/sbin/start-dfs.sh
停止HDFS系统:
$HADOOP_HOME/sbin/stop-dfs.sh
另外,HDFS不允许用root用户启动。如果要强制使用root用户进行操作,可以在$HADOOP_HOME/etc/hadoop/hadoop-env.sh
中添加下述内容。(非常不建议这样做,因为系统会不安全)
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_NODEMANAGER_USER=root
export YARN_RESOURCEMANAGER_USER=root
启动YARN
在节点hadoop103的$HADOOP_HOME
目录下执行命令sbin/start-yarn.sh
可以启动YARN。Web端yarn位于http://hadoop103:8088。
测试集群
测试HDFS
# 在hadoop根目录下创建新文件夹
hadoop fs -mkdir /myfolder
# 上传本节点文件到myfolder文件夹
hadoop fs -put ~/mytest.txt /myfolder
上传到hadoop的上述文件实际上是被分成了多个数据块被存储到了每一个DataNode中,每个DataNode都有一份该文件的副本。具体路径为:
Hadoop336/data/dfs/data/current/BP-1433059334-192.168.10.102-1725551956628/current/finalized/subdir0/subdir0
每一个DataNode中都有所上传的mytest.txt文件的完整版。如果是一个大文件,它可能被拆分并存储到几个”blk_…“文件中。
测试YARN
# 在$HADOOP_HOME路径下执行下述命令。
# 确保在/myfolder下有一个用于被统计单词数量的.txt文件
# /myfolderOutput为输出文件夹
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /myfolder /myfolderOutput
Hadoop集群启停命令
我将之命名为hadoopstartstop.sh
。在/root/bin
目录下创建好hadoopstartstop.sh
后,写入下述代码。之后执行chmod 777 hadoopstartstop.sh
。之后使用hadoopstartstop.sh start
和hadoopstartstop.sh stop
即可启停。
标准版
#!/bin/bash
if [ $# -lt 1 ]
then
echo "No Args Input..."
exit ;
fi
case $1 in
"start")
echo "====== 启动hadoop集群 ======"
echo "------ 启动hdfs ------"
ssh hadoop102 "/opt/Hadoop336/hadoop-3.3.6/sbin/start-dfs.sh"
echo "------ 启动yarn ------"
ssh hadoop103 "/opt/Hadoop336/hadoop-3.3.6/sbin/start-yarn.sh"
echo "------ 启动history server ------"
ssh hadoop102 "/opt/Hadoop336/hadoop-3.3.6/bin/mapred --daemon start historyserver"
;;
"stop")
echo "====== 关闭hadoop集群 ======"
echo "------ 关闭history server ------"
ssh hadoop102 "/opt/Hadoop336/hadoop-3.3.6/bin/mapred --daemon stop historyserver"
echo "------ 关闭yarn ------"
ssh hadoop103 "/opt/Hadoop336/hadoop-3.3.6/sbin/stop-yarn.sh"
echo "------ 关闭hdfs ------"
ssh hadoop102 "/opt/Hadoop336/hadoop-3.3.6/sbin/stop-dfs.sh"
;;
*)
echo "Input Args Error..."
;;
esac
Kerberos安全版
#!/bin/bash
if [ $# -lt 1 ]
then
echo "No Args Input..."
exit ;
fi
case $1 in
"start")
echo "====== 启动hadoop集群 ======"
echo "------ 启动hdfs ------"
ssh hadoop102 "su - hdfs_user -c '/opt/Hadoop336/hadoop-3.3.6/sbin/start-dfs.sh'"
echo "------ 启动yarn ------"
ssh hadoop103 "su - yarn_user -c '/opt/Hadoop336/hadoop-3.3.6/sbin/start-yarn.sh'"
echo "------ 启动history server ------"
ssh hadoop102 "su - mapred_user -c '/opt/Hadoop336/hadoop-3.3.6/bin/mapred --daemon start historyserver'"
;;
"stop")
echo "====== 关闭hadoop集群 ======"
echo "------ 关闭history server ------"
ssh hadoop102 "su - mapred_user -c '/opt/Hadoop336/hadoop-3.3.6/bin/mapred --daemon stop historyserver'"
echo "------ 关闭yarn ------"
ssh hadoop103 "su - yarn_user -c '/opt/Hadoop336/hadoop-3.3.6/sbin/stop-yarn.sh'"
echo "------ 关闭hdfs ------"
ssh hadoop102 "su - hdfs_user -c '/opt/Hadoop336/hadoop-3.3.6/sbin/stop-dfs.sh'"
;;
*)
echo "Input Args Error..."
;;
esac
自定义查看所有节点Java进程情况
在/root/bin
下创建jpsall
,并写入下述信息。然后执行chmod 777 jpsall
。
#!/bin/bash
for host in hadoop102 hadoop103 hadoop104
do
echo ============ $host ============
ssh $host /opt/JDK8/jdk1.8.0_202/bin/jps
done
HDFS
HDFS分布式存储系统具有一次写入,多次读出的特点:一个文件经过创建、写入、关闭之后就不再改变,除了追加。
HDFS的文件在物理上是分块存储的(Block1, Block 2, …),一般100MB/S的磁盘传输速率设置块大小为128MB,200-300MB/s的磁盘传输速率设置块大小为256MB。
每一个Block只能属于一个文件,每个文件由一个或多个Block组成。Block的大小并不会被预先分配,例如我上传一个1KB的文件,那么这个文件由实际只占用空间1KB的Block存储。再次上传新的文件时,又会有新的Block来存储新上传的文件。
HDFS缺点:
不适合低延时的数据访问。
无法高效地对大量小文件进行存储。因为会占用大量NameNode内存(一般是128G)来存储文件目录。
不能被多个线程并发地写。
NameNode作用:
管理HDFS的名称空间。
配置副本策略。
管理数据块(Block)的映射信息。
处理客户端读写请求。
DataNode作用:
实际存储数据块。
执行数据块的读写操作。
HDFS的Shell操作
HDFS的基本命令hadoop fs <命令>
或hdfs dfs <命令>
。
HDFS上传、下载操作
# 查看某一hadoop命令的帮助文档
hadoop fs -help rm
# 在hadoop的根目录下创建一个名为threekingdoms的空文件夹
hadoop fs -mkdir /threekingdoms
# 将本节点的当前目录下的本地文件剪切上传到HDFS中,本地被上传的文件会被删除
hadoop fs -moveFromLocal ./shukingdom.txt /threekingdoms
# 将本节点的当前目录下的本地文件复制上传到HDFS中,与-put命令效果相同
hadoop fs -copyFromLocal ./shukingdom.txt /threekingdoms
# 追加一个文件到目的文件的末尾
hadoop fs -appendToFile ./jinkingdom.txt /threekingdoms/weikingdom.txt
# 从HDFS拷贝到本地,与-get命令效果相同
hadoop fs -copyToLocal /threekingdoms/shukingdom.txt ./
HDFS常用操作
# 将HDFS中一个文件拷贝到HDFS中的另一个路径中
hadoop fs -cp /myfolder/mytest.txt /threekingdoms
# 将HDFS中一个文件移动到HDFS中的另一个路径中
hadoop fs -mv /myfolder/mytest.txt /threekingdoms
# 递归删除一个目录中所有的内容
hadoop fs -rm -r /threekingdoms
# 将HDFS文件的所有者改为zt:ztgroup,冒号前时owner,冒号后是Group
hadoop fs -chown zt:ztgroup /threekingdoms
# 显示一个文件末尾1KB的数据
hadoop fs -tail /threekingdoms/weikingdom.txt
# 显示HDFS一个文件夹的大小,比如:44 132,44表示在一个datanode上的文件大小,132表示在所有datanode上的文件大小。
hadoop fs -du -s -h /threekingdoms
# 显示HDFS一个文件夹中所有文件和子文件夹的大小
hadoop fs -du -h /threekingdoms
# 设置副本数量为10,10会记录在NameNode元数据中,因为实际只有三个DataNode,因此最多只能有三个副本。不会对物理内存造成影响。
hadoop fs -setrep 10 /threekingdoms
查询某个文件具体的存储情况
hdfs fsck <HDFS上的文件路径> -files -blocks -locations
输出的部分信息如下:
Connecting to namenode via https://hadoop102:9871/fsck?ugi=hdfs_user&files=1&blocks=1&locations=1&path=%2Ftmp%2Foutput4%2Fpart-00023
FSCK started by nn/hadoop102@EXAMPLE.COM (auth:KERBEROS_SSL) from /192.168.0.45 for path /tmp/output4/part-00023 at Sat May 03 15:26:18 CST 2025
/tmp/output4/part-00023 3 bytes, replicated: replication=3, 1 block(s): OK
0. BP-1893721203-192.168.0.45-1736402046661:blk_1073742691_1867 len=3 Live_repl=3 [DatanodeInfoWithStorage[192.168.11.210:9866,DS-5a16df09-7e9c-4ce1-abb8-31248812d7dd,DISK], DatanodeInfoWithStorage[192.168.0.45:9866,DS-5e8c62ba-a995-4d3a-8989-77b168e37af9,DISK], DatanodeInfoWithStorage[192.168.0.5:9866,DS-266d72b4-db30-47ab-8bca-52cf6505d339,DISK]]
上述信息表示文件/tmp/output4/part-00023
总大小为3字节,占用1个block,存在着3个副本,
3个副本分别位于上述列出的DataNode上。该文件在所有的3个节点上的实际物理存储地址可能是/data/hadoop/hdfs/data/current/BP-1893721203-192.168.0.45-1736402046661/current/finalized/subdir*/subdir*/blk_1073742691*
,区别在于subdir路径可能不同。
HDFS的API操作
NameNode和SecondaryNameNode的机制
NameNode元数据是存储在运行内存当中的。NameNode的内存为128GB,一个Block占元数据的150B。
NameNode启动,加载编辑日志edits和镜像文件fsimage到运行内存中。
客户端向NameNode发送增/删/查/改请求。
edits记录操作日志、更新滚动日志。
增/删/查/改操作完成。
Secondary NameNode请求NameNode是否需要CheckPoint,若需要则执行CheckPoint。CheckPoint的触发条件为:1.定时时间到了;2.Edits中的数据满了。
edits滚动,从edits_inprogress_001变为edits_001,新增edits_inprogress_002。
NameNode中的edits和fsimage被拷贝到Secondary NameNode中并生成fsimage.chkpoint然后拷贝到NameNode中,该fsimage.chkpoint被重命名为fsimage
fsimage和edits
在NameNode被初始化后,在Hadoop336/data/dfs/name/current
中会生成下述四个文件:
fsimage_0000000000000000000
fsimage_0000000000000000000.md
seen_txid
VERSION
fimage文件是HDFS元数据中的一个永久性检查点,包含HDFS文件系统的所有目录和文件inode的序列化信息。可以使用下述命令查看每一个fsimage文件。
hdfs oiv -p XML -i fsimage_0000000000000000000 -o /my/path/to/store/myfsimage.xml
edits是存放HDFS所有更新操作的文件,客户端请求的所有操作首先会被记录到edits中。可以使用下述命令查看每一个edits文件。
hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /my/path/to/store/myedits.xml
seen_txid文件保存的是一个数字,即最后一个edits_的数字。我曾今在HDFS上做了随意一个修改,然后删除了记录了该修改的Edits Log文件edits_inprogress_0000000000000000731。此时seen_txid里面记录的值为731。之后我重启HDFS集群发现namenode启动失败,报错显示txid校验失败,然后我手动将seen_txid中的731改为730后,namenode就可以正常启动了,最后我发现我一开始所做的哪个随意HDFS修改不见了。
设置CheckPont默认触发
在hdfs-default.xml
中添加下述配置,设置NameNode的CheckPoint的默认触发时间是1小时,默认edits满操作次数是10000次,检查edits操作次数的时间间隔为1分钟。
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600s</value>
</property>
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>10000</value>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60s</value>
</property>
DataNode工作机制
DataNode在每个Block中存储数据+数据长度+校验和+时间戳。
DataNode启动后向NameNode注册,NameNode向DataNode返回注册成功的信息。以后每隔一定时间DataNode向NameNode上报所有的Block信息。
心跳3秒一次,用于确保每个NameNode和DataNode之间的通信连接正常。若NameNode超过10分钟+30秒没有收到DataNode的心跳,则认为该DataNode不可用。
参数设置:
<property>
<name>dfs.blockreport.intervalMsec</name>
<value>21600000</value>
<description>Determines block reporting interval in milliseconds.</description>
</property>
<property>
<name>dfs.datanode.directoryscan.interval</name>
<value>21600s</value>
<description>Interval in seconds for Datanode to scan its data directories and reconcile the difference between blocks in memory and on the disk.</description>
</property>
数据完整性
数据在上传到HDFS中时会在本地进行数据封装,给数据增加一个校验位(如crc校验位)。HDFS接收到数据时会根据校验位对数据进行检查。校验位如果与数据不匹配,则表明数据在上传过程中出现损坏。
掉线时限
如果DataNode与NameNode超过\(2\times \text{recheck_interval} + 10 \times \text{heart_beat_interval}=10\text{mins}\ 30\text{seconds}\),则NameNode与DataNode断开通讯,认为DataNode不可用。
参数设置:
<property>
<name>dfs.datanode.heartbeat.recheck-interval</name>
<value>300000</value>
<description>millisecond.</description>
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value>
<description>second.</description>
</property>
HDFS的读写数据流程
客户端写数据的逻辑流程
客户端向NameNode请求上传目标文件。NameNode检查权限和目录结构,返回允许上传的响应。该过程需要创建
DistributedFileSystem
对象客户端请求上传第一个Block(0-128MB)。NameNode元数据进行副本存储节点的选择,返回DataNode1, DataNode2, DataNode3这三个存储数据的节点。
客户端HDFS数据流向DataNode1传输文件,DataNode1向DataNode2传输文件,DataNode2向DataNode3传输文件。DataNode3向DataNode2响应传输成功,DataNode2向DataNode1响应传输成功,DataNode1向客户端响应传输成功。为提高并发性,DataNode1开始被写入文件的同时已经向DataNode2节点开始传输文件了。数据流会将目标文件缓存为一个个chunk(512B)+chunksum(4B),当所有chunk512B+chunksum4B足够大了之后它们会被封装成一个Packet(64KB),Packet是传输数据的最小单元。该过程需要创建
FSDataOutputStream
对象
客户端读数据的逻辑流程
- 客户端向NameNode请求下载文件。NameNode检查权限以及文件是否存在,返回目标文件的元数据(包含目标文件的存储目录、所在的Block)。该过程需要创建
DistributedFileSystem
对象
2.客户端HDFS数据流向节点距离最近的DataNode请求数据,若当前最近DataNode节点负载过大,则数据流会向别的DataNode请求数据。读取DataNode文件时采取串型读取方式,即读完目标文件的Block1后再读取Block2。该过程需要创建FSDataInputStream
对象
网络拓扑节点距离计算
设有一台服务器,其结构如下:
\[ 服务器 \begin{cases} 集群d1 \begin{cases} 机架r1: \text{DataNode1}, \text{DataNode2}, \text{DataNode3}\\ 机架r2: \text{DataNode4}, \text{DataNode5}, \text{DataNode6}\\ 机架r3: \text{DataNode7}, \text{DataNode8}, \text{DataNode9} \end{cases}\\ 集群d2 \begin{cases} 机架r4: \text{DataNode10}, \text{DataNode11}, \text{DataNode12}\\ 机架r5: \text{DataNode13}, \text{DataNode14}, \text{DataNode15}\\ 机架r6: \text{DataNode16}, \text{DataNode17}, \text{DataNode18} \end{cases} \end{cases} \]
DataNode7和DataNode12的节点距离为:\(2+2+2=6\)
DataNode1和DataNode2的节点距离为:\(2\)
HDFS的默认副本存储方式:加入副本因子为\(3\),那么HDFS会在当前DataNode下存储一份副本,然后在随机另一个机架的随机DataNode中存储一份副本(出于安全性考虑),最后再在这个随机机架中选择一个随机DataNode存储一份副本(机架传输速度更快)。
MapReduce
MapReude概述
MapReduce不擅长实时计算,不能实现像MySQL那种毫秒级查询。
MapReduce不擅长流式计算,不能像Sparkstreaming和flink那样处理新出现的一条一条的数据。
MapReduce不擅长有向无环图计算(迭代式串联计算),而Spark的RDD适合做这样的计算。
Map阶段对原始数据进行切分,然后分布式计算,保存计算结果到磁盘分区。
Reduce阶段从磁盘分区中拿取数据并汇总,然后输出最终结果。
MapReduce进程:
MrAppMaster:负责整个程序的过程调度和状态协调。
MapTask:负责Map阶段的整个数据处理流程。
ReduceTask:负责Reduce阶段的整个数据处理流程。
Map和Reduce的原理
以WordCount任务为例。
在Map阶段,原始输入文本wordcount.txt
会被分割成3个数据块(input
splits)发送到三个Hadoop节点上。KeyInput为偏移量,其数据类型为LongWritable。ValueInput为每一行文本,其数据类型为Text。KeyOutput为单词,其数据类型为Text。ValueOutput为频次1,其数据类型为IntWritable。三个节点独立并行运行。最终节点1的Map结果为:(“hello”,
1), (“hello”, 1), (“world”, 1);节点2的结果为:(“hello”, 1), (“hadoop”,
1);节点3的结果为:(“hadoop”, 1)。
在Reduce阶段,先对各个节点的Map结果进行shuffle排序,然后对属于同一个Reduce任务的数据进行数据传输(传输过程涉及序列化)。比如节点2的1个(“hello”, 1)记录会被传送到节点1上。三个”hello”属于同一个reduce任务,reduce任务执行计算\(1+1+1\)。
MapReduce编程
MapReduce编程代码中需要涉及:1. Mapper;2. Reducer;3.
Driver三个部分。样例代码存放于practice_files/Mapreduce_WordCount
中。
程序在Hadoop集群上的运行命令为:
hadoop jar Mapreduce_WordCount-1.0-SNAPSHOT-jar-with-dependencies.jar /threekingdoms/shuinput /threekingdoms/shuoutput
其中HDFS路径/threekingdoms/shuinput
下存放的是待统计词频的一个.txt文件。在这个程序中是不需要指定这个.txt文件本身的,而只需指定它的上级文件夹。输出文件夹shuoutput
不能预先存在,这个文件夹只能由程序自己创建,程序执行完毕后里面存放的是“_SUCCESS”和“part-r-00000”两个文件,后者存储了词频统计的结果。
MapReduce序列化
序列化技术用于解决不同节点之间内存数据的传输问题。Hadoop序列化可以减轻待传输数据的校验信息,方便节点之间的通信。
将一个节点内存中的数据序列化为字节码到磁盘,然后传输字节码到另一个节点,字节码反序列化加载到另一个节点的内存中。
可序列化的数据才能在Reduce阶段在不同的节点中进行网络传输。
自定义序列化类FlowBean.java
位于practice_files\mapreduce_files\src\main\java\com\zt\mapreduce\mobiledata
中。
InputFormat
MapTask数量(即并行度)由数据存储在HDFS中的切片数量决定。切片大小默认为Block_Size。切片只针对于单个数据文件,比如wordcount.txt而不是对wordcount.txt和mobiledata.txt视作一个整体切片。
例如我有一个400MB的文件分布式存储在下述三个节点中(设Block大小为128MB,切片大小默认为128MB):
节点1:140MB(\(140\text{MB} < 128\text{MB}\times1.1\))
节点2:200MB
节点3:60MB
则在Map操作中,节点1中的所有140MB数据会被划分为一个切片,因为它小于切片大小的1.1倍(\(128\times1.1=140.8\));节点2中的200MB数据会被划分为两个切片(128MB+72MB);节点3中的60MB数据会被划分为一个切片。
FileInputFormat源码数据流程
程序先找到输入数据存储目录。
遍历输入数据存储目录下的每一个文件。
- 获取文件大小
- 计算切片大小
- 将切片信息写到切片规划文件中
切片规划提交到YARN,由YARN开启MapTask个数。
CombineTextInputFormat
FileInputFormat常见的接口实现类:TextInputFormat, KeyValueInputFormat, NLineInputFormat, CombineTextInputFormat, 自定义InputFormat等。
CombineTextInputFormat是解决大量小文件的方法,将多个小文件从逻辑上规划到一个切片中。
设input文件夹下有4个文件:a.txt(1.7MB), b.txt(5.1MB), c.txt(3.4MB), d.txt(6.8MB)
1.7在0~1个最大分割大小内,故分1块1.7MB
5.1在1~2个最大分割大小内,故分2块2.55MB
3.4在0~1个最大分割大小内,故分1块3.4MB
6.8在1~2个最大分割大小内,故分2块3.4MB
切片过程:从上到下对块累加,如果大于最大分割大小则单独形成一个切片。
最终的切片情况,形成3个切片:1.7MB, 2.55MB, 2.55MB, 3.4MB, 3.4MB, 3.4MB
// 在driver.java文件中的“设置最终输出KV类型”代码之后,“设置输入输出路径”代码之前添加如下内容。
job.setInputFormatClass(CombineTextInputFormat.class)
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304) // 设置最大分割大小为4MB
Shuffle
OutputFormat
ETL(Extract-Transform-Load)
ETL用来描述将数据从源端经过抽取、转换、加载到目的端的过程。
YARN
YARN工作流
YARN相当于是一个分布式操作系统。YARN由ResourceManager、NodeManager、Container、ApplicationMaster等组件构成。
ResourceManager的作用:
接收客户端提交任务的请求。
监控NodeManager。
启动、监控ApplicationMaster。
资源的分配与调度。
NodeManager的作用:
管理单个节点上的资源。
处理来自ResourceManager的命令。
处理来自ApplicationMaster的命令。
ApplicationMaster的作用:
为应用程序申请资源并分配给内部的任务。
任务的监控和容错。
Container的作用:
Container是YARN资源的抽象,它封装了一个节点上的如内存、CPU、磁盘、网络等多个维度的资源。例如一个节点有4个物理CPU核心,每一个核心被映射成一个vCore,每一个Container使用一个vCore,那么这个节点上最多可以拥有的Container的数量是4。
YARN 调度器
FIFO调度器:先来的job先被服务。例如job0中有4个MapTask任务,集群首先最多同时处理3个MapTask任务,然后再处理job0中剩下的那一个MapTask任务,之后job0才能被处理完成,然后才处理之后的job。FIFO效率非常差。
容量调度器:
多队列,每个队列采用FIFO调度策略。
可以为每个队列配置资源最低保证和资源上限。
一个队列中的资源有剩余时,剩余的这部分资源可以共享给别的队列。
每个队列支持多用户。多个用户可以在同一个队列中运行应用程序。调度器可以对同一个用户所使用的资源总量进行限定。
(1). 使用深度优先算法,优先选择实际资源占用率最低的队列分配资源;(2). 按照队列中作业的优先级和提交时间顺序分配资源;(3). 依次按照作业中容器的优先级、数据本地性原则分配资源。
公平调度器(大公司常用):
YARN常用命令
# 查看所有正在运行的application
yarn application -list
# 查看某特定状态的application(状态选项:ALL, NEW, NEW_SAVING, SUBMITTED, ACCEPTED, RUNNING, FINISHED, FAILED, KILLED)
yarn application -lis -appStates FINISHED
# 结束某applicatin,-kill 后的参数是application ID
yarn application -kill <application_ID>
# 查看yarn日志
yarn logs -applicationId <application_ID>
# 查看某个应用所对应的某个Container的信息
yarn logs -applicationId <application_ID> -containerId <container_ID>
# 查看尝试运行的任务及其容器ID
yarn applicationattempt -list <application_ID>
# 查看某个application所对应的所有Container的信息,只有在运行状态中才能查看到Container的信息。
yarn container -list <application_ID>
# 查看某个Container的状态
yarn container -status <container_ID>
# 查看yarn节点状态
yarn node -list -all
# 重新加载修改之后的队列参数
yarn rmadmin -refreshQueues
# 查看队列信息
yarn queue -status <QueueName>
YARN参数配置
配置:我的VMWare的每一个节点都是2GB内存+2个CPU(每个CPU拥有2个核心)。
需求:处理1GB的文件。设置Block大小为128GB,则要分为8个MapTask,至少1个ReduceTask,1个mrAppMaster。
$HADOOP_HOME/etc/hadoop/yarn-site.xml
。如果集群各个节点性能一致,则可以直接分发下述的YARN配置,否则需要对不同的性能的节点单独配置。
(在配置下述参数之前,我已经在VMWare上将所有节点都设置了快照名为YARN1)
<!-- 配置容量调度器 -->
<property>
<description>The class to use as the resource scheduler.</description>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
</property>
<!-- ResourceManager最大能处理调度器请求的线程数量。在我的VMWare集群中同一时间最多提供3×2×2=12个线程,减去4个线程用于其他服务,因此我在这里设置RM最大处理线程数量为8 -->
<property>
<description>Number of threads to handle scheduler interface.</description>
<name>yarn.resourcemanager.scheduler.client.thread-count</name>
<value>8</value>
</property>
<!-- 关闭YARN的自动检测硬件配置功能 -->
<property>
<description>Enable auto-detection of node capabilities such as memory and CPU.</description>
<name>yarn.nodemanager.resource.detect-hardware-capabilities</name>
<value>false</value>
</property>
<!-- 是否虚拟化CPU Core为vCore。当集群中个节点CPU型号不同时可以启动次选项 -->
<property>
<name>yarn.nodemanager.resource.count-logical-processors-as-cores</name>
<value>false</value>
</property>
<!-- 单个CPU Core映射成多少个vCore -->
<property>
<name>yarn.nodemanager.resource.pcores-vcores-multiplier</name>
<value>1.0</value>
</property>
<!-- NodeManager使用当前节点的内存大小为2GB(默认配置是8GB) -->
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>2048</value>
</property>
<!-- NodeManager的CPU核心数量(默认是8个) -->
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>4</value>
</property>
<!-- 一个Container的最小占用内存大小设置为512MB -->
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>512</value>
</property>
<!-- 一个Container的最大占用内存大小设置为2GB。当我设置为1GB时去运行example wordcount任务会出现Container请求了1536MB的大内存而报错-->
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>2048</value>
</property>
<!-- 一个Container的最小CPU核心数量 -->
<property>
<name>yarn.scheduler.maximum-allocation-vcores</name>
<value>1</value>
</property>
<!-- 一个Container的最大CPU核心数量 -->
<property>
<name>yarn.scheduler.maximum-allocation-vcores</name>
<value>2</value>
</property>
<!-- 关闭虚拟内存检测。因为Java8和CentOS7系统对虚拟内存的不适配性,Java8实际没有充分利用CentOS为它预留的内存而去使用有限的Java堆内存,可能会导致虚拟内存经常性爆掉。-->
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
<!-- 物理内存到虚拟内存的映射比例。2×2.1=4.2GB-->
<property>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>2.1</value>
</property>
YARN队列配置(容量调度器)
设有两个队列:default和hive。
需求1:default队列期望使用40%的集群资源,限制其最大能使用60%的集群资源;hive队列期望使用40%的集群资源,限制其最大能使用60%的集群资源。
需求2:配置队列优先级。
在$HADOOP_HOME/etc/hadoop/capacity-scheduler.xml
中修改下述内容:
修改完毕后执行yarn rmadmin -refreshQueues
刷新,不必重启集群。
配置好后,在HADOOP_HOME
中执行hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount -D mapreduce.job.queuename=hive /threekingdoms/shukingdom.txt /output333
即可指定只在hive队列上运行该实例程序。
通过在WordCountDriver.java中添加下述内容也可以实现指定需要提交到的队列。
Configuration conf = new Configuration();
conf.set("mapreduce.job.queuename", "hive");
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>default,hive</value>
<description>
The queues at the this level (root is the root queue).
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.default.capacity</name>
<value>40</value>
<description>Default queue target capacity.</description>
</property>
<!--添加下述内容-->
<property>
<name>yarn.scheduler.capacity.root.hive.capacity</name>
<value>60</value>
<description>Default queue target capacity.</description>
</property>
<!-- 一个用户使用的最大的default队列的资源比例 -->
<property>
<name>yarn.scheduler.capacity.root.default.user-limit-factor</name>
<value>1</value>
<description>
Default queue user limit a percentage from 0.0 to 1.0.
</description>
</property>
<!-- 一个用户使用的最大的hive队列的资源比例 -->
<property>
<name>yarn.scheduler.capacity.root.hive.user-limit-factor</name>
<value>1</value>
<description>
hive queue user limit a percentage from 0.0 to 1.0.
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.default.maximum-capacity</name>
<value>60</value>
<description>
The maximum capacity of the default queue.
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.hive.maximum-capacity</name>
<value>80</value>
<description>
The maximum capacity of the hive queue.
</description>
</property>
<!--队列保持运行状态-->
<property>
<name>yarn.scheduler.capacity.root.default.state</name>
<value>RUNNING</value>
<description>
The state of the default queue. State can be one of RUNNING or STOPPED.
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.hive.state</name>
<value>RUNNING</value>
<description>
The state of the hive queue. State can be one of RUNNING or STOPPED.
</description>
</property>
<!--设置让哪些用户可以在某队列上提交任务,*表示所有用户-->
<property>
<name>yarn.scheduler.capacity.root.default.acl_submit_applications</name>
<value>*</value>
<description>
The ACL of who can submit jobs to the default queue.
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.hive.acl_submit_applications</name>
<value>*</value>
<description>
The ACL of who can submit jobs to the hive queue.
</description>
</property>
<!--设置让哪些用户可以操作某队列,*表示所有用户-->
<property>
<name>yarn.scheduler.capacity.root.default.acl_administer_queue</name>
<value>*</value>
<description>
The ACL of who can administer jobs on the default queue.
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.hive.acl_administer_queue</name>
<value>*</value>
<description>
The ACL of who can administer jobs on the hive queue.
</description>
</property>
<!--设置让哪些用户可以设置队列中任务的优先级,*表示所有用户-->
<property>
<name>yarn.scheduler.capacity.root.default.acl_application_max_priority</name>
<value>*</value>
<description>
The ACL of who can submit applications with configured priority.
For e.g, [user={name} group={name} max_priority={priority} default_priority={priority}]
</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.hive.acl_application_max_priority</name>
<value>*</value>
<description>
The ACL of who can submit applications with configured priority.
For e.g, [user={name} group={name} max_priority={priority} default_priority={priority}]
</description>
</property>
<!--默认YARN任务最大生命周期,-1表示不设时间限制。(还有一个default-application-lifetime,我不太清楚为什么还需要这样一个参数。)-->
<property>
<name>yarn.scheduler.capacity.root.default.maximum-application-lifetime
</name>
<value>-1</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.hive.maximum-application-lifetime
</name>
<value>-1</value>
</property>
YARN任务优先级
$HADOOP_HOME/etc/hadoop/yarn-site.xml
<!-- 设置5个任务优先级 -->
<property>
<name>yarn.cluster.max-application-priority</name>
<value>5</value>
</property>
运行下述命令,模拟提交长任务直至资源紧张。优先级越大的任务优先执行。
cd $HADOOP_HOME
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi 5 50000
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi -D mapreduce.job.priority=1 5 50000
YARN队列配置(公平调度器)
需求:新建root.group.test和root.group.zt两个队列。若提交任务未指定队列,则由test用户提交的任务提交到root.group.test队列上,zt用户提交的任务提交到root.group.zt队列上。
在$HADOOP_HOME/etc/hadoop/yarn-site.xml
文件的末尾追加下述内容。
<property>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
<description>配置使用公平调度器</description>
</property>
<property>
<name>yarn.scheduler.fair.allocation.file</name>
<value>/home/zt/development/Hadoop336/hadoop-3.3.6/etc/hadoop/fair-scheduler.xml</value>
<description>指定公平调度器的配置文件</description>
</property>
<property>
<name>yarn.scheduler.fair.preemption</name>
<value>false</value>
<description>禁止队列之间的资源抢占</description>
</property>
创建fair-scheduler.xml
文件。
<?xml version="1.0"?>
<allocations>
<!--单个队列中Application Master占用这个队列的资源的最大比例,企业一般配置0.1-->
<queueMaxAMShareDefault>0.5</queueMaxAMShareDefault>
<!--单个队列最大资源的默认值-->
<queueMaxResourcesDefault>2048mb,4vcores</queueMaxResourcesDefault>
<!--新增队列test-->
<queue name="test">
<!--队列最小资源-->
<minResources>1024mb,2vcores</minResources>
<!--队列最大资源-->
<maxResources>2048mb,4vcores</maxResources>
<!--队列中最多同时运行的应用数,默认50,根据线程数配置-->
<maxRunningApps>4</maxRunningApps>
<!--队列中Application Master占用资源的最大比例-->
<maxAMShare>0.5</maxAMShare>
<!--该队列的资源权重,默认值为1.0-->
<weight>1.0</weight>
<!--队列内部的资源分配策略-->
<schedulingPolicy>fair</schedulingPolicy>
</queue>
<!--新增队列zt-->
<queue name="zt" type="parent">
<!--队列最小资源-->
<minResources>1024mb,2vcores</minResources>
<!--队列最大资源-->
<maxResources>2048mb,4vcores</maxResources>
<!--队列中最多同时运行的应用数,默认50,根据线程数配置-->
<maxRunningApps>4</maxRunningApps>
<!--队列中Application Master占用资源的最大比例-->
<!--maxAMShare>0.5</maxAMShare-->
<!--该队列的资源权重,默认值为1.0-->
<weight>1.0</weight>
<!--队列内部的资源分配策略-->
<schedulingPolicy>fair</schedulingPolicy>
</queue>
<!--任务队列分配策略,可配置多层的规则,从第一个规则开始匹配,直到匹配成功-->
<queuePlacementPolicy>
<rule name="specified" create="false"/>
<rule name="nestedUserQueue" create="true">
<rule name="primaryGroup" create="false"/>
</rule>
<rule name="reject"/>
</queuePlacementPolicy>
</allocations>
运行下述命令测试新建的队列。其中,下述第二个提交任务的命令会根据Linux系统当前的用户名称提交到对应的用户队列上面去(但是好像由于fair-scheduler.xml
文件的问题,导致我无法实现这条功能)。(此外,由于每个队列的最大内存只分配了2048MB,这个容量大小执行下述命令是不满足的。)
cd $HADOOP_HOME
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi -Dmapreduce.job.queuename=root.test 1 1
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi 1 1
Kerberos安全系统
客户端要访问服务端,需要先向Kerberos KDC (Key Distribution Center)发送请求。(?这个过程如何完成)
Kerberos的认证服务器(AS, Authentication Server)负责校验客户端的身份信息(客户端名称、客户端IP、时间戳),认证成功后向客户端发送可以访问票证授予服务器的ticket(包含有效时间、客户端可以解密和不可以解密的信息)。
客户端收到ticket,然后带上要访问的服务端名称访问票证授予服务器,票证授予服务器返回客户端访问服务端的另外有一个ticket。
病毒入侵情况
由于没有配置安全系统,在云公网上暴露HDFS_IP:9870和YARN_IP:8088曾让我的集群受到病毒入侵。
病毒被存在在路径/var/tmp
下:
这些文件会启动一个异常ssh连接。即使是我重启整个集群,每个节点的CPU内存占用率莫名其妙高居不下,且通过htop
命令发现不了异常进程。
Kerberos安装与配置
Kerberos安装
在Hadoop02上安装Kerberos服务端:
apt-get install krb5-kdc krb5-admin-server
服务端安装完成后会生成文件:``。
在Hadoop102, Hadoop103, Hadoop104上安装Kerberos客户端:
sudo apt-get install -y krb5-user libkrb5-dev libpam-krb5 libpam-ccreds
客户端安装完成后会生成文件:/etc/krb5.conf
。
查看Kerberos版本(纪录此笔记时的Kerberos版本为1.19.2):
klist -V
Kerberos服务端配置
vim /etc/krb5kdc/kdc.conf
原文件内容如下:
[kdcdefaults]
kdc_ports = 750,88
[realms]
EXAMPLE.COM = {
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
acl_file = /etc/krb5kdc/kadm5.acl
key_stash_file = /etc/krb5kdc/stash
kdc_ports = 750,88
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
#master_key_type = aes256-cts
#supported_enctypes = aes256-cts:normal aes128-cts:normal
default_principal_flags = +preauth
}
kdc_ports:KDC服务的监听端口,这里配置的是750和88两个端口。一定要保证防火墙至少允许其中一个端口,比如
ufw allow 88/tcp
和ufw allow 88/udp
,通过ufw status查看是否已经开放了目标端口
。否则其他Kerberos客户端连接不上服务端的KDC。EXAMPLE.COM:realm,大写。
master_key_type:Kerberos主秘钥的加密算法类型。
acl_file:Kerberos通过acl_file来确定Principal具有哪些权限。
admin_keytab:用于认证管理员密码。
supported_enctypes:支持的加密算法类型。
Kerberos客户端配置
vim /etc/krb5.conf
krb5.conf修改后的内容
[logging]
default=FILE:/var/log/krb5libs.log
kdc=FILE:/var/log/krb5kdc.log
admin.server=FILE:/var/log/kadmind.log
[libdefaults]
dns_lookup_realm=false
ticket_lifetime=24h
renew_lifetime=7d
forwardable=true
rdns=false
pkinit_anchors=FILE:/etc/pki/tls/certs/ca-bundle.crt
default_realm=EXAMPLE.COM
#default_ccache_name=KEYRING:persistent:%{uid}
[realms]
EXAMPLE.COM = {
kdc=hadoop102
admin_server=hadoop102
}
[domain_realm]
#.example.com=EXAMPLE.COM
#example.com=EXAMPLE.COM
ticket_lifetime:客户端拿到的Kerberos服务端的票据的有效时间。
renew_lifetime:客户端可以向Kerberos服务端重新请求票据的时间。
****:
分发/etc/krb5.conf
到其他节点,让其他节点(Kerberos客户端)可以访问到hadoop102(Kerberos服务端)。
krb5.conf修改前的内容
krb5.conf krb5kdc/
root@hadoop102:/etc# vim /etc/krb5.conf
root@hadoop102:/etc# cat /etc/krb5.conf
[libdefaults]
default_realm = ATHENA.MIT.EDU
# The following krb5.conf variables are only for MIT Kerberos.
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
# The following encryption type specification will be used by MIT Kerberos
# if uncommented. In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.
#
# The only time when you might need to uncomment these lines and change
# the enctypes is if you have local software that will break on ticket
# caches containing ticket encryption types it doesn't know about (such as
# old versions of Sun Java).
# default_tgs_enctypes = des3-hmac-sha1
# default_tkt_enctypes = des3-hmac-sha1
# permitted_enctypes = des3-hmac-sha1
# The following libdefaults parameters are only for Heimdal Kerberos.
fcc-mit-ticketflags = true
[realms]
ATHENA.MIT.EDU = {
kdc = kerberos.mit.edu
kdc = kerberos-1.mit.edu
kdc = kerberos-2.mit.edu:88
admin_server = kerberos.mit.edu
default_domain = mit.edu
}
ZONE.MIT.EDU = {
kdc = casio.mit.edu
kdc = seiko.mit.edu
admin_server = casio.mit.edu
}
CSAIL.MIT.EDU = {
admin_server = kerberos.csail.mit.edu
default_domain = csail.mit.edu
}
IHTFP.ORG = {
kdc = kerberos.ihtfp.org
admin_server = kerberos.ihtfp.org
}
1TS.ORG = {
kdc = kerberos.1ts.org
admin_server = kerberos.1ts.org
}
ANDREW.CMU.EDU = {
admin_server = kerberos.andrew.cmu.edu
default_domain = andrew.cmu.edu
}
CS.CMU.EDU = {
kdc = kerberos-1.srv.cs.cmu.edu
kdc = kerberos-2.srv.cs.cmu.edu
kdc = kerberos-3.srv.cs.cmu.edu
admin_server = kerberos.cs.cmu.edu
}
DEMENTIA.ORG = {
kdc = kerberos.dementix.org
kdc = kerberos2.dementix.org
admin_server = kerberos.dementix.org
}
stanford.edu = {
kdc = krb5auth1.stanford.edu
kdc = krb5auth2.stanford.edu
kdc = krb5auth3.stanford.edu
master_kdc = krb5auth1.stanford.edu
admin_server = krb5-admin.stanford.edu
default_domain = stanford.edu
}
UTORONTO.CA = {
kdc = kerberos1.utoronto.ca
kdc = kerberos2.utoronto.ca
kdc = kerberos3.utoronto.ca
admin_server = kerberos1.utoronto.ca
default_domain = utoronto.ca
}
[domain_realm]
.mit.edu = ATHENA.MIT.EDU
mit.edu = ATHENA.MIT.EDU
.media.mit.edu = MEDIA-LAB.MIT.EDU
media.mit.edu = MEDIA-LAB.MIT.EDU
.csail.mit.edu = CSAIL.MIT.EDU
csail.mit.edu = CSAIL.MIT.EDU
.whoi.edu = ATHENA.MIT.EDU
whoi.edu = ATHENA.MIT.EDU
.stanford.edu = stanford.edu
.slac.stanford.edu = SLAC.STANFORD.EDU
.toronto.edu = UTORONTO.CA
.utoronto.ca = UTORONTO.CA
服务端配置kadmin.acl文件
vim /etc/krb5kdc/kadm5.acl
添加如下内容:
*/admin@EXAMPLE.COM *
上述第一个*代表任何用户,第二个*代表任何的权限。
初始化Kadmin数据库
kdb5_util create -s -r EXAMPLE.COM
密码设置为:123456
上述命令执行成功后,会在路径/etc/krb5kdc
中生成由/etc/krb5kdc.conf
所指定的stash文件,以及在路径/var/lib/krb5kdc
中生成四个以principal为前缀的文件。
之后务必执行下述命令以启动Kerberos服务端:
systemctl start krb5-kdc
systemctl start krb5-admin-server
Kerberos服务端的启动、关闭、状态
systemctl start krb5-kdc
systemctl start krb5-admin-server
systemctl stop krb5-kdc
systemctl stop krb5-admin-server
systemctl status krb5-kdc
systemctl status krb5-admin-server
Kerberos常用命令
执行kadmin.loacl
(Kerberos服务端登录)登录服务端Kerberos-KDC数据库。
执行?
查看所有命令列表。
- 展示所有的principal:
listprincs
- 添加一个principal:
add_principal mytest/admin@EXAMPLE.COM
- 删除一个principal:
delprinc mytest/admin@EXAMPLE.COM
- 将一个principal加入到一个新的mytest.keytab文件中(
/root/mytest.keytab
不存在则会被创建):[-norandkey]可选参数表示不新生成随机密码
ktadd [-norandkey] -kt /root/mytest.keytab mytest/admin@EXAMPLE.COM
在Shell命令中输入klist -kt /root/mytest.keytab
可以查看到里面已经有的principal。
- 将一个principal从mytest.keytab中移除:
ktremove -kt /root/mytest.keytab mytest/admin@EXAMPLE.COM
Kerberos客户端向服务端认证
通过密码认证拿到服务端ticket
通过下述命令在Kerberos客户端(例如hadoop103)上登录创建的principal:“mytest/admin@EXAMPLE.COM”。(通过命令klist
可以查看登录状态以及客户端所获取的票据详情。)
kinit mytest/admin@EXAMPLE.COM
通过keytab认证拿到服务端ticket
在Hadoop103节点上执行下述命令,可以直接登录Kerberos服务端:
kinit -kt /root/mytest.keytab mytest/admin@EXAMPLE.COM
在拿到服务端ticket之后,通过命令kadmin
就可以登录服务端的kerberos了。为了避免再次输入密码,记得在ktadd命令中加上-norandkey
一些关于Kerberos认证的说明
对Kerberos的任意Principal认证后均可以访问到HDFS集群。在HDFS中的用户名为认证的Principal的全称(或在core-site.xml中配置的映射的名称),用户组是什么不明朗(好像是supergroup,且supergroup可以转变为父目录的组)。
不对Kerberos认证则完全不能访问HDFS系统。
创建Linux用户及用户组hadoop
在每个节点上新增Linux用户组hadoop。创建hdfs_user,创建yarn_user,创建mapred_user创建密码。
groupadd hadoop
useradd -g hadoop -m hdfs_user
useradd -g hadoop -m yarn_user
useradd -g hadoop -m mapred_user
在kerberos中创建principal hdfs_user@EXAMPLE.COM并设置密码123456,然后就可以在任一的节点上使用passwd hdfs_user
并输入current
kerberos password:
123456可以修改密码。来实现修改用户密码了。在一个节点上修改的hdfs_user的用户密码直接适用于其他节点上的用户hdfs_user。遇到了一个很奇怪的bug,上述修改Linux用户的密码的过程可能不会顺利。在按照上述步骤修改密码前,一定要试一试能否真的用密码123456登录hdfs_user@EXAMPLE.COM。如果不能,需要执行kadmin.local -q "change_password hdfs_user"
来重新修改密码为123456.虽然这个步骤看起来很奇怪,但确实能解决问题。
之后登录进各个节点的hdfs_user用户,相互设置ssh免密登录。yarn_user、mapred_user用户同理。先在各个节点的root用户下执行下述命令,之后再创建ssh免密登录。(在hdfs_user@hadoop102下直接使用命令
ssh-copy-id hadoop103
可以直接实现传输公钥到hdfs_user@hadoop103上。)
mkdir -p /home/hdfs_user/.ssh
mkdir -p /home/yarn_user/.ssh
mkdir -p /home/mapred_user/.ssh
chown -R hdfs_user:hadoop /home/hdfs_user/
chown -R yarn_user:hadoop /home/yarn_user/
chown -R mapred_user:hadoop /home/mapred_user/
运行HDFS任务时,切换到hdfs_user用户(或root用户)、认证任一与HDFS相关的Principal;运行YARN任务时,切换到yarn_user用户(或root用户)、认证任一与YARN相关的Principal;运行MapReduce任务时,切换到mapred_user用户(或root用户)、认证任一与MapReduce相关的Principal。
Hadoop本地目录权限
参照官方文档Permissions for both HDFS and local fileSystem paths
在hadoop102上执行:
# 下述两个文件夹由第一次启动HDFS集群时自动生成
chmod 700 $HADOOP_HOME/data/dfs/name
chown -R hdfs_user:hadoop $HADOOP_HOME/data/dfs/name
chmod 700 $HADOOP_HOME/data/dfs/data
chown -R hdfs_user:hadoop $HADOOP_HOME/data/dfs/data
# 下面这个文件夹为$HADOOP_LOG_DIR和$YARN_LOG_DIR的默认路径
chmod 775 $HADOOP_HOME/logs
chown -R hdfs_user:hadoop $HADOOP_HOME/logs
# 下面这个文件夹为yarn.nodemanager.local-dirs,它由第一次启动yarn集群时自动生成
chmod 755 $HADOOP_HOME/data/nm-local-dir
chown -R yarn_user:hadoop $HADOOP_HOME/data/nm-local-dir
# 下面这个文件夹为yarn.nodemanager.log-dirs,默认位置为$YARN_LOG_DIR/userlogs
chmod 755 $HADOOP_HOME/logs/userlogs
chown -R yarn_user:hadoop $HADOOP_HOME/logs/userlogs
# 下面这个文件是啥?
chown -R yarn_user:hadoop /tmp/hadoop-yarn-yarn_user
在hadoop103上执行:
chmod 700 $HADOOP_HOME/data/dfs/data
chown -R hdfs_user:hadoop $HADOOP_HOME/data/dfs/data
chmod 775 $HADOOP_HOME/logs
chown -R hdfs_user:hadoop $HADOOP_HOME/logs
chmod 755 $HADOOP_HOME/data/nm-local-dir
chown -R yarn_user:hadoop $HADOOP_HOME/data/nm-local-dir
chmod 755 $HADOOP_HOME/logs/userlogs
chown -R yarn_user:hadoop $HADOOP_HOME/logs/userlogs
chown -R yarn_user:hadoop /tmp/hadoop-yarn-yarn_user/
在hadoop104上执行:
chmod 700 $HADOOP_HOME/data/dfs/data
chown -R hdfs_user:hadoop $HADOOP_HOME/data/dfs/data
chmod 700 $HADOOP_HOME/data/dfs/namesecondary
chown -R hdfs_user:hadoop $HADOOP_HOME/data/dfs/namesecondary
chmod 775 $HADOOP_HOME/logs
chown -R hdfs_user:hadoop $HADOOP_HOME/logs
chmod 755 $HADOOP_HOME/data/nm-local-dir
chown -R yarn_user:hadoop $HADOOP_HOME/data/nm-local-dir
chmod 755 $HADOOP_HOME/logs/userlogs
chown -R yarn_user:hadoop $HADOOP_HOME/logs/userlogs
chown -R yarn_user:hadoop /tmp/hadoop-yarn-yarn_user/
在视频教程中,我还剩一个journalnode没有配置。
创建Hadoop principal账户
Kerberos服务规划(必须要认证相应的principal才能够操作hadoop组件):
namenode:nn/hadoop102@EXAMPLE.COM
secondarynamenode:snn/hadoop104@EXAMPLE.COM
datanode:dn/hadoop102@EXAMPLE.COM, dn/hadoop103@EXAMPLE.COM, dn/hadoop104@EXAMPLE.COM
resourcemanager:rm/hadoop103@EXAMPLE.COM
nodemanager:nm/hadoop102@EXAMPLE.COM, nm/hadoop103@EXAMPLE.COM, nm/hadoop104@EXAMPLE.COM
jobhistoryserver:jhs/hadoop102@EXAMPLE.COM
https:专门用于保护hadoop web UI 所暴露出来的端口。https/hadoop102@EXAMPLE.COM, https/hadoop103@EXAMPLE.COM, https/hadoop104@EXAMPLE.COM
hive
创建每个hadoop组件的kerberos账户(principal):
下述代码在Kerberos服务端上创建了12个principal(即12个Hadoop用户),并将12个principal的keytab文件分别发送到对应节点上的/etc/security/keytabs
的文件夹中。在后续的hdfs-site.xml配置文件中,NameNode就会使用Principal
nn/hadoop102@EXAMPLE.COM来托管自己,必须认证此账户才能操作NameNode。
ssh hadoop102
mkdir /etc/security/keytabs
kadmin.local -q "add_principal -randkey nn/hadoop102@EXAMPLE.COM"
kadmin.local -q "ktadd -kt /etc/security/keytabs/nnService.keytab nn/hadoop102@EXAMPLE.COM"
kadmin.local -q "add_principal -randkey dn/hadoop102@EXAMPLE.COM"
kadmin.local -q "ktadd -kt /etc/security/keytabs/dnService.keytab dn/hadoop102@EXAMPLE.COM"
kadmin.local -q "add_principal -randkey nm/hadoop102@EXAMPLE.COM"
kadmin.local -q "ktadd -kt /etc/security/keytabs/nmService.keytab nm/hadoop102@EXAMPLE.COM"
kadmin.local -q "add_principal -randkey jhs/hadoop102@EXAMPLE.COM"
kadmin.local -q "ktadd -kt /etc/security/keytabs/jhsService.keytab jhs/hadoop102@EXAMPLE.COM"
kadmin.local -q "add_principal -randkey https/hadoop102@EXAMPLE.COM"
kadmin.local -q "ktadd -kt /etc/security/keytabs/httpsService.keytab https/hadoop102@EXAMPLE.COM"
chmod 400 /etc/security/keytabs/*
chmod 440 /etc/security/keytabs/httpsService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/nnService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/dnService.keytab
chown yarn_user:hadoop /etc/security/keytabs/nmService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/httpsService.keytab
chown mapred_user:hadoop /etc/security/keytabs/jhsService.keytab
ssh hadoop103
mkdir /etc/security/keytabs
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey dn/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/dnService.keytab dn/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey rm/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/rmService.keytab rm/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey nm/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/nmService.keytab nm/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey https/hadoop103@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/httpsService.keytab https/hadoop103@EXAMPLE.COM"
chmod 400 /etc/security/keytabs/*
chmod 440 /etc/security/keytabs/httpsService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/dnService.keytab
chown yarn_user:hadoop /etc/security/keytabs/rmService.keytab
chown yarn_user:hadoop /etc/security/keytabs/nmService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/httpsService.keytab
ssh hadoop104
mkdir /etc/security/keytabs
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey dn/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/dnService.keytab dn/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey nm/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/nmService.keytab nm/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey snn/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/snnService.keytab snn/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "add_principal -randkey https/hadoop104@EXAMPLE.COM"
kadmin -p mytest/admin@EXAMPLE.COM -w123456 -q "ktadd -kt /etc/security/keytabs/httpsService.keytab https/hadoop104@EXAMPLE.COM"
chmod 400 /etc/security/keytabs/*
chmod 440 /etc/security/keytabs/httpsService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/dnService.keytab
chown yarn_user:hadoop /etc/security/keytabs/nmService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/snnService.keytab
chown hdfs_user:hadoop /etc/security/keytabs/httpsService.keytab
修改Hadoop配置文件
修改配置文件以建立Hadoop集群组件与Principal账户之间的对应关系。
修改core-site.xml
vim $HADOOP_HOME/etc/hadoop/core-site.xml
<!-- 启用Kerberos安全认证 -->
<property>
<name>hadoop.security.authentication</name>
<value>kerberos</value>
</property>
<!-- 启用Hadoop集群授权管理 -->
<property>
<name>hadoop.security.authorization</name>
<value>true</value>
</property>
<!-- Linux系统用户映射Kerberos principal的映射规则-->
<property>
<name>hadoop.security.auth_to_local.mechanism</name>
<value>MIT</value>
</property>
<!-- 具体映射规则 -->
<property>
<name>hadoop.security.auth_to_local</name>
<value>
RULE:[2:$1/$2@$0]([dn]n\/.*@EXAMPLE\.COM)s/.*/hdfs_user/
RULE:[2:$1/$2@$0](snn\/.*@EXAMPLE\.COM)s/.*/hdfs_user/
RULE:[2:$1/$2@$0]([rn]m\/.*@EXAMPLE\.COM)s/.*/yarn_user/
RULE:[2:$1/$2@$0](jhs\/.*@EXAMPLE\.COM)s/.*/mapred_user/
</value>
</property>
上述的hdfs_user、yarn_user、mapred_user与Linux用户hdfs_user、yarn_user、mapred_user应该没有关系。
修改hdfs-site.xml
vim $HADOOP_HOME/etc/hadoop/hdfs-site.xml
<!-- 开启DataNode数据块的Kerberos认证 -->
<property>
<name>dfs.block.access.token.enable</name>
<value>true</value>
</property>
<!-- NameNode对应的Kerberos的Principal,这个值也可以设置为nn/_HOST@EXAMPLE.COM -->
<property>
<name>dfs.namenode.kerberos.principal</name>
<value>nn/hadoop102@EXAMPLE.COM</value>
</property>
<!-- NameNode服务对应的keytab文件 -->
<property>
<name>dfs.namenode.keytab.file</name>
<value>/etc/security/keytabs/nnService.keytab</value>
</property>
<!-- DataNode对应的Kerberos的Principal -->
<property>
<name>dfs.datanode.kerberos.principal</name>
<value>dn/_HOST@EXAMPLE.COM</value>
</property>
<!-- DataNode服务对应的keytab文件 -->
<property>
<name>dfs.datanode.keytab.file</name>
<value>/etc/security/keytabs/dnService.keytab</value>
</property>
<!-- Secondary NameNode 对应的 Kerberos 的 Principal,这个值也可以设置为 snn/_HOST@EXAMPLE.COM -->
<property>
<name>dfs.secondary.namenode.kerberos.principal</name>
<value>snn/hadoop104@EXAMPLE.COM</value>
</property>
<!-- Secondary NameNode 服务对应的 keytab 文件 -->
<property>
<name>dfs.secondary.namenode.keytab.file</name>
<value>/etc/security/keytabs/snnService.keytab</value>
</property>
<!-- HDFS支持的HTTPS协议 -->
<property>
<name>dfs.http.policy</name>
<value>HTTPS_ONLY</value>
</property>
<!-- DataNode的数据传输保护策略为仅认证模式-->
<property>
<name>dfs.data.transfer.protection</name>
<value>authentication</value>
</property>
<!-- HDFS WebUI服务认证主体,这个值也可以设置为https/_HOST@EXAMPLE.COM -->
<property>
<name>dfs.web.authentication.kerberos.principal</name>
<value>https/_HOST@EXAMPLE.COM</value>
</property>
<!-- HDFS WebUI服务对应的keytab文件 -->
<property>
<name>dfs.web.authentication.kerberos.keytab</name>
<value>/etc/security/keytabs/httpsService.keytab</value>
</property>
修改yarn-site.xml
vim $HADOOP_HOME/etc/hadoop/yarn-site.xml
<!-- ResourceManager服务principal,这个值也可以设置为rm/_HOST@EXAMPLE.COM -->
<property>
<name>yarn.resourcemanager.principal</name>
<value>rm/hadoop103@EXAMPLE.COM</value>
</property>
<!-- ResourceManager服务的keytab文件路径 -->
<property>
<name>yarn.resourcemanager.keytab</name>
<value>/etc/security/keytabs/rmService.keytab</value>
</property>
<!-- NodeManager服务principal -->
<property>
<name>yarn.nodemanager.principal</name>
<value>nm/_HOST@EXAMPLE.COM</value>
</property>
<!-- NodeManager服务的keytab文件路径 -->
<property>
<name>yarn.nodemanager.keytab</name>
<value>/etc/security/keytabs/nmService.keytab</value>
</property>
修改mapred-site.xml
vim $HADOOP_HOME/etc/hadoop/mapred-site.xml
<!-- 配置JobHistoryServer的Principal和密码 -->
<property>
<name>mapreduce.jobhistory.principal</name>
<value>jhs/hadoop102@EXAMPLE.COM</value>
</property>
<property>
<name>mapreduce.jobhistory.keytab</name>
<value>/etc/security/keytabs/jhsService.keytab</value>
</property>
<property>
<name>mapreduce.jobhistory.http.policy</name>
<value>HTTPS_ONLY</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.spnego-principal</name>
<value>https/_HOST@EXAMPLE.COM</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.spnego-keytab-file</name>
<value>/etc/security/keytabs/httpsService.keytab</value>
</property>
配置Hadoop的HTTPS访问
HTTPS=HTTP+SSL
生成自签名证书
HTTPS的访问需要有安全证书,下述是生成自签名证书和对应私钥的命令。生成有效期为100年的自签名证书保存在/root/hdfs_ca_cert
中,私钥保存在/root/hdfs_ca_key
中。两个文件夹都要分发到其他节点。
设置PEM pass phrase为:123456。
openssl req -new -x509 -keyout /root/hdfs_ca_key -out /root/hdfs_ca_cert -days 36500 -subj '/C=CN/ST=beijing/L=haidian/O=devA/OU=devB/CN=devC'
生成keystore文件和truststore文件
keystore文件存储了SSL握手所涉及的私钥以及证书信息。
输入下述命令,设置密码123456,然后在Enter key password for <hadoop102>时直接输入回车。
ssh hadoop102
keytool -keystore /root/keystore/ -alias hadoop102 -genkey -keyalg RSA -dname "CN=hadoop102,OU=dev,O=dev,L=dev,ST=dev,C=CN"
ssh hadoop103
keytool -keystore /root/keystore/ -alias hadoop103 -genkey -keyalg RSA -dname "CN=hadoop103,OU=dev,O=dev,L=dev,ST=dev,C=CN"
ssh hadoop104
keytool -keystore /root/keystore/ -alias hadoop104 -genkey -keyalg RSA -dname "CN=hadoop104,OU=dev,O=dev,L=dev,ST=dev,C=CN"
truststore文件存储了可信任的根证书,用于验证服务器证书链中的证书是否可信。在每个节点上分别执行下述命令。之后输入两遍密码123456,输入Y表示信任。
keytool -keystore /root/truststore -alias CARoot -import -file /root/hdfs_ca_cert
从keystore中导出cert
在各个节点上执行:
ssh hadoop102
keytool -certreq -alias hadoop102 -keystore /root/keystore -file /root/cert
ssh hadoop103
keytool -certreq -alias hadoop103 -keystore /root/keystore -file /root/cert
ssh hadoop104
keytool -certreq -alias hadoop104 -keystore /root/keystore -file /root/cert
生成自签名证书
使用hdfs_ca_cert和hdfs_ca_key对cert文件进行签名,生成自签名证书。分别在各个节点执行下述命令。密码123456
openssl x509 -req -CA /root/hdfs_ca_cert -CAkey /root/hdfs_ca_key -in /root/cert -out /root/cert_signed -days 36500 -CAcreateserial
将CA证书导入到keystore
将hdfs_ca_cert证书文件导入到keystore中。在每个节点执行下述命令。密码123456,Y确认。
keytool -keystore /root/keystore -alias CARoot -import -file /root/hdfs_ca_cert
将自签名证书导入到keystore
输入密码123456
ssh hadoop102
keytool -keystore /root/keystore -alias hadoop102 -import -file /root/cert_signed
ssh hadoop103
keytool -keystore /root/keystore -alias hadoop103 -import -file /root/cert_signed
ssh hadoop104
keytool -keystore /root/keystore -alias hadoop104 -import -file /root/cert_signed
将keystore和truststore文件导入到/home目录
在每个节点上执行下述命令:
cp keystore truststore /home/
chown -R root:hadoop /home/keystore
chown -R root:hadoop /home/truststore
chmod 770 /home/keystore
chmod 770 /home/truststore
配置ssl-server.xml文件
mv $HADOOP_HOME/etc/hadoop/ssl-server.xml.example $HADOOP_HOME/etc/hadoop/ssl-server.xml
vim $HADOOP_HOME/etc/hadoop/ssl-server.xml
<property>
<name>ssl.server.truststore.location</name>
<value>/home/truststore</value>
<description>Truststore to be used by NN and DN. Must be specified.
</description>
</property>
<property>
<name>ssl.server.truststore.password</name>
<value>123456</value>
<description>Optional. Default value is "".
</description>
</property>
<property>
<name>ssl.server.keystore.location</name>
<value>/home/keystore</value>
<description>Keystore to be used by NN and DN. Must be specified.
</description>
</property>
<property>
<name>ssl.server.keystore.password</name>
<value>123456</value>
<description>Must be specified.
</description>
</property>
<property>
<name>ssl.server.keystore.keypassword</name>
<value>123456</value>
<description>Must be specified.
</description>
</property>
配置完成后分发。
配置ssl-client.xml文件
mv $HADOOP_HOME/etc/hadoop/ssl-client.xml.example $HADOOP_HOME/etc/hadoop/ssl-client.xml
vim $HADOOP_HOME/etc/hadoop/ssl-client.xml
<property>
<name>ssl.client.truststore.location</name>
<value>/home/truststore</value>
<description>Truststore to be used by clients like distcp. Must be
specified.
</description>
</property>
<property>
<name>ssl.client.truststore.password</name>
<value>123456</value>
<description>Optional. Default value is "".
</description>
</property>
<property>
<name>ssl.client.keystore.location</name>
<value>/home/keystore</value>
<description>Keystore to be used by clients like distcp. Must be
specified.
</description>
</property>
<property>
<name>ssl.client.keystore.password</name>
<value>123456</value>
<description>Optional. Default value is "".
</description>
</property>
<property>
<name>ssl.client.keystore.keypassword</name>
<value>123456</value>
<description>Optional. Default value is "".
</description>
</property>
配置完成后分发。
Yarn配置LinuxContainExecutor
安装LinuxContainerExecutor
LinuxContainerExecutor能有助于提升对YARN访问的安全性。
安装libcrypto.so库(此库华为云Ubuntu22.04已经预装)。libcrypto.so库提供了加密算法,隶属于OpenSSL库。
查看Ubuntu系统是否是已经安装了libcrypto.so库:
ldconfig -p | grep libcrypto
出现类似libcrypto.so.3 (libc6,x86-64) => /lib/x86_64-linux-gnu/libcrypto.so.3表明已经安装。
华为云Ubuntu22.04系统中预装了该库,之后需要将该库路径添加到系统共享搜索路径中:
# 找到该库的位置:/snap/core20/1587/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
find / -name libcrypto.so.1.1 2>/dev/nul
echo "/snap/core20/1587/usr/lib/x86_64-linux-gnu/" | sudo tee -a /etc/ld.so.conf
sudo ldconfig
如果不配置成功这一步骤,会导致Yarn集群的DataNode都无法正常启动。
修改container-executor权限
修改每个节点中container-executor的权限:
chown root:hadoop $HADOOP_HOME/bin/container-executor
chmod 40750 $HADOOP_HOME/bin/container-executor
修改下述文件并分发:
vim $HADOOP_HOME/etc/hadoop/container-executor.cfg
yarn.nodemanager.linux-container-executor.group=hadoop
# 禁止使用容器执行器的用户
banned.users=hdfs_user,yarn_user
# 系统用户的ID小于1000,普通用户的ID大于等于1000
min.user.id=1000
# 允许使用容器执行器的系统用户的列表
allowed.system.users=
feature.tc.enabled=false
在每个节点上修改container-executor.cfg权限:
chown root:hadoop $HADOOP_HOME/etc/hadoop/container-executor.cfg
chown root:hadoop $HADOOP_HOME/etc/hadoop
chown root:hadoop $HADOOP_HOME/etc
chown root:hadoop $HADOOP_HOME
chown root:hadoop /opt/Hadoop336
chown root:hadoop /opt
chmod 400 $HADOOP_HOME/etc/hadoop/container-executor.cfg
配置yarn-site.xml并分发:
vim $HADOOP_HOME/etc/hadoop/yarn-site.xml
<!-- 开启YARN的https -->
<property>
<name>yarn.http.policy</name>
<value>HTTPS_ONLY</value>
</property>
<!-- 配置NodeManager使用LinuxContainerExecutor管理Container -->
<property>
<name>yarn.nodemanager.container-executor.class</name>
<value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
</property>
<!-- 配置NodeManager的启动用户所属组 -->
<property>
<name>yarn.nodemanager.linux-container-executor.group</name>
<value>hadoop</value>
</property>
<!-- LinuxContainerExecutor-->
<property>
<name>yarn.nodemanager.linux-container-executor.path</name>
<value>/opt/Hadoop336/hadoop-3.3.6/bin/container-executor</value>
</property>
修改Hadoop集群的启停文件
HDFS启停脚本
vim $HADOOP_HOME/sbin/start-dfs.sh
在文件的头部添加,并分发:
HDFS_DATANODE_USER=hdfs_user
HDFS_DATANODE_SECURE_USER=hdfs_user
HDFS_NAMENODE_USER=hdfs_user
HDFS_SECONDARYNAMENODE_USER=hdfs_user
HDFS_ZKFC_USER=hdfs_user
vim $HADOOP_HOME/sbin/stop-dfs.sh
在文件的头部添加,并分发:
这里的ZKFC好像是要配置ZooKeeper。
HDFS_DATANODE_USER=hdfs_user
HDFS_DATANODE_SECURE_USER=hdfs_user
HDFS_NAMENODE_USER=hdfs_user
HDFS_ZKFC_USER=hdfs_user
YARN启停脚本
vim $HADOOP_HOME/sbin/start-yarn.sh
在文件的头部添加,并分发:
YARN_RESOURCEMANAGER_USER=yarn_user
YARN_NODEMANAGER_USER=yarn_user
vim $HADOOP_HOME/sbin/stop-yarn.sh
在文件的头部添加,并分发:
YARN_RESOURCEMANAGER_USER=yarn_user
YARN_NODEMANAGER_USER=yarn_user
HDFS目录权限
在首次使用kerberos安全系统启动HDFS集群后,我尝试以任何用户进入HDFS文件系统都失败。HDFS的初始文件夹只有一个/tmp,属于root:supergroup。为了在HDFS上创建hdfs_user:hadoop用户所能操作的文件夹。我需要先在Linux上创建一个全新的用户和组以及pricipal用于首次进入HDFS。
这里有一个疑问,新建任意Principal都可以进入HDFS修改根目录权限,这应该会导致安全问题?
groupadd supergroup
useradd -g supergroup -m zt
kadmin.local -q "add_principal zt"
设置好principal zt的密码后,在core-site.xml
中配置zt@EXAMPLE.COM到zt:supergroup的映射。
<property>
<name>hadoop.security.auth_to_local</name>
<value>
RULE:[2:$1/$2@$0]([dn]n\/.*@EXAMPLE\.COM)s/.*/hdfs_user/
RULE:[2:$1/$2@$0](snn\/.*@EXAMPLE\.COM)s/.*/hdfs_user/
RULE:[2:$1/$2@$0]([rn]m\/.*@EXAMPLE\.COM)s/.*/yarn_user/
RULE:[2:$1/$2@$0](jhs\/.*@EXAMPLE\.COM)s/.*/mapred_user/
RULE:[1:$1@$0](zt@EXAMPLE\.COM)s/.*/zt/
</value>
</property>
重启HDFS,使用kinit zt
拿到zt@EXAMPLE.COM的票据后,即可使用hadoop fs -mkdir /usr
在HDFS上创建目录了。拿到zt的票之后执行下述命令:
hadoop fs -chown -R hdfs_user:hadoop /tmp
hadoop fs -chmod -R 777 /tmp
之后才能顺利启动jobhistoryserver,因为jobhistoryserver的启动需要以jhs的principal向/tmp
文件夹里面写入东西。
按照官网规则,还应该配置下述hadoop目录和权限(我单独为/user目录递归增加了用户组写权限,为了顺利启动Spark On Yarn):
hadoop fs -chown hdfs_user:hadoop /id
hadoop fs -chmod u=rwx,g=rx,o=rx /
hadoop fs -mkdir /user
hadoop fs -chown hdfs_user:hadoop /user
hadoop fs -chmod -R u=rwx,g=rwx,o=rx /user
hadoop fs -mkdir /nmLogs
hadoop fs -chown yarn_user:hadoop /nmLogs
hadoop fs -chmod 777 /nmLogs
hadoop fs -mkdir -p /tmp/hadoop-yarn/staging/history/done
hadoop fs -chown mapred_user:hadoop /tmp/hadoop-yarn/staging/history/done
hadoop fs -chmod 750 /tmp/hadoop-yarn/staging/history/done
hadoop fs -mkdir -p /tmp/hadoop-yarn/staging/history/done_intermediate
hadoop fs -chown mapred_user:hadoop /tmp/hadoop-yarn/staging/history/done_intermediate
hadoop fs -chmod 777 /tmp/hadoop-yarn/staging/history/done_intermediate
hadoop fs -chown mapred_user:hadoop /tmp/hadoop-yarn/staging/history
hadoop fs -chown mapred_user:hadoop /tmp/hadoop-yarn/staging
hadoop fs -chown mapred_user:hadoop /tmp/hadoop-yarn
hadoop fs -chmod 770 /tmp/hadoop-yarn/staging/history
hadoop fs -chmod 770 /tmp/hadoop-yarn/staging
hadoop fs -chmod 770 /tmp/hadoop-yarn
成功启动基于Kerberos安全模式的Hadoop集群后,访问地址https://NameNode的公网IP:9871
来访问HDFS的Web
UI。通过地址https://ResourceManager的公网IP:8090
来访问Yarn的Web
UI。
Hive
- 准备Principal和linux用户,并配置权限:
# 在每个节点上都要执行下面这一行创建hive_user的代码,并相互设置免密ssh登录
useradd -g hadoop -m hive_user
chown -R hive_user:hadoop /opt/Hive313/apache-hive-3.1.3-bin
kadmin.local -q "add_principal hive_user"
kadmin.local -q "add_principal -randkey hive/hadoop102@EXAMPLE.COM"
kadmin.local -q "ktadd -kt /etc/security/keytabs/hiveService.keytab hive/hadoop102@EXAMPLE.COM"
chown hive_user:hadoop /etc/security/keytabs/hiveService.keytab
chmod 400 /etc/security/keytabs/hiveService.keytab
- 修改
hive-env.sh
文件
mv /opt/Hive313/apache-hive-3.1.3-bin/conf/hive-env.sh.template /opt/Hive313/apache-hive-3.1.3-bin/conf/hive-env.sh
vim /opt/Hive313/apache-hive-3.1.3-bin/conf/hive-env.sh
追加下述内容:
export JAVA_HOME=/opt/JDK8/jdk1.8.0_202
export HADOOP_HOME=/opt/Hadoop336/hadoop-3.3.6
export HIVE_HOME=/opt/Hive313/apache-hive-3.1.3-bin
export HIVE_CONF_DIR=/opt/Hive313/apache-hive-3.1.3-bin/conf
- 修改
hive-site.xml
文件
vim /opt/Hive313/apache-hive-3.1.3-bin/conf/hive-site.xml
添加下述Kerberos安全相关配置:
<property>
<name>hive.server2.authentication</name>
<value>KERBEROS</value>
</property>
<property>
<name>hive.server2.authentication.kerberos.principal</name>
<value>hive/_HOST@EXAMPLE.COM</value>
</property>
<property>
<name>hive.server2.authentication.kerberos.keytab</name>
<value>/etc/security/keytabs/hiveService.keytab</value>
</property>
<property>
<name>hive.metastore.sasl.enabled</name>
<value>true</value>
</property>
<property>
<name>hive.metastore.kerberos.principal</name>
<value>hive/_HOST@EXAMPLE.COM</value>
</property>
<property>
<name>hive.metastore.kerberos.keytab.file</name>
<value>/etc/security/keytabs/hiveService.keytab</value>
</property>
上述内容配置好后,执行hive
后,系统当前的票据会自动变成hive/hadoop102@EXAMPLE.COM。
- 在
$HADOOP_HOME/etc/hadoop/core-site.xml
中新增hive_user的映射规则,以及允许hive在任何主机上模拟属于hadoop组的用户:
<property>
<name>hadoop.security.auth_to_local</name>
<value>
RULE:[2:$1/$2@$0]([dn]n\/.*@EXAMPLE\.COM)s/.*/hdfs_user/
RULE:[2:$1/$2@$0](snn\/.*@EXAMPLE\.COM)s/.*/hdfs_user/
RULE:[2:$1/$2@$0]([rn]m\/.*@EXAMPLE\.COM)s/.*/yarn_user/
RULE:[2:$1/$2@$0](jhs\/.*@EXAMPLE\.COM)s/.*/mapred_user/
RULE:[2:$1/$2@$0](hive\/.*@EXAMPLE\.COM)s/.*/hive_user/
RULE:[1:$1@$0](zt@EXAMPLE\.COM)s/.*/zt/
</value>
</property>
<!-- 按照视频里的教程,这里还加了一堆hive, hdfs, HTTP的* -->
分发到所有节点。
本地Windows访问HDFS Web
注意:因为遇到了Hadoop本身的Bug,Hadoop-3.1.x及以后版本无法完成下述功能的实现。
安装配置Kerberos的Windows客户端
下载地址。下载MIT Kerberos for Windows 4.1 kfw-4.1-amd64.msi。在安装过程中选择“Typical”,默认的安装地址为:C:Files:Files。安装完毕后需要重启。
在系统环境变量中Path找到最后一行的C:\Program Files\MIT\Kerberos\bin
,把它提前以掩盖Java中可能含有的kinit和klist命令。
配置Kerberos认证
从服务端把
/etc/krb5.conf
复制到Windows中的C:\ProgramData\MIT\Kerberos5\krb5.ini
。然后把其中的kdc和admin_server都改成公网IP。从服务端把
/etc/security/keytabs/nnService.keytab
复制到Windows中的C:\ProgramData\MIT\Kerberos5
目录下。
操作Kerberos客户端
打开Windows命令行,在C:\Program Files\MIT\Kerberos\bin
路径下正常输入Kerberos命令即可。
在火狐浏览器中,在网址框输入about:config
,然后修改以下两项:
network.negotiate-auth.trusted-uris 改为服务器域名,集群用逗号分割
network.auth.use-sspi 改为fales
然后访问:https://NameNode公网IP:9871
。
但是通过上述步骤依然不能实现本地Windows通过Web UI访问HDFS文件系统,并出现报错:Failed to obtain user group information: java.io.IOException: Security enabled but user not authenticated by filter。这个报错好像是hadoop-3.1.x之后版本的Bug,详见https://issues.apache.org/jira/browse/HDFS-16441。
配置Windwos Kerberos客户端
其他问题的解决方案
网络通信问题
hadoop集群各个组件要通过网络的特定端口建立通信连接。
建议在各个节点上允许私网的所有端口的访问,否则会出现各个hadoop组件都正常启动而相互不能感知的情况:
# 下述命令中的私有IP网段通过命令ip addr show查看本机的网段
ufw all from 192.168.1.0/24
另外记得开放hadoop的一些web页面的端口访问,例如HDFS的web页面端口:
ufw allow 9870/tcp
ufw allow 9870/udp
VMWare虚拟机间歇性宕机
跟一个网络相关的程序有关
未关闭集群直接关机节点
此操作会可能会造成再次启动hdfs时datanode的clusterID与NameNode的clusterID不匹配。导致后续无法正常启动datanode。
可以在每一个节点上使用rm -rf /home/zt/development/Hadoop336/data/dfs/data/*
来使datanode可以被正常启动。
Windows系统运行MapReduce代码
对于hadoop3.3.6版本,可以下载https://github.com/ruslanmv/How-to-install-Hadoop-on-Windows/tree/master。然后在新增系统环境变量HADOOP_HOME
为上述文件中的winutils\hadoop-3.3.1
。然后在系统Path中
新增一个%HADOOP_HOME%\bin
。
之后在Windows平台测试MapReduce代码将不会再报找不到HADOOP_HOME之类的错误。