第一步搭建三节点的hdfs,没有故障转移功能
1.下载相关jar包:hadoop-3.3.0.tar.gz,apache-zookeeper-3.7.0-bin.tar.gz,spark-3.2.0-bin-hadoop3.2.tgz(后续使用)
2.虚拟机安装java环境,如果是yum安装openjdk,那么只有jre环境,没有jdk,此时还需要下载java-1.X.X-openjdk-devel这个包,通过yum list |grep jdk-devel来查询。
3.centos上新建一个用户,用来启动hadoop等组件:useradd atguigu(后续操作都使用这个用户,要将hadoop相关组件的目录都chown为此用户,还有要注意目录的读写权限,我就是忽略了这一点导致ssh免秘钥登录失败)。几台虚拟机建立ssh免秘钥登录,在新建用户的家目录下创建rsa秘钥,使用ssh-copy-id,将公钥分发到其它机器(也包括自己)(进入到家目录的.ssh目录下,使用ssh-keygen -t rsa生成公私钥id_rsa,id_rsa.pub(如果没有的话),执行ssh-copy-id 目标主机 的命令将公钥分发过去),测试使用ssh登录几台虚拟机。
4.开始安装hdfs,解压hadoop的tar包,进入etc/hadoop,编辑core-site.xml
<configuration>
<!-- 指定hdfs的nameservice为cluster1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://cluster1/</value>
</property>
<!-- 指定hadoop临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/ha/hadoop-3.3.0/data</value>
</property>
<!-- core-default.xml默认为dr.who,要修改为启动hdfs集群的用户!! 否则在浏览器上上传文件和创建文件夹时失败-->
<property>
<name>hadoop.http.staticuser.user</name>
<value>atguigu</value>
</property>
</configuration>
修改hdfs-site.xml
<!-- 配置namenode和datanode的工作目录-数据存储目录 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/data</value>
</property>
<!-- 指定JournalNode在本地磁H的位置 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>${hadoop.tmp.dir}/jn</value>
</property>
<!--指定hdfs的nameservice为cluster1,需要和core-site.xml中的保持一致 dfs.ha.namenodes.[nameservice id]为在nameservice中的每一个NameNode设置唯一标示符。 配置一个逗号分隔的NameNode ID列表。这将是被DataNode识别为所有的NameNode。 例如,如果使用"cluster1"作为nameservice ID,并且使用"nn1"和"nn2"作为NameNodes标示符
-->
<property>
<name>dfs.nameservices</name>
<value>cluster1</value>
</property>
<!-- cluster下面有3个NameNode,分别是nn1,nn2,nn3-->
<property>
<name>dfs.ha.namenodes.cluster1</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.cluster1.nn1</name>
<value>hadoop10:8020</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.cluster1.nn2</name>
<value>hadoop11:8020</value>
</property>
<!-- nn3的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.cluster1.nn3</name>
<value>hadoop12:8020</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.cluster1.nn1</name>
<value>hadoop10:9870</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.cluster1.nn2</name>
<value>hadoop11:9870</value>
</property>
<!-- nn3的http通信地址 -->
<property>
<name>dfs.namenode.http-address.cluster1.nn3</name>
<value>hadoop12:9870</value>
</property>
<!-- 指定NameNode的edits元数据的共享存储位置。也就是JournalNode列表 该url的配置格式:qjournal://host1:port1;host2:port2;host3:port3/journalId journalId推荐使用nameservice,默认端口号是:8485 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop10:8485;hadoop11:8485;hadoop12:8485/cluster1</value>
</property>
<!-- 配置失败自动切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.cluster1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制方法,多个机制用换行分割,即每个机制暂用一行 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
</value>
</property>
<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/atguigu/.ssh/id_rsa</value>
</property>
编辑workers文件,里面写上三台服务器的hostname(我第一次部署时没有编辑这里,发现在停止集群时(stop-dfs.sh)其他节点的datanode进程还在,要单独手动杀死,后来编辑了这里,再停止集群时,其它节点的datanode都停止了); 编辑hadoop-env.sh,末尾添加:export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-1.el7_9.x86_64 (这一步我没有编辑,hdfs也正常启动了)
5.将hadoop的目录使用scp -r分发到其它几台服务器
6.启动journalnode:hdfs --daemon start journalnode (在三台服务器执行)
7.在任意一台服务器上(比如hadoop10)格式化namenode,然后启动namenode:hdfs namenode -format ; hdfs --daemon start namenode
8.在另外两台服务器执行同步namenode元数据:hdfs namenode -bootstrapStandby
9.然后另外两台执行启动namenode: hdfs --daemon start namenode (此时三台服务器都是standby(可在浏览器访问9870端口))
10.在三台机器启动datanode:hdfs --daemon start datanode
11.手动将其中某个节点置为avtive状态:hdfs haadmin -transitionToActive nn1(nn1是前面配置的NameNode的其中一台的名称,指定谁谁就是active状态,如果都不指定,hdfs集群无法使用)
12.测试:创建目录:hadoop fs -mkdir /huyao ;上传文件:hadoop fs -put ./1.txt /huyao
--------------------------------------------------------------------加入自动故障转移--------------------------------------------------------------------
1.先停止集群:stop-dfs.sh(通过jps确保所有相关进程都死掉了,没杀死的手动停止)
2.进入etc/hadoop目录,编辑core-site.xml,加入zookeeper的配置
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop10:2181,hadoop11:2181,hadoop12:2181</value>
</property>
再编辑hdfs-site.xml,加入
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
最后将两个配置文件分发至其它的节点
3.启动几个节点的zookeeper
4.在其中一台服务器执行命令初始化zkfc:hdfs zkfc -formatZK
5.启动hdfs集群:start-dfs.sh
6.进入zookeeper:./zkCli.sh 查看自动选举为active节点:get -s /hadoop-ha/cluster1/ActiveStandbyElectorLock,可看到当前active的节点,在浏览器查看确认,确实如此
7.尝试kill掉当前active的namenode,发现没有进行故障自动转移,查看几个standBy节点的zkfc的log:logs/hadoop-atguigu-zkfc-xxx.log,第一次报错说:ha.zookeeper.quorum这个配置不存在,原来是我分发core-site.xml时漏掉了,此时分发过去,重启集群,再kill掉当前的active的namenode,查看zkCLi,发现故障自动转移生效了,但是在两个节点间反复横跳,一直没有定下来,看来还是有问题,再次查看standby节点的zkfc日志,报错为:PATH=$PATH:/sbin:/usr/sbin fuser -v -k -n tcp 8090 via ssh: bash: fuser: 未找到命令,原来系统是centos最小安装版,并没有fuser这个东西,在三个节点su到root后执行:yum -y install psmisc, 完成后此时不用重启集群,查看zkCli,发现active节点已经完成转移了。
8.将被杀死的namenode再单独启动:hdfs --daemon start namenode , 但此时只能作为standby节点了。 在standby节点和active节点执行上传文件:hadoop fs -put ./yy.txt /huyao , 会报错:Operation category READ is not supported in state standby,但最终可以上传成功(它自己会重试)。 可通过命令:hdfs haadmin -getServiceState nn1 来查看namenode的状态
9.另一种上传文件方式:hadoop fs -put a.json hdfs://cluster1/
--------------------------------------------------------------------加入yarn的高可用--------------------------------------------------------------------
1.编辑yarn-site.xml
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>cluster-yarn1</value>
</property>
<!-- 指定resourcemanager的逻辑列表 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2,rm3</value>
</property>
<!-- ============ rm1配置 ============ -->
<!-- 指定rm1主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop10</value>
</property>
<!-- 指定rm1web端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>hadoop10:8088</value>
</property>
<!-- 指定rm1内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>hadoop10:8032</value>
</property>
<!-- 指定AM向rm1申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>hadoop10:8030</value>
</property>
<!-- 指定供NM连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>hadoop10:8031</value>
</property>
<!-- ============ rm2配置 ============ -->
<!-- 指定rm2主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop11</value>
</property>
<!-- 指定rm2web端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>hadoop11:8088</value>
</property>
<!-- 指定rm2内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm2</name>
<value>hadoop11:8032</value>
</property>
<!-- 指定AM向rm2申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>hadoop11:8030</value>
</property>
<!-- 指定供NM连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm2</name>
<value>hadoop11:8031</value>
</property>
<!-- ============ rm3配置 ============ -->
<!-- 指定rm3主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm3</name>
<value>hadoop12</value>
</property>
<!-- 指定rm3web端地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm3</name>
<value>hadoop12:8088</value>
</property>
<!-- 指定rm3内部通信地址 -->
<property>
<name>yarn.resourcemanager.address.rm3</name>
<value>hadoop12:8032</value>
</property>
<!-- 指定AM向rm3申请资源的地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm3</name>
<value>hadoop12:8030</value>
</property>
<!-- 指定供NM连接的地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm3</name>
<value>hadoop12:8031</value>
</property>
<!-- 指定zookeeper集群的地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop10:2181,hadoop11:2181,hadoop12:2181</value>
</property>
<!-- 启用自动恢复 -->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<!-- 指定resourcemanager的状态信息存储在zookeeper集群 -->
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
<!-- 环境变量的继承 -->
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME</value>
</property>
分发到其它几个节点。
2.启动yarn集群:start-yarn.sh,启动完毕后查看jps,如果虚拟机内存没给够,是起不来的,也许会把datanode干掉,或者resourceManager起不来,以我部署的情况来看,每个节点至少需要3g的内存,保险起见给4g。
3.查看yarn状态:yarn rmadmin -getServiceState rm1(rm1为yarn-site.xml中配置的resourceManager名字)。在浏览器访问8088端口,yarn会自动重定向到active的机器。
4.手动kill掉active的resourceManager进程,yarn可以自动故障转移,其中另一个节点提升为active,然后在节点单独启动被kill掉的resourcemanager:yarn --daemon start resourcemanager,启动后为standby状态。
--------------------------------------------------------------------运行spark任务--------------------------------------------------------------------
1.解压spark压缩包,进入,编辑conf/spark-env.sh,加入:
export JAVA_HONE=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-1.el7_9.x86_64
YARN_CONF_DIR=/opt/ha/hadoop-3.3.0/etc/hadoop
2.尝试提交一个任务,在shell执行:
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode client \
./examples/jars/spark-examples_2.12-3.2.0.jar 10
3.加入spark的日志服务器,vi spark-defaults.conf:
spark.eventLog.enabled true
spark.eventLog.dir hdfs://cluster1/directory
spark.yarn.historyServer.address=hadoop10:18080
spark.history.ui.port=18080
spark.eventLog.dir这个配置对应的hdfs上的目录,需要提前创建:hadoop fs -mkdir hdfs://cluster1/directory,再编辑spark-env.sh,加入:
export SPARK_HISTORY_OPTS="
-Dspark.history.ui.port=18080
-Dspark.history.fs.logDirectory=hdfs://cluster1/directory
-Dspark.history.retainedApplications=30"
4.启动日志服务器:./sbin/start-history-server.sh
5.再次尝试提交任务,可在yarn的界面上等到任务执行完后,点击任务对应的history,可进入到spark的日志服务器