yarn
ssh无密码访问原理
首先生成公钥和私钥
生成公钥和私钥
将公钥copy到需要访问的主机的Authrized_keys中
rsync 远程同步工具
hdfs
1.HDFS,它是一个文件系统,用于存储文件,通过目录树来定位文件; 2.它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。 3.HDFS的设计适合一次写入,多次读出的场景,且不支持文件的修改。 4.适合用来做数据分析,并不适合用来做网盘应用。
DataNode的作用
提供真实文件数据的存储服务
1.DataNode 以数据的形式存储HDFS文件
2.DataNode响应HDFS客户端读写请求
3.DataNode 周期性向NameNode汇报心跳信息
4.DataNode周期性向NameNode汇报数据块信息
HA
高可用相关概念:
Active NameNode 和 Standby NameNode:
两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务。 Active NN负责集群中所有客户端的操作; Standby NN主要用于备用,它主要维持足够的状态,如果必要,可以提供快速 的故障恢复
FailoverController(主备切换器):
FailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。FailoverController 监测 NameNode 的健康状况,在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换
zkfc的作用
FailoverController(也就是ZKFC进程),每一个NameNode所在的机器都有一个ZKFC进程,ZKFC可以给NameNode发送一些指令,比如切换指令。同时ZKFC还负责监控NameNode,一旦它发现NameNode宕机了,它就会报告给Zookeeper,另一台NameNode上的ZKFC可以得到那一台NameNode宕机的信息,因为Zookeeper数据是同步的,因此它可以从ZK中得到这条信息,它得到这条信息之后,会向它控制的NameNode发送一条指令,让它由Standby状态切换为Active状态。具体原理是什么呢,刚开始的时候两个NameNode都正常工作,处于激活状态的NameNode会实时的把edits文件写入到存放edits的一个介质当中(如下图绿色的如数据库图形的东西),Standby状态的NameNode会实时的把介质当中的edits文件同步到它自己所在的机器。因此Active里面的信息与Standby里面的信息是实时同步的。FailoverController实时监控NameNode,不断把NameNode的情况汇报给Zookeeper,一旦Active状态的NameNode发生宕机,FailoverController就跟NameNode联系不上了,联系不上之后,FailoverController就会把Active宕机的信息汇报给Zookeeper,另一个FailoverController便从ZK中得到了这条信息,然后它给监控的NameNode发送切换指令,让它由Standby状态切换为Active状态
zkfc的模块
联邦 federation
完全分布式hdfs.site.xml
单点namenode存在的问题: 单点故障:高可用 主备切换 压力过大,内存受限:联邦机制 元数据分片 多个namenode管理不同的元数据
HA搭建
配置文件core-site.xml
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>sunyjhost:2181,sunyjhost2:2181,sunyjhost4:2181</value>
</property>
hdfs-site.xml
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>sunyjhost:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>sunyjhost2:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>sunyjhost:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>sunyjhost2:50070</value>
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://sunyjhost:8485;sunyjhost2:8485;sunyjhost3:8485/mycluster</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/var/bigdata/hadoop/ha/dfs/jn</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/sunyj/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
启动 1.两个namenode的节点 需要配置ssh免密通信
2.初始化
启动jounalnode
hadoop-daemon.sh start journalnode 在三台机器上同时都要启动
注意因为journalnode启动时会创建用于保存数据的目录 所以当前用户需要有创建目录的权限 否则会报错无法创建目录
两台namenode 随便选一个进行格式化 hdfs namenode -format
注意因为格式化namenode的同时也会在journalnode的节点上创建相关目录 所以一点确保节点节点直接能通信 关闭防火墙
查看防火墙状态: systemctl status firewalld.service 执行关闭命令: systemctl stop firewalld.service 执行开机禁用防火墙自启命令 : systemctl disable firewalld.service
启动namenode hadoop-daemon.sh start namenode
第二台namenode 执行同步 hdfs namenode -bootstrapStandby
格式化zookeeper节点:就是在zookeeper上创建节点 hdfs zkfc -formatZK
提示:
初始化步骤完毕之后可以启动文件系统了 start-dfs.sh
停止集群时 一次行可以停很多进程
hadoop切换用户
将/tmp的目录的所属用户和所属组进行修改
修改权限
**MapReduce
数据以一条记录为单位经过map方法映射成kv,相同的key为一组 这一组数据调用一次reduce方法,在方法内迭代计算这一组数据
计算程序分发到集群的每一台DN上去做统计,也就是把运算往数据去移动,而不是把数据移动到运算,把我的运算逻辑移动到数据那端去,数据在哪里,我就在哪里运算
map :以一条记录为单位做映射, 那么一条记录record是怎么来的 ,有format的概念 如果以换行符切割 就以一行为一个记录,如果用html的标签进行分割,就很多行为一个记录。。。。根据需求订 reduce:以一组为单位做计算 什么叫做一组 分组 依赖于一种数据格式 key:value
split 切片 map并行度由切片数量决定 切片会格式化出记录 以记录为单位调用map方法,map的输出结果映射成kv kv会参与一次分区计算 拿着key算出p 分区号 k v p maptask的输出是一个文件 存在本地的文件系统中:如果每计算一条结果就要写到文件中,都要向磁盘写,速度就非常慢,所以会有buffer in memory 这个缓冲区大小默认是100M可以调整,buffer满了会做一次系统io调用, 在内存中处理速度非常快,可以做排序 每当buffer数据满了 做排序 根据分区号,然后在溢写的小文件中 ,那么这些小文件中的记录是根据分区排好顺序的。多个小文件最后需要合并,那么这些小文件会有个特点,内部有序 外部无序,可以采用归并排序算法。
内存缓冲区溢写磁盘时 会做两次排序 分区有序 ,且分区内key有序,未来相同的key会相邻的排在一起
reduce数量可以控制 多个reduce的时候需要注意 同一个组的数据不能分到不同的reduce中去,组是不能被拆分的 分解的 不然数据计算就不正确了
partition Partitioner类: 该该主要在Shuffle过程中按照Key值将中间结果分成R份,其中每份都有一个Reduce去负责,可以通过job.setPartitionerClass()方法进行设置,默认的使用hashPartitioner类。实现getPartition函数
迭代器模式用于处理数据集
查询出重复的单词
map和reduce是一种阻塞关系:
MapReduce计算框架 1思考:计算向数据移动是如何实现的呢?数据分散在不同的datanode中,我们写的执行计算的类是如何跑到对应的节点上的呢
把计算程序移动到合适的节点:资源管理和任务调度。
Hadoop1中
jobtracker 资源管理 任务调度
tasktracker 任务管理 资源汇报
客户端会根据每次计算的数据拿到切片清单 切片清单就是 每个切片的偏移量 以及 每个split对应的map任务移动到哪个节点(locations)
yarn
集群角色分布
yarn搭建 mapred-site.xml配置文件:
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
/yarn-site.xml:
<configuration>
<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>sunyjcluster</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>sunyjhost3</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>sunyjhost4</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>sunyjhost3:8088</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>sunyjhost4:8088</value>
</property>
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>sunyjhost:2181,sunyjhost2:2181,sunyjhost4:2181</value>
</property>
</configuration>
1.启动 start-yarn.sh 启动时候发现只是启动了nodemanager节点 所以需要自己去手动启动resourcemanager
2.yarn-daemon.sh start resourcemanager
执行官方示例的程序
/opt/install/hadoop-2.7.2/share/hadoop/mapreduce
命令:
hadoop jar hadoop-mapreduce-examples-2.7.2.jar wordcount /data/wc/input/ /data/wc/output
完全分布式搭建
1.角色分配
三个节点 第一个节点namenode 第二个节点secondaryNameNode datanode在三个节点上
2.配置文件修改
core-site.xml
配置namenode启动的节点和端口号
hdfs-site.xml
配置集群的副本数,namenode secondaryNameNode datanode产生数据的存储目录 以及secondaryNameNode的启动节点和端口
slaves文件
配置datanode节点
3.进行分发:将自己的配置文件分别分发给2,3,4节点
4格式化namenode hdfs namenode -format 格式化的目的是生成namenode的相关路径 初始化 fsimage和 version version文件里有集群id等信息,同一个集群的集群id需要相同
5.启动集群 ,这个脚本会跳到不同的节点 启动不同的角色 secondarynamenode datanode 因为配置了ssh免密登录 start-dfs.sh
6.验证是否启动成功
方式1 可以使用jps 查看启动的进程
方式2:启动后有个web页面 可以访问namenode节点:50070
hadoop HA 搭建
两个namenode
一个是active
一个是standby 同时有两个zkfc进程 zkfc需要和namenode进程在同一个节点 因为zkfc的作用如下:
作用1:监控同主机的namenode的健康状态
作用2:同时作为zookeeper客户端和zookeeper交互 向zookeeper创建节点,创建成功的那个就是active,类似抢锁,比如某一个namenode节点挂点之后,最先监听到namenode挂掉的是zkfc,zkfc在得知namenode挂掉后会去zookeeper中将锁删除,以便于其他节点有机会做active,因为其他的zkfc在监听这把锁是否存在,如果监听到锁被删除了,会重新抢锁
作用3:抢到锁也不会立即就把自己升为active,还要和另一个namenode通信,确定真的是挂掉了之后,才会将自己升为active,把对方降为standby
搭建HA的时候需要配置免密ssh:ssh免密的两个用处
配置文件: core-site.xml 配置:为这个集群起个逻辑名称,后续的配置需要这个名称 自动故障转移需要zookeeper:这里需要自己搭建zookeeper集群
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>sunyjhost:2181,sunyjhost2:2181,sunyjhost4:2181</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<!-- 指定HDFS副本的数量 -->
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<!-- namenode存储路径 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/var/bigdata/hadoop/ha/dfs/name</value>
</property>
<!-- datanode存储路径 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>/opt/var/bigdata/hadoop/ha/dfs/data</value>
</property>
<!-- 要和core-site.xml中-->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<!--配置这个集群中namenode的名称 -->
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>sunyjhost:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>sunyjhost2:8020</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>sunyjhost:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>sunyjhost2:50070</value>
</property>
<!--journal地址-->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://sunyjhost:8485;sunyjhost2:8485;sunyjhost3:8485/mycluster</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/opt/var/bigdata/hadoop/ha/dfs/jn</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/sunyj/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
</configuration>
分发配置:将修改后的配置分发到各个节点。 scp -r ./hadoop sunyjhost4:/opt/install/hadoop-2.7.2/etc/
初始化启动:
1.初始化启动的时候,先启动journal,启动后会生成对应的jn目录,目前jn目录是空目录
三个节点的journalnode都要分别启动
hadoop-daemon.sh start journalnode
2.两台namenode随便选择一个进行格式化 格式化就会生成集群version和id
hdfs namenode -format
格式化成功之后会生成name目录
里面有初始化的fsimage镜像文件和VERSION文件VERSION文件,VERSION文件里存着集群id
刚才jn目录还是空的,格式化成功之后,会在jn目录下生成如下文件,说明在格式化namenode的时候 journalnode也会发生格式化
3.第一台格式化成功后 启动namenode,因为第二台要和他同步,第二台一定不要格式化了 否则集群id就会发生变化了 hadoop-daemon.sh start namenode
4.第二台namenode进行同步命令,
hdfs namenode -bootstrapStandby
执行后发现在自己节点的目录下产生name目录,这样两个节点初始化就同步好了
5.经过上述步骤后已经可以启动hdfs了 ,但是还是手动的,不能自动控制,所以需要先启动zookeeper集群 在对应的zookeeper节点 执行./bin/zkServer.sh start 启动zookeeper集群
6.格式化zkfc 目的就是为了在zk上创建一个目录 以后抢锁就在这个目录下
hdfs zkfc -formatZK
7.所有的初始话完毕后 可以启动集群了,
start-dfs.sh
这个脚本会全部启动,所以以后再启动集群执行这个脚本就ok了 不需要再执行初始化的步骤了
启动后发现zk上这个锁节点有内容了,代表当前active的namenode是节点sunyjhost
启动集群后journal开始同步edit
停止集群的时候
HDFS权限
添加用户前需要切换到root用户 要不没有权限
添加god用户 并修改密码 每个节点都要做,因为要用这个用户去启动集群
useradd god
passwd god
将hadoop的安装目录和数据日志存储目录修改成god权限拥有
chown -R god /hadoop 将hadoop的目录更换成god拥有
god用户还需要做免密登录,因为需要用god用户启动集群
切换用户启动这个配置文件也要配置成对应用户的ssh免密登录,然后分发配置
上述操作完成之后 可以通过god用户去启动hdfs。
如何修改资源的组
hdfs dfs -chgrp ooxx /user/sunyj 或者
hdfs dfs -chown god:ooxx /user/sunyj --这个直接修改用户和组
我只是把sunyj这个目录的组变成ooxx,父目录user的组没有发生变化
将sunyj这个目录修改为 拥有者和组内人员拥有所有权限
hdfs dfs -chmod 770 /user/sunyj rwxrwx---
修改成功后
这时如果linux系统上有个用户是ooxx组 就可以对这个目录进行所有操作
Hadoop本身的用户和组的关系,都是同步Linux系统中的,但是HDFS和Linux的超级用户组又有一点差别,HDFS中的超级用户组是supergroup,但是Linux中默认是没有supergoup这个组,这个时候只需要在Linux中增加supergroup这个组,然后将要在HDFS中加入到supergroup中的用户加到这个组中,再同步HDFS用户和组即可
以下问题解决方式:
mapreduce原理
为什么hdfs中已经是block,为什么还需要split的概念呢? 默认split等于block,但是可以调整split大小,从而控制map任务个数 ,可以控制并行度,控制粒度
map: 以一条记录为单位,经过map方法映射成kv,
reduce: 相同的key为一组,这一组数据调用一次reduce方法,在方法内迭代的计算这一组数据
迭代器模式:由于文件很大,一次加载到内存很耗费内存的空间,因此可以使用迭代器设计模式进行设计,一次读取一行,加载到内存.
maptask的输出是一个文件,存放在本地的文件系统,但不会得到一个kv就写到文件中,这样会频繁的操作io,所以会有缓冲区,默认是100M,缓冲区块满了,溢写到磁盘,这样会有很多的小文件 最后合成一个文件
归并排序算法
yarn 资源调度框架
客户端在mapreduce中的重要位置:
如何才能实现计算向数据移动? 1.所以客户端会产生切片清单 客户端比如想要统计某个目录下文件的wordcount 首先要和namenode通信获取文件元数据,文件的block信息,block身上有(offset,location),这样split就和块有映射关系,这样split包含偏移量,split对应的map任务移到哪些节点
比如文件A 分为三个block 每个block位于dn1 dn2 dn3,根据映射关系默认切片和块大小相等,就可以将map任务分发到对应的节点 2.运行作业时需要一些配置文件,客户端生成
3.将jar包 split清单,配置文件要上传到hdfs
4.客户端调用jobtracker,通知启动计算程序了,并告知文件在hdfs的位置
ResourceManager负责对集群中的所有资源进行统一的管理和调度。
NodeManager进程负责单个节点上的资源管理,它监控一个节点上的资源使用情况(如cpu,内存,硬盘,网络等)并将其report给ResourceManager
yarn搭建
yarn-site.xml
<configuration>
<!-- Site specific YARN configuration properties -->
<!-- reducer获取数据的方式 -->
<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>sunyjcluster</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>sunyjhost3</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>sunyjhost4</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>sunyjhost3:8088</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>sunyjhost4:8088</value>
</property>
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>sunyjhost:2181,sunyjhost2:2181,sunyjhost4:2181</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<!-- 指定mr运行在yarn上 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
分发配置
datanode和nodemanager应该是同一个节点 在slaves中配置 所以不需要单独配置
启动yarn
start-yarn.sh
我在节点一上启动yarn 但是我的rm是配置在三四节点上的,所以只有nodemanager启动成功了 ,需要单独去三四节点上去启动rm
yarn-daemon.sh start resourcemanager
mapreduce on yarn
mapreduce的相关概念
map:做映射,给我一批数据不太好处理,需要做映射,改变下形式。将数据映射成另一种形式 reduce:将映射后的数据进行规约,合并处理
序列化
hadoop自己开发了一套序列化机制 writable,因为java的序列化 是重量级序列化框架,hadoop的序列化轻量,例如一个person类,创建了一个对象Tom,含有属相name:tom age:18,那么序列化的时候就只有(tom,18),抛弃了不重要的信息,只保留了数据信息,所以在反序列化时,要明确指定出反序列化的类型,不然就无法知道是什么类型。也就是hadoop只序列化了必要的内容