Hadoop

471 阅读15分钟

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只序列化了必要的内容