新手大数据开发一枚,之前也做了一些MR、Spark、Storm的项目,但是有些框架本身的东西还不是很懂,毕业季找工作,就顺手整理一些东西。希望在这个过程中能把只是融会贯通。不会很细的去面面俱到的写框架,只会写一写自己遇到的问题。
HDFS的设计思想(1)一次写入,多次读取
(2)hdfs是对搞数据吞吐量优化的,以提高时间延时为代价
(3)namenode存储着文件系统的元数据(每个目录、每个文件和数据块的存储信息)
Hadoop2.x默认block size增大为128M,这样做有什么好处?(1)减轻了namenode的压力
Hadoop集群在启动的时候,会向namenode上报自己的block信息。namenode会把这些信息存在内存中。如果块变大了,那么namenode记录的信息相对减少,所以namenode就有更大的内存去做其他的事情,使得整个集群的性能增强。
(2)增大带来的影响?
这个应该不是问题,可以灵活设置。
如果数据量级别达到PB的话,可以设置的大一些。
负面影响:如果网络环境不好,可能会造成重新传输。
引申:Namenode和Datanode
NameNode
:namenode管理文件系统的命名空间。它维护文件系统树以及整棵树内所有的文件和目录。这些信息是永久保存
在本地磁盘的,以两个文件的形式:命名空间镜像文件和编辑日志文件同时,NameNode会也记录着每个文件中各个块所在的数据节点信息,但是这些文件不是永久保存的,这些信息会在系统启动的时候由数据节点重建。 DataNode
:根据需要存储并检索数据块,并定期向namenode的发送存储的数据块的列表NameNode的灾备:运行一个辅助namenode的,但不会被用作名称节点(Secondary NameNode)。这个节点一般在另一台单独的物理计算机(内存需求与NameNode相同)上运行。其作用是通过编辑日志合并并命名空间镜像,以防编辑日志过大。过大的日志文件会使NameNode在下次重新启动时需要更大的时间.Secondary NameNode会在NameNode发生故障时生效。但是其保存的状态也总是滞后于NameNode的,所以在NameNode全部失效时,会有部分数据的丢失。
小文件Block块占用问题:小于块大小的小文件不会占用整个HDFS块空间。较多的小文件会占用更多的NameNode的内存。在Linux File system占用的空间为实际文件的大小,不是一个块的大小。
HDFS设置Block的目的(为什么默认Block设置为128M):
(1)减少硬盘寻道时间:HDFS是支持大容量流式读写操作的,当涉及大数据量时,Block size设置的越小,需要读取的数据块就越多。而数据块在硬盘上是非连续存储的,普通硬件移动磁头,随机寻址较慢,读越多的数据块就增大了总的硬盘寻址时间。合适的块大小有助于减少硬盘寻道时间,提高系统吞吐量。
联邦HDFS
NameNode在内存中保存文件系统中每个文件和每个数据块的引用关系
这意味着对于一个拥有大量文件的超大集群来说,内存将成为限制系统横向拓展的瓶颈。在Hadoop2.x中引入的联邦HDFS允许系统通过添加的NameNode实现拓展,其中每个NameNode的管理文件系统命名空间中的一部分。在联邦环境下,每个NameNode会维护一个命名空间卷,包括命名空间的源数据和在下的文件的所有数据块的。命名空间卷之间是相互独立的,两两之间并不相互通信,甚至其中一个的NameNode的失效也不会影响由其他的NameNode维护的命名空间的可用性。数据块池不再切分,集群中的DataNode需要注册到每个NameNode,并且存储着来自多个数据块池中的数据块。Client端上传文件Client向NameNode发起文件写入的请求.NameNode根据文件大小和文件块配置情况,返回给客户端所有者管理部分Dat aNode的信息.Client将文件划分为多个Block,根据DataNode的地址信息,按顺序写入每一个DataNode块中。
Hadoop环境搭建配置文件conf目录下的:core-site.xml中; HDFS-site.xml中; mapred-site.xml中
写入HDFS文件client链接NameNode,确定文本起始块的位置。NameNode返回存有该块副本的DataNode地址。
这些DataNode根据他们与客户端的距离来排序(根据集群的网络拓扑)。
client通过HDFS的API将数据块存储到DataNode上。
DataNode将数据水平备份。并且备份完将反馈给client
client通知NameNode存储块完毕。
NameNode将元数据同步到内存中。
读取HDFS文件1、client链接NameNode,查看元数据,找到数据的存储位置
2、client通过HDFS的API并发读取数据
3、并发连接
Hadoop中combiner的作用每一个map都会有一个本地输出。combiner的作用是对map的输出先做一次合并,以减少map和Reduce间的数据通信量(减少网络IO)。combiner的输出是Reduce的输入,这一步骤绝不会改变最终的结果。
Hadoop partition的作用partition的默认实现是hashpartition,是map端将数据按照reduce个数取余,进行分区,不同的reduce来copy自己的数据。
partition的作用是将数据分到不同的reduce进行计算,加快计算效果。
简述Hadoop搭建的过程1、新建Hadoop用户,并赋予sudo权限
2、配置Java环境
3、配置/etc/hosts 主机与IP的
4、配置免密
5、解压Hadoop版本包
6、配置Hadoop conf目录下的hadoop -env.sh,core-site.xml,hdfs-site.xml,mapre-site.xml
7、配置Hadoop的环境变量
8、hadoop namenode -format
9、.bin/start-all.sh
Hadoop 杀死一个jobhadoop job -list (拿到job ID)
hadoop job -kill job-id
hadoop 加载一个新的存储节点和删除一个计算节点动态添加DataNode,不停用namedode方式:
1、修改slaves文件,添加需要增加的节点host或者IP,并将其
更新
到各个节点 2、在DataNode中执行启动DataNode命令。
sh hadoop-daemon.sh start datanode
在NameNode
3、可以通过界面查看节点添加情况。
删除一个存储节点:
hadoop dfsadmin -refreshNodes
hadoop dfsadmin -report
Hadoop 作业调度器调度器基本作用:根据节点资源使用情况和作业的要求,将任务调度到各个节点上执行
调度器考虑的因素:作业提交时间、作业优先级、作业所在队列的资源限制。
文章图片
1、client通过submitJob()函数向jobTracker提交一个作业
2、Jobtracker通知taskSechduler,进行初始化,创建一些内部函数
3、tasktracker通过心跳向jobtracker汇报它的资源情况,比如空闲的map slot和Reduce slot
4、如果jobtracker发现第一个tasktracker有空闲的资源,JobTracker 就会调用 TaskScheduler的assignTasks() 函数,返回一些task list给第一个TaskTracker。 这时TaskTracker就会执行调度器分配的任务。
Hadoop自带调度器:
1、先进先出调度器(FIFO)
2,容量调度器:支持多个队列,每个队列可配置一定的资源量,每个队列采用FIFO调度策略,为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占的资源进行限制。
3,公平调度器:公平调度,所有工作具有相同的资源
mapreduce如何解决数据倾斜数据倾斜:map / reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个减少节点运行很慢,导致整个程序的处理时间很长,这是因为某一个的条键数比其他键多很多(有时是百倍或者千倍之多),这条关键所在的减少节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜。
解决方法:自己实现分区类,用键和值相加取散列值
源码:
public int getPartition(K key,V value,
int numReduceTasks){
返回(key.hashCode()&Integer.MAX_VALUE的)%numReduceTasks;
}
修改后:
public int getPartition(K key,V value,
int numReduceTasks){
return (((key).hashCode()+value.hashCode()) & Integer.MAX_VALUE) % numReduceTasks;
}
或者:
public class HashPartitioner extends Partitioner {
private int aa= 0;
/** Use {@link Object#hashCode()} to partition. */
public int getPartition(K key, V value,
int numReduceTasks) {
return (key.hashCode()+(aa++) & Integer.MAX_VALUE) % numReduceTasks;
}
Hadoop框架的优化:(1) 从应用程序角度进行优化。由于mapreduce是迭代逐行解析数据文件的,怎样在迭代的情况下,编写高效率的应用程序,是一种优化思路。
(2) 对Hadoop参数进行调优。当前hadoop系统有190多个配置参数,怎样调整这些参数,使hadoop作业运行尽可能的快,也是一种优化思路。
(3) 从系统实现角度进行优化。这种优化难度是最大的,它是从hadoop实现机制角度,发现当前Hadoop设计和实现上的缺点,然后进行源码级地修改。该方法虽难度大,但往往效果明显。
(4)linux内核参数调整
从应用程序角度进行优化
(1) 避免不必要的reduce任务
如果mapreduce程序中reduce是不必要的,那么我们可以在map中处理数据, Reducer设置为0。这样避免了多余的reduce任务。
(2) 为job添加一个Combiner
为job添加一个combiner可以大大减少shuffle阶段从map task拷贝给远程reduce task的数据量。一般而言,combiner与reducer相同。
(3) 根据处理数据特征使用最适合和简洁的Writable类型
Text对象使用起来很方便,但它在由数值转换到文本或是由UTF8字符串转换到文本时都是低效的,且会消耗大量的CPU时间。当处理那些非文本的数据时,可以使用二进制的Writable类型,如IntWritable, FloatWritable等。二进制writable好处:避免文件转换的消耗;使map task中间结果占用更少的空间。
(4) 重用Writable类型
很多MapReduce用户常犯的一个错误是,在一个map/reduce方法中为每个输出都创建Writable对象。例如,你的Wordcout mapper方法可能这样写:
public void map(...) {
…for (String word : words) {
output.collect(new Text(word), new IntWritable(1));
}
}
这样会导致程序分配出成千上万个短周期的对象。Java垃圾收集器就要为此做很多的工作。
更有效的写法是:
class MyMapper ... {
Text wordText = new Text();
IntWritable one =new IntWritable(1);
public void map(...){
for(String word:words){
wordText.set(word);
output.collect(wordText,one);
}
}
}
(5)使用StringBuffer而不是String
mapreduce工作流程mapreduce实际的处理过程可以理解为Input->Map->Sort->Combine->Partition->Reduce->Output。
【大数据面试集锦---Hadoop篇】1、Input
数据以一定的格式传递给Mapper,有TextInputFormat等可以使用
2、map阶段
对输入的(key,value)进行处理
3、Sort阶段
对Map的输出进行排序,map的输出会放到一个缓冲区中,在缓冲区进行与排序。如果数据过大,超出缓冲区大小,会有个溢写到磁盘过程。
4、Combiner
这个阶段对于sort之后有相同key的结果进行合并
5、Partition阶段
将mapper的中间结果按照key的范围划分为R份,按照key分别映照给不同的Reduce。partition的作用就是把这些数据归类
6、Reduce阶段
对于mapper阶段的结果进行进一步处理
7、output阶段
Reduce输出数据的格式
推荐阅读
- 人工智能|干货!人体姿态估计与运动预测
- Python专栏|数据分析的常规流程
- 读书笔记|《白话大数据和机器学习》学习笔记1
- 网络|一文彻底搞懂前端监控
- html5|各行业工资单出炉 IT类连续多年霸占“榜首”位置
- 人工智能|【机器学习】深度盘点(详细介绍 Python 中的 7 种交叉验证方法!)
- 网络|简单聊聊压缩网络
- 数据库|效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)...
- r语言|手把手(R语言文本挖掘和词云可视化实践)
- 腾讯|SaaS的收入模型有哪些(终于有人讲明白了)