大数据介绍 Hadoop 伪分布式 完全分布式 HDFS MapReduce yarn zookeeper

大数据

数据:字母 数字 声音 影像等都是数据
数据没有任何含义,仅代表一个符号。数据是信息的载体。
信息:数据经过解释加工之后,赋予一定的含义。
信息量:消除人们对不确定因素的大小

大:
1 数据量大
基于非常非常大量的数据,甚至是海量数据才能给我们带来一定的价值。
价值是从这些数据中挖掘出来的。
2.大数据的技术
在海量数据的基础上,必须产生能处理这么大数据量的技术。

大数据:
大数据(big data),是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。
数据就是价值

特点:
1.大量
2.多样性
3.高速
4.价值

Hadoop

可靠的,可扩展的,可以分布式计算的开源软件。
特点:
1.使用简单编程模型在集群中分布式处理海量数据
分布式:从软件的角度思考,使用多个服务器共同计算完成任务
集群:从硬件的角度思考,一个集群中可以有多台服务器
2.节点的数量可以是单个到成千上万,并且每个节点都有自己的计算和存储
3.相对比在硬件层次做优化,hadoop提供了应用层的高性能操作
4.集群中的任何一个节点都允许出错

hadoop到底是什么?
1.从具体内容来说
Hadoop是一个软件、分布式的计算框架
2.从大数据整体上来说
特指hadoop生态圈

hadoop(大数据)能解决什么问题?
1.海量数据怎么存?
2.海量数据怎么算?

hadoop的四大组件

  • HDFS:Hadoop Distributed File System
    三个角色:
    NameNode:
    主节点,存元数据(描述数据的数据),全局只有一个。
    DataNode:
    数据节点,存真实数据,全局可以有多个。
    NameNode节点可同时充当DataNode角色。
    SecondoryNameNode:
    主节点备份节点,备份元数据,全局只有一个。

  • MapReduce:解决海量数据的计算问题

  • Yarn:资源调度器

  • Common:与Hadoop生态圈的其他组件进行交互的jar包

HDFS,MapReduce名字由来
根据谷歌发表了三篇论文
GFS -> HDFS
Map-Reduce -> MapReduce
BigTable -> HBase

版本:
普通版:
安装使用比较简单,提供了基础的功能,一般适用于初学者。
商业版:
添加额外的功能,比较专业。

hadoop安装
1.本地环境:用于开发和简单测试使用
2.伪分布式环境:用一台机器充当了所有的角色
3.完全分布式环境:真正意义上的分布式,每个节点都有不同的角色

伪分布式

前提:jdk ssh

  • 下载Hadoop安装包
    hadoop.apache.org -> Apache release archive -> hadoop2.7.6
  • 解压缩
    tar -xzvf hadoop2.7.6.tar.gz -C …/modules
  • 配置环境变量
HADOOP_HOME=xxxx/hadoop
PATH=${PATH}:${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin
[bduser@node200~]$ source .bashrc
  • 修改配置文件
    关闭防火墙
  • 格式化
    hadoop namenode -format
  • 启动相应服务
start-all.sh (start-dfs.sh;start-yarn.sh)
start-dfs.sh 单独启动hdfs的相应服务
start-yarn.sh  单独启动yarn的相应服务
start-all.sh 同时启动hdfs和yarn的相应服务
  • 验证
    a.jps 查看java进程
    b.webUI 主机名/ip:50070
  • 注意:
    a.配置分布式的前提条件
    1)jdk1.8
    2)ssh免密登录
    3)防火墙关闭
    b.如果访问不到webUI的几种情况处理
    1)windows的防火墙没有关闭
    2)linux的防火墙没有关闭
    3)hosts文件没有做映射关系
    4)浏览器(不要使用IE浏览器或兼容模式)
    c.如果需要重新格式化
    1)关闭服务
    2)删除dfs目录
    3)格式化
    4)开启服务

完全分布式

  • 创建节点
    1)传统使用镜像的方式创建
    2)以完整的原型机为基础,做完整克隆
  • 修改网络配置
    a.sudo vim /etc/udev/rules.d/70-persistent-net.rules
    把eth0网卡行注释掉,然后把eth1改成eth0
    复制当前网卡eth0里的mac地址
    b.sudo vim /etc/sysconfig/network-scripts/ifcfg-eth0
    把mac地址粘贴上,修改ip地址
    c.重启网卡
    sudo service network restart
  • 修改主机名
    sudo vi /etc/sysconifg/network 修改HOSTNAME
    reboot重启机器生效
  • 修改映射关系 /etc/hosts
    ssh由于是原节点的完整克隆,无需重新配置ssh
    *创建两个脚本放在/usr/local/bin/目录下,并赋予可执行权限
    如果想要同步根目录下的内容,必须切换到root用户使用,sudo不好使
    xsync:rsync 本地路径/文件名 whoami@主机名:路径 向集群所有节点同步数据
    rsync 本地路径 远程用户名@远程主机名:远程路径
    xcall:ssh 主机名 命令 让集群中所有节点执行同一命令
  • 修改hadoop的配置文件,使用xsync进行同步
  • 在主节点进行格式化
    hadoop namenode -format
  • 在主节点启动服务
    start-all.sh 每个节点按照配置文件会启动响应的进程
  • 注意:
    1.关闭防火墙
    2.时间同步
    rsync与scp的区别:
    相同点:语法完全相同
    不同点:
    scp是不管远程文件是否与本地文件一致,全部复制。
    rsync只同步本地文件与远程文件不一致的部分。

HDFS

Hadoop Distributed File System
分布式的文件系统

什么是文件系统?
能存东西,硬盘,做存储的,是一个单纯的硬件设备
在硬件设备基础上添加一层软件对数据进行存储和管理
表现形式?
Windows:file:///c://xxx
Linux:file:///xxx
ftp: ftp://xxx
hdfs://node200:9000/xxx

三个角色:
NameNode:hdfs集群的主节点,存储元数据,全局只有一个
DataNode:hdfs集群的从节点,存储真实数据,全局有多个
SecondaryNameNode:hdfs集群主节点的备份节点,全局只有一个

分布式存储:
如果一个文件很大,存在一个节点中有压力,可以把文件划分成多个小部分
每个部分进行分别存储,可以把整个文件的存储压力分摊给每个节点
优势:
1.存储量大
2.可以容错,默认有三个副本
3.适合一次写入,多次读出的情景
劣势:
1.不适合做实时运算
2.速度慢
3.适合添加,不适合修改

关于hdfs的两个脚本
hdfs / hadoop
1.没有参数,或者写–help/-help/-h 跳出提示信息
2.每个命令都对应一个java类,本质命令就是java代码
3.hdfs dfs 完全等价于 hadoop fs

hdfs的存储方式:
按照128M的大小为block块的大小进行文件的划分
每128M划分一个block块,最后不足128M的部分按一块算,但是大小是实际的大小
每个块以一个独立个体的形式进行存储,但是整体会通过块池id统一
为什么是128M?
最优化寻址时间。
应用题
已知条件:
1.硬盘的读写速度为100M/s
2.寻址时间是读写时间的1%
3.性价比最高的寻址时间为10ms
问题:
10ms的时间能读写多少数据
答:
10ms / 0.01 = 1000ms = 1s
1s * 100M/s = 100M
100M是整数嘛
在计算机二进制中,与100最接近的数字是128。
查看DataNode里存放的数据
很多个层次,依次进入就ok,其中两个subdir0与hdfs中文件的位置没有关系
DataNode中存储的是真实的数据,文件或目录中间的关联DataNode不关心。

hdfs的操作:
1.shell操作
看文档
2.API操作

  • 引包:
    a.传统方式
    i.hadoop.tar.gz解压缩 -> share -> 在搜索框搜索.jar -> 复制到_lib -> 搜索框中搜索-source -> 剪切到_source ->继续搜索-test -> 剪切到_test ->_lib中还剩144个jar包
    ii.file -> projectStructure -> libraries -> + java -> 选择_lib的所有jar包 -> 确定
    b.maven
    在pom文件中修改依赖
  • 代码:
    Configuration conf = new Configuration(); 创建配置项,作为文件系统连接的参数
    FileSystem fs = FileSystem.get(conf); 通过配置项与hdfs连接
    System.out.println(fs); 输出连接信息 fs.close(); 关闭连接,释放资源

关于hdfs里的相关配置信息
1.core-default.xml 没有特殊说明 默认使用
2.core-site.xml 覆盖default相应选项
3.conf.set(key,value) 设置具体的配置项 当次有效
生效的顺序:倒序

关于权限问题
1.FileSystem.get(new URI(""),conf,“bduser”)
2.run->editConfiguration->VMoptions->-DHADOOP_USER_NAME=bduser
3.hdfs dfs -chmod -R 777 /xxx
4.hdfs dfs -chown -R windows /xxx
5.把Windows用户改成bduser

HDFS写数据的原理
1.由客户端向NN发送链接请求
2.由NN响应客户端,通知可以传递数据
3.block块依次向NN发送请求,请求可以存入数据的DN列表
4.NN向客户端发送可以存储数据的DN列表
5.客户端与DN列表里的所有节点建立连接
6.所有节点反馈连接结果
7.如果连接没有问题,由客户端向DN列表里的节点使用RPC发送数据
8.发送完成,客户端向NN发送最后一次请求,通知数据传递完毕
9.NN接收请求后保存元数据

NameNode依据什么返回三个DN?
机架感知
hadoop1.x
首先按照距离最近找一个节点进行存储,在不同机架下找第二个节点,在第二个节点的同机架下找第三个节点。
hadoop2.x
首先按照距离最近找一个节点进行存储,在同机架下找第二个节点存储,在其他机架上找第三个节点。

自定义机架感知

  • net.topology.script.file.name
    设置一个路径
    这个路径是一个脚本文件,可以执行得到集群中的节点的机架分配情况

  • net.topology.node.switch.mapping.impl
    设置一个实现类
    这个类是分配集群中节点机架情况的逻辑代码
    implemens
    DNSToSwitchMapping
    重写 resolves 方法
    参数:所有节点的ip或主机名
    返回值:经过解析之后的机架

  • 怎么设置逻辑上的同机架
    hadoop在启动hdfs服务的时候,在做机架分配。
    验证:hdfs dfsadmin -printTopology
    1.net.topology.node.switch.mapping.impl
    如果此配置项没有被覆盖,走默认类ScriptBasedMapping执行
    a.没有在core-site.xml中重写相同配置项
    b.没有在代码中用conf.set(“此配置项”,"")
    如果net.topology.script.file.name没有设置,
    所有节点都在 /default-rack 机架下
    如果net.topology.script.file.name有指定具体文件,
    按照指定脚本进行分配机架
    2.net.topology.node.switch.mapping.impl 被覆盖
    与1中所有内容无关,直接执行此配置项指定的类分配机架。
    implements DNSToSwitchMapping
    重写 resolves 方法
    参数:集群中所有节点的列表
    返回值:解析之后的机架的列表

  • 程序部署:
    1.打成jar包,并放入/hadoop/share/hadoop/common/lib
    2.修改core-site.xml 指定自定义机架的类
    3.同步jar包和配置文件
    4.重启服务
    5.查看拓扑 hdfs dfsadmin -printTopology

hdfs读数据的原理
1.客户端向NN发送数据请求
2.NN向客户端响应请求文件的元数据
3.客户端通过NN提供的元数据,就近找DN(存三份,读一份)
4.DN返回数据
5.在内存中缓存,所有块合并成一个文件

NameNode原理
满足速度快和数据安全两个前提下,在磁盘和内存中各存储一份当前状态文件
hdfs如果是第一次使用,会在name目录下创建edits和fsimage文件。
hdfs在之后的启动过程,会把磁盘中的数据加载到内存中,还原关机前的状态

  • 两种文件
    editsxxx --> 临时的操作过程数据
    fsimage --> 某一时刻的最终完整状态
  • 两种文件怎么配合使用
    把上一次的最终状态文件(fsimage_xxx)与这个时间点以后,当前时间点以前的所有操作记录(edits_xxx)合并,生成当前的最终状态(fsimage_xxx)文件
  • 触发合并的两个条件:
    1.记录数达到一百万条
    2.时间达到一小时
  • 合并的工作由谁来做:SecondoryNameNode
  • 合并过程
    1.2NN一分钟询问一次NN是否需要做合并操作
    2.NN如果记录数达到100万条或时间达到1小时会反馈2NN可以执行合并操作
    3.NN中edits_inprocess文件会向前滚动一次,保证当前的完整状态
    4.2NN把NN最后一个fsimage和新添加的edits文件复制到2NN
    5.把这些文件在内存中合并成fsimage.chkpoint
    6.2NN把fsimage.chkpoint文件复制回NN
    7.在NN中把fsimage.chkpoint重命名成fsimagexxx

所有的条件对应的配置项位置
默认设置位置在hdfs-default.xml,可以在hdfs-site.xml修改。
a.//触发合并的条件之一 — 间隔时间达到一个小时
dfs.namenode.checkpoint.period 3600
b.//触发合并的条件之二 — 记录数量超过了100万条
dfs.namenode.checkpoint.txns 1000000
c.//每隔60秒(1分钟)询问一次是否需要合并
dfs.namenode.checkpoint.check.period 60
使用命令人为合并或滚动文件
a.只做edits文件的滚动
hdfs dfsadmin -rollEdits
b.做fsimage与edits的合并
hdfs dfsadmin -safemode enter
hdfs dfsadmin -saveNamespace
注意:
a.合并的时候,会自动做edits的滚动。
b.合并的时候,一定先进入安全模式。
c.命令操作只对NN生效,2NN不发生任何改变。
安全模式
合并数据的时候,保证数据的完整性。
hdfs dfsadmin -safemode
数据的恢复
删除NN上的 dfs/name 数据(模拟NameNode节点出现问题)
把2NN上的 dfs/secondaryName 目录下的所有复制到 NN里的 name目录下
注意:
a.复制完毕之后要重启服务
b.这种方式肯定会丢失一定的数据,不可避免。

查看edits和fsimage文件
edits:
hdfs oev [-p xml(默认转出的格式)] -i input -o output
fsimage:
hdfs oiv [-p XML(默认的转出格式为web)] -i input -o output
注意:
a.在edits里不是一个操作为一条记录,一个操作可以分成多条记录。
b.fsimage分两部分,一部分描述目录和文件,另一部分描述目录和文件层次关系。

DataNode原理
除直接破坏数据本身的行为之外,也有一些因素可以引起数据无法使用(网络)
1.在启动hdfs服务的时候,DN向NN注册,告诉NN当前节点的存储情况
2.NN告知DN,注册成功
3.DN每隔一小时向NN上报一次自己当前的存储情况
4.NN每隔3秒(心跳机制)向DN发送链接测试请求,保持节点之间的联通
5.如果发送心跳后10分钟还没有收到回应,可以判断当前DN不可用
i.当前节点真的宕机了。
ii.当前节点可以使用,但是网络传输可能出现问题,不适合继续工作。

为什么超时时间定为10分钟

dfs.namenode.heartbeat.recheck-interval
300000
dfs.heartbeat.interval
3
2 * dfs.namenode.heartbeat.recheck-interval+10 *dfs.heartbeat.interval

添加一个节点(DataNode)步骤
a.关闭现有集群服务
b.把新节点的ip调整到与原集群同一网段
c.修改配置文件并对所有节点(包括新添加的节点)进行同步
d.重启服务

服役新节点
在dfs服务不重启的前提下,动态添加一个新的DN。
步骤:
1.准备工作:
a.创建(克隆)一个新的节点,修改ip,主机名,删除原有dfs。
b.修改主节点上的xcall和xsync两个脚本,把新节点添加进去。
c.修改/etc/hosts,添加新节点信息,并同步到所有节点
2.在一个路径下(一般选择${hadoop_home}/etc/hadoop)创建一个文件(一般名为dfs.hosts.include)。内容为所有的节点(原有和新加DN)
3.修改hdfs-site.xml,添加一个配置项指向新创建的文件


    dfs.hosts
    xxx      

4.修改slaves文件,添加新服役的节点
5.同步配置文件
6.刷新节点
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes
7.在新服役的节点上启动DN服务
hadoop-daemon.sh start datanode
8.根据实际情况进行数据的均衡
start-balancer.sh

退役旧节点
在dfs服务不重启的前提下,动态减少一个已有的DN。
步骤:
1.在一个路径下(一般选择${hadoop_home}/etc/hadoop)创建一个文件(一般名为dfs.hosts.exclude)。内容为需要退役的节点
2.修改hdfs-site.xml ,添加配置项指向退役的文件

 
     dfs.hosts.exclude
     xxx
 

3.同步配置文件
4.刷新节点
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes
刷新节点之后,退役的节点首先会进入到Decommission in process(正在退役)状态,把数据转移到其他节点转移完毕之后,自动改为Decommissioned(已退役)状态
注意:
DN节点数一定要大于等于副本数,否则退役不成功,需要更改副本数
5.关闭DataNode服务,从slaves里删除退役的节点
hadoop-daemon.sh stop datanode

HDFS的其他管理功能(一些零散的知识点)
1.集群之间的数据传输
cp:本地之间的数据传输
scp:一个局域网内之间(跨节点)的数据传输
不管目标文件是否存在或相同,都做一次完整的复制
rsync:一个局域网内之间(跨节点)的数据传输
判断目标文件与当前文件的差别,把不一样的地方进行复制
hadoop distcp:两个集群之间的数据传输(复制)

hadoop distcp  
hadoop distcp hdfs://node101:9000/apple
hdfs://node000:9000/
注意:这个命令需要执行MapReduce程序,所以需要开启yarn服务。

2.小文件处理
只要文件存到hdfs里,都要遵循hdfs的规则既不足128M按128M计算。
严重浪费hdfs的存储资源,尤其是小文件量特别大的情况。
存档与linux本地的tar原理类似,把多个小文件压缩成一个文件。
创建存档
hadoop archive -archiveName NAME.har -p 父路径 src* dest
查看存档
hadoop fs -lsr /home.har 正常的查看,看不见存档之前的文件
hadoop fs -lsr har:///home.har 以har规则进行查看,可以看见原文件
hadoop fs -cat har:///home.har/xxx 可以查看具体的文件内容
解除存档
hadoop fs -cp har:///home.har / 通过复制的形式,还原原文件

3.配额管理
数量的配额
hdfs dfsadmin -setQuota n url 设置数量上限
hdfs dfsadmin -clrQuota url 取消数量上限
注意:上限包括当前目录
容量的配额
hdfs dfsadmin -setSpaceQuota n [type] url 设置容量上限
hdfs dfsadmin -clrSpaceQuota url 取消容量上限

windows环境的搭建
步骤:
1.解压缩 hadoop.tar.gz
2.配置环境变量
新建 HADOOP_HOME
path %HADOOP_HOME%/bin %HADOOP_HOME%/sbin
3.把bin(支持Windows操作)目录下的所有文件覆盖到Hadoop安装目录的bin目录下
把hadoop.dll文件放在C://Windows/System32目录下
4.修改配置文件
与linux环境的配置文件基本保持一致,只是路径按照windows的规则写
注意:路径改成Windows的规则,并且分隔符使用 /
5.格式化
hadoop.cmd namenode -format
6.启动服务
start-dfs.cmd
注意:正常使用的时候不需要开启hdfs的服务,就可以直接使用。

MapReduce

处理海量数据怎么计算的问题
由来:
谷歌论文
map-reduce -> MapReduce
a.从论文的角度分析,mapreduce就是一种思想
b.从技术的角度分析,MapReduce是一种计算框架

软件框架(software framework),通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。

MapReduce给我们提供了哪些规范?
思想的规范
map:映射 key-value键值对
把数据划分成最小的数据单元。
怎么理解最小->按照实际的业务逻辑划分最小单位
把最小的数据单元根据实际情况变成键值对的形式发送到下一个阶段。
reduce:合并
按key相同的,value值合并
合并:
i.每组分别合并,最终再汇总。
ii.整体进行汇总。(默认使用的汇总方式)
把合并之后的结果以键值对的形式写入文件。
2.代码的规范
Mapper类
把数据划分成最小数据单元,以键值对展示的具体代码实现
Reducer类
按key相同,value值合并的具体代码实现
Driver
一般是主方法,指定一些Mapper和Reducer的一些特有的情况
比如:输入输出文件 输入输出泛型 等
举例:wordCount 地位相当于是java中的 hello world

序列化
内存和磁盘之间需要频繁地进行数据的交换
序列化:把内存中的对象以字节数组的形式写入磁盘的过程
反序列化:把磁盘中的字节数组以对象的形式写入内存的过程
java的序列化:
java有序列化,但是是比较重量级的序列化,不适合海量数据的处理。
hadoop的序列化:
在java序列化的基础上进行轻量级改进,更加适合海量数据的处理。
在原理上与java序列化没有任何区别,在实现上与java不同。

数据类型
java的数据类型 在hadoop中相应的序列化类型

byte      ByteWritable

short     ShortWritable

int       IntWritable

long      LongWritable

float     FloatWritable

double    DoubleWritable

boolean   BooleanWritable

String    Text

Array     ArrayWritable

null      NullWritable

          自定义序列化类型

什么情况使用自定义序列化类型?
在基本数据类型不能满足开发者的需求的时候,必须自定义。
如果key或者value表示的数据大于1个字段的时候,需要重新自定义一个类。

shuffle 洗牌
map是一个进程 mapTask
reduce也是一个进程 reduceTask
MapReduce中只有这两种进程
shuffle是存在于mapTask和reduceTask之间的一个过程
shuffle可以分为map端的shuffle和reduce端的shuffle
shuffle的执行流程:
a.根据分片规则划分出不同的节点执行
b.每个节点接收到相应数据,按照mapper代码划分出最小数据单元并发送
c.发送出去的数据进入到环形缓冲区(100M 达到80%产生溢写)
d.数据溢写到磁盘缓冲区,执行分区(partitioner),排序(sort),合并(combiner可选)
e.reduce端shuffle主动向map端索取数据
f.在reduce端做分组合并(key相同的,把value合并成一个序列)
g.把 key->序列 键值对送到reduce端代码执行处理
h.把最终结果写入文件

分区(partitioner):
map端shuffle的第一个执行过程
对数据按照某种条件或逻辑进行分别处理的时候使用分区。
注意:
a.map的数量与reduce的数量没有任何关系
b.每个reduce处理所有map的其中一个特定分区

分区数量与reduceTask的数量关系
    规则:分区数量要小于等于reduceTask的数量
    a.分区数等于reduceTask数,完美分配。每个分区的数据进入一个reduce
    b.分区数小于reduceTask数,正常分配。不会报错,会有空reduce
    c.分区数大于reduceTask数,直接报错,无法执行
    d.分区数大于1,reduceTask等于1,特殊情况,所有分区数据进入reduce

默认分区:
使用HashPartitioner类实现默认分区
HashPartitioner extends Partitioner,重写getPartition方法。
方法实现:
通过key的hashCode值与Integer的最大值做&操作,
与reduceTask的数量取余,余数是几,当前的key就在哪个分区。
总结:默认分区数与reduceTask数量保持一致。
方法返回的余数就是它所在的分区编号,为随机分区。

自定义分区:
自己写一个类(单独类或内部类),继承Partitioner,重写getPartition方法
在方法中按照实际业务逻辑进行分区,返回的数字就是相应的分区编号。
注意:在driver中,要指定reduceTask数量和分区类。

排序
发现规律:
MapReduce执行完毕之后,所有的key都是有序的。
顺序:自然顺序
默认的排序规则
1.原有的序列化数据类型,都实现了Comparable接口
重写compareTo方法,在方法中定义默认的排序规则
2.自定义数据类型,如果想要充当key的话,必须要实现Comparable接口
重写compareTo方法,定义自定义类型的默认排序规则
自定义排序规则
1.当前的默认排序规则无法满足我们的排序需求的时候,
可以使用自定义排序规则打破默认的排序规则,
但是不会影响其他类使用默认排序规则。
2.代码实现
hadoop自带的序列化类型都是有一个Comparator内部类
继承了WritableComparator类,重写compare。
在compare中定义自己的排序规则,有一个构造器进行注册。
WritableComparable和WritableComparator比较
a.WritableComparable用于序列化数据类型的默认排序规则,
WritableComparator用于序列化数据类型的自定义排序规则。
b.WritableComparable是使用implements实现接口,
WritableComparator是使用extends继承使用。
c.WritableComparable重写compareTo方法,
WritableComparator重写compare方法。
d.WritableComparable有指定泛型,一般是当前类,
compareTo方法中有一个参数。
WritableComparator不指定泛型,
compare方法中以两个WritableComparable的参数传递
e.WritableComparable类中不需要注册,不需要单独指定,直接使用
WritableComparator类中必须由构造方法注册,并在driver指定使用

排序专题:

  • 部分排序(默认排序)
    每个分区的key全部有序,但是整体无序。
  • 全排序
    不仅每个分区的key全部有序,而且整体有序。
    想要达到全排序的效果,解决方案:
    a.把reduce的数量设置为1
    b.按照业务逻辑自定义分区
    c.随机抽样
    由于数据的不均衡分配或者是数据随时调整,很有可能在原有分区的基础上产生数据倾斜问题,一旦产生数据倾斜问题,会让某个reduce节点的计算量远远大于其他节点的计算量,影响整体的性能。
    为了解决这个问题,我们采用随机抽样的方式,
    动态地选择临界点作为分区的依据。
    步骤:
    1.设置分区类 TotalOrderPartitioner类
    2.设置随机抽样(0.5,1000,4)
    第一个参数:是每条数据被抽取到的概率
    第二个参数:样本数量,抽取这些数据进行统计分析
    第三个参数:最大分区数,一般与reduce数量保持一致
    3.writePartitionerFile(job,sample)
    相当于把随机抽样后得到的临界点写入_partition.lst文件
    4.如果已经有分区的临界点文件,可以不用随机抽样
    直接TotalOrderPartitioner.setPartitionFile(…)
    注意:
    1.分区文件的路径默认走配置文件,应该所有位置都设置成本地
    2.输入路径一定要放在随机抽样代码之前,否则找不到文件
    3.如果使用随机抽样,输入文件的格式必须是序列化文件。
    job.setInputFormatClass(SequenceFileInputForma.class)
    4.mapper端的keyIn和valueIn 必须与序列化文件保持一致
    序列化文件:
    hdfs中使用的一种类型,每行的内容有且仅有key和value。
    读写数据的时候按照实际的key和value的类型进行读写。
    windows下的查看命令 hdfs.cmd dfs -text file:///xxx
  • 二次排序
    在有多个字段的时候(自定义序列化类型),如果一个字段无法满足排序需求
    必须使用两个甚至两个以上的字段同时作为排序的条件。
    注意:
    a.自定义类型写默认排序规则的时候,尽量把所有字段全部考虑到。
    b.排序规则如果字段少,可以使用三目形式
    如果字段较多,建议使用if…else…形式,逻辑比较清晰
    c.不管默认排序规则怎么定义,如果使用自定义排序规则,与默认无关。
  • 倒排索引

combiner
是shuffle过程中的一部分,根据业务逻辑可以存在可以不存在。
实质上,combiner就是在map端完成部分reduce的工作。

为什么是部分reduce的工作而不是全部?
集群中执行的时候,有多个map,多个reduce。
每个map只能完成当前这个节点的数据汇总,而reduce需要所有map的汇总。
所以最后一定需要一个reduce对所有的map做最终合并。
正常情况下,combiner的输入是map端的输出,combiner的输出是reduce的输入

分组排序:
分组:把一些具有相同特征的内容放在一起,形成一个分组
MapReduce中的执行位置:是在reduce端的shuffle的一个过程
MapReduce中什么时候使用分组:
把map端的数据按照key相同的,value值自然形成一个分组。
分组的依据:
MapReduce本身提供的默认序列化类型
只有一个字段数据,所以这个字段如果相同就自然成一组。
也可以打破原有的默认分组规则,自定义指定,很少使用。
自定义序列化类型
一个类型中有两个及以上字段,这个就比较复杂。
所以想要分为一组,必须指定分组的条件(n个字段)
怎么实现分组:
世上本没有分组,只是按照一定的排序规则对数据进行排序,
如果在排序过程中按照此排序规则有相同的数据,自然形成一个分组。
结论:
分组就是排序
所以默认的排序规则可以充当默认的分组规则。
如果默认的分组规则不能满足需求,使用自定义分组规则。
实现:
1.正常走MapReduce就可以,默认的排序规则就是默认的分组规则
2.自定义一个分组排序类,语法与自定义排序类一样job.setGroupingComparatorClass(…);

排序和分组的区别:
1.排序就是按照某种规则进行顺序的指定
所谓的规则就是某个(些)字段按照升序或降序排列
分为默认的排序规则和自定义排序规则
a.默认排序是写在数据类型(原生和自定义)中的,不需要特殊指定。
b.自定义排序单独写一个类,继承WritableComparator,重写compare方法
必须在driver中通过job.setSortComparatorClass(xxx);进行指定
2.在没有特殊指定的情况下,默认的排序规则就是默认的分组规则。
按照正常的排序进行,如果遇到内容相同,则自动分组。
分组规则可以单独写一个类,继承WritableComparator,重写compare方法
需要在driver中通过job.setGroupingComparatorClass(xxx)进行指定;
3.排序和分组在shuffle中的位置不一样
排序是在map端的shuffle
分组是在reduce端的shuffle

join 连接
mysql中表连接
innerJoin
leftJoin
rightJoin
MapReduce中的表连接
属于一种业务,没有真正的表,使用不同文件的数据充当表数据。
mysql中使用sql语句实现,在MapReduce中使用代码实现。

并行度

  • reduce端的并行度
    一般在集群中,一个节点启动一个reduceTask。
    reduceTask的数量是由代码决定的。
    job.setNumReduceTask(n)
    n就是reduce端的并行度
    数量是可以随意设定的,但是要考虑到实际的业务逻辑。根据实验的结论
    在满足实际的业余逻辑的前提下,尽可能的让reduce的数量趋向于集群中
    从节点的数量,才能保证性能最优。

  • map端的并行度
    map端的并行度不是人为决定,需要一个临界点对原数据进行切割而来,
    由于map端需要读取hdfs上的数据,为了避免hdfs数据块重组后再分割,
    直接按照block块的大小(128M)为map端分片的临界点。
    这样可以直接读取hdfs上的block直接进入map端处理。
    如果原数据有多个文件,每个文件分别进行切片处理。
    每个切片,是一个InputSplit,作为每个map端的输入数据。
    每个InputSplit会启动一个mapTask。
    mapTask的数量与reduceTask的数量没有任何关系。
    mapTask里的分区数量与reduceTask数量由关系。
    注意:
    如果剩余大小不足10%,不会进行切分。避免过小的分区存在。

输入格式化

  • TextInputFormat
    纯文本文件,每一行内容都是String类型的数据。
  • SequenceFileInputFormat
    序列化文件,文件中只有key和value,并且key和value都有各自的类型。
    使用的时候在代码中需要指定key和value的具体类型。
  • KeyValueTextInputFormat
    键值对文本文件,文件中只有key和value,但是key和value都是Text类型。
    不做特殊指定的情况下,这里的key和value默认按照\t进行分割。
    可以使用代码指定分隔符
    job.getConfiguration()
    job.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR,",");
  • NlineInputFormat
    改变原有的切片规则,以行为单位进行切片,可以设置切片的行数。
    如果没有特殊指定的情况下,默认以1行为一个切片,每个文件分别切片
    可以使用代码指定每个切片的行数
    NLineInputFormat.setNumLinesPerSplit(job,n);
  • CombineTextInputFormat
    a.对于小文件进行处理的一种方式,为了避免每个小文件都占用一个mapTask,浪费资源,通过combine可以把多个小文件合并在一起处理。
    b.切片的时候正常是每个文件分别切片,即使文件特别小,也会占用一个切片的位置,如果使用此方式,可以把所有小文件当做一个文件整体处理。
    c.关于CombineTextInputFormat里的maxISplitSize属性:
    I.split切片由设置的元数据输入路径下的文件而来
    II.一个切片里不能有不同池里的块数据
    III.一个切片可以有一个节点中的不同文件里的块数据
    IV.不设置这个属性,每个机架下的所有节点里的文件为一个单独的split
    V.设置这个属性,先按照每个节点进行合并,剩余内容在同机架下合并
    VI.属性值与块大小一致,分片规则与hadoop里的规则基本保持一致
    VII.属性值不与块大小一致,分片规则如下
    1)虚拟存储过程
    a.遍历每一个文件,当前文件大小与设置的最大值进行比较
    b.如果文件容量小于最大值,自己本身自成一个文件。
    c.如果文件容量介于最大值与最大值2倍之间,原文件均分。
    d.如果文件容量大于最大值的2倍,按照最大值切分:
    每一次切分之后还要继续判断剩余容量与最大值关系
    执行上面的判断步骤
    2)切片过程
    通过上一步虚拟存储结果(<=最大值),分别与设置的最大值比较
    a.如果不超过最大值,与后面的合并为一个split切片
    如果两个合并后还小于最大值,继续与第三个合并,直到大于等于最大值
    b.如果等于最大值,直接为一个split切片。
  • 自定义

输出格式化

  • TextFileOutputFormat
    以纯文本文件的形式输出
  • SequenceFileOutputFormat
    以序列化文件的形式输出

MapReduce中的一些零散的知识点

  • 压缩
    hadoop处理的数据量是相当巨大,执行过程过IO读写的次数会非常多,
    为了提高磁盘的利用率,可以使用压缩机制。
    但是在一定程度上会增加计算的压力,所以要根据实际情况合理使用压缩
    使用条件:
    a.计算密集型的程序,减少使用压缩机制
    b.磁盘密集型的程序,多使用压缩机制
    可以使用压缩的位置:
    1.mapper之前:原数据可以使用压缩文件
    2.mapper之后,reducer之前:执行MapReduce的中间结果
    3.reducer之后:最后输出的结果
    使用:看文档

  • 计数器
    在某些需要做数据统计的地方添加计数器,方便在控制台查看计数结果。
    使用的方式:
    Counter counter = context.getCount(groupName,counterName);
    counter.increment(n);
    说明:
    map端和reduce端可以分别使用计数器,计数的位置不同,但是语法相同
    最后有汇总阶段的计数,要根据map和reduce端的组名决定是否合并。

  • 链式MR
    a.在一个代码中,可以存在多个Mapper,但是只能有一个Reducer。
    ChainMapper.addMapper
    ChainReducer.setReducer / ChainReducer.addMapper
    b.reducer之前不管有多少个Mapper,实质上都属于一个Mapper。
    reducer之后(包含)不管有多少个Mapper,实质上都属于一个Reducer。

  • 数据清洗
    属于一种业务逻辑。
    由于数据量巨大,所以在计算之前要把所有会影响到计算结果甚至起反作用的数据给过滤掉,以保证数据的准确性和计算的高性能。

yarn

yarn是hadoop中的一个组件,是一个资源调度器
什么是资源:软件资源、硬件资源
从另一个角度来说,yarn也可以看成是一种操作系统
对当前计算机的软件和硬件资源进行管理。是一个独立的管理系统。
对集群中的所有节点做统一的硬件和软件资源的调度。
yarn是一种规范,只要符合yarn的管理机制的框架,都可以使用yarn资源管理器
比如:spark。
角色:

  • ResourceManager
    资源管理者,管理整个集群的资源调度。
    全局只有一个,一般与NameNode在同一个节点。

  • NodeManager
    节点管理者,负责当前节点的工作
    每一个DataNode里都有一个NodeManager

  • ApplicationMaster
    应用程序(我们自己写好的代码)的管理者,
    从软件的角度对资源进行分配。

  • Container
    容器,盛放硬件资源的容器,是一个抽象的概念。
    从集群的角度虚拟化出来能保证程序正常运行的硬件资源

yarn的执行原理:
1.由客户端提交job任务,向ResourceManager申请Application
2.ResourceManager反馈给客户端一个路径和ApplicationId
3.客户端向 路径/applicationId 发送job运行所需内容
4.客户端向ResourceManager申请ApplicationMaster
5.ResourceManager分配一个NodeManager,通过Container虚拟化硬件环境,执行ApplicationMaster,从软件角度分配任务(map和reduce)
6.applicationMaster向ResourceManager申请n个mapTask任务
7.ResourceManager分配n个NodeManager,加载资源,执行mapTask。
8.applicationMaster向ResourceManager申请n个reduceTask任务
9.ResourceManager分配n个NodeManager,从map端获取数据,执行reduce
10.所有任务执行完毕,applicationMaster向ResourceManager申请注销释放资源,当前节点可以继续完成其他的任务。
11.MapReduce的执行是边执行边申请资源。
yarn的资源调度方式:

  • 先进先出调度器(FIFO Scheduler)
    只有一个队列,先来的任务先分配执行,后来的后分配

  • 容量调度器(Capacity Scheduler)
    有多个队列,每个队列遵循先进先出原则
    新来的任务,根据每个队列的占用比,占用越少,任务分配到这个队列

  • 公平调度器(Fair Scheduler)
    有多个队列,每个队列中的任务都会分配一定的资源
    按照缺值最大有限分配
    新来的任务,根据每个队列的缺值比,缺值越小的,分配到当前队列

  • 修改yarn的资源调度方式

yarn-default.xml 默认是CapacityScheduler
      
  yarn.resourcemanager.scheduler.class      
  org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
 

zookeeper

管理整个hadoop生态圈的组件
与yarn的区别?
yarn是管理类似MapReduce这样的小范围的资源。
zookeeper是管理整个hadoop生态圈的资源。
zookeeper = 文件系统 + 监听通知机制

  • 文件系统:
    一个小型的文件系统,存储的是大家都关心的数据。
    存在的形式:
    树形结构,树上有很多个节点,每个节点叫做一个znode
    默认的情况下,只有一个根节点(zookeeper)
    随着数据不断增加,树的节点也会越来越多
    数据的形式:
    以key-value键值对的形式表示
    key表示当前这个znode的名字
    value表示当前这个znode内的具体内容
  • 监听通知机制:
    监听所有节点上需要监听的数据,如果数据发生了变化,
    当前节点的zookeeper会感知到此变化,
    并通知给zookeeper集群的所有其他节点。

zookeeper的架构:
zookeeper本身有自己独立的集群,节点主从结构。

  • 角色:
    leader:领导者,充当主节点,全局只有一个。
    follower:随从,充当从节点,全局可以有很多个。

  • 主从节点怎么确定:
    hadoop中,在配置文件中直接指定,
    在不改变配置信息的前提下,主节点是不发生变化的
    zookeeper,在整个集群中通过选举的形式产生主节点。
    选举机制
    采取投票选举的方式确定leader,只要票数过半直接当选,
    当选的leader不会让位,只有当前leader宕机的时候,才会重新选举下一任leader。
    半数原则
    在zookeeper集群中,只要超过集群数量一半的节点可以使用,那么集群就可用。

  • 如果宕机怎么办?
    a.如果follower宕机,只要剩余数量不少于半数,不受影响
    b.如果leader宕机,剩余数量不少于半数,重新选举

  • zookeeper集群的数量一般都是奇数个节点。

zookeeper的执行原理
通过事件id控制整个集群的数据变化
某个节点以当前最大id+1的id向leader提交数据
leader接收到数据后,会验证id,看是否冲突。
如果不冲突,接纳此事件,并把当前id和事件同步给所有节点
如果同一时刻有多个节点以相同id发送数据,谁快要谁。
慢的那个事件被leader驳回,但可以以下一个id继续提交
zookeeper提交事件只有两个结果:
a.被接纳,同步给其他所有节点
b.被驳回,换个id继续提交
zookeeper中 文件系统的简单命令

zkCli.sh   :进入到文件系统的编辑环境
help       :显示帮助信息(所有可用的命令)
ls path [watch]   :显示当前路径下的所有子znode
ls2 path [watch]  :显示当前路径下所有子znode的详细信息
create path data  :以键值对的形式创建znode
get path    :获取某个znode下的数据
set path data  :修改某个znode的数据
delete path    :删除空znode
rmr path       :级联删除非空znode 

zookeeper的环境搭建

  • 本地模式(standalone)
    1.解压缩
    2.配置环境变量
    3.修改配置文件
    cp zoo_sample.cfg zoo.cfg
    dataDir=xxx
    4.启动服务
    zkServer.sh start / zkServer.sh status
    5.正确执行

  • 集群模式
    选择奇数个节点作为集群
    在本地模式的基础上
    1.修改配置文件
    zoo.cfg
    server.id=hostName/ip:2888:3888
    2888为zookeeper内部通讯端口,3888为选举机制通讯端口
    …(有几个节点就写几个节点)
    在dataDir相应目录下,添加myid文件,内容为当前节点id。
    2.启动服务
    每个节点分别启动
    xcall 启动服务
    启动的命令写成脚本

你可能感兴趣的:(Big,Data)