1、文件上传:
总结: 客户端上传请求--->namenode检查,返回响应--->客户端真正的文件上传请求,包括文件名,文件大小--->namenode返回上传节点--->客户端准备上传,进行块的逻辑切分--->客户端构建pipline流--->开始上传,先上传到缓存中,再上传到磁盘--->上传完成,关闭pipline流--->上传其他数据块--->全部上传完成,namenode更新元数据。 |
2、文件下载
总结: 客户端下载请求--->namenode进行检查,文件是否存在,并在元数据库中搜索文件的块信息及副本存储位置--->客户端开始下载,就近原则--->数据块1下载完成,下载其他数据块--->所有数据块下载完成,客户端返回下载完成。 |
3、元数据合并
总结: Seconderynamenode向namenode定义发送检查的请求,检查是否需要进行元数据合并--->namenode返回需要合并--->seconderynamenode发送合并请求--->namenode将正在编辑的日志文件进行回滚,转化为历时日志文件,生成新的正在编辑日志--->Seconderynamenode将edits文件和fsimage(该文件只发生在第一次合并中)文件拷贝到Seconderynamenode上--->元数据合并,生成新的fsimage文件--->Seconderynamenode将fsimage文件刷到磁盘--->将fsimage文件发到namenode并覆盖旧的。 |
4、文件切片split和文件切块block的区别?
文件切块:是HDFS进行数据存储的单位,物理上的切片,不同的数据块有可能存储在不同的数据节点上。
文件切片:是一个逻辑概念,是MR任务过程中和maptask任务一一对应的,是maptask任务执行对应的数据单元,并没有进行物理切分。
经过上面的分析:一个文件切片的大小128M最合理的。
5、MAPReduce的详细流程:
1、 一个大文件需要处理,它在在 HDFS 上是以 block 块形式存放,每个 block 默认为 128M存 3 份,运行时每个 map 任务会处理一个 split,如果 block 大和 split 相同( 默认情况下确实相同),有多少个 block 就有多少个 map 任务,所以对整个文件处理时会有很多 map 任务进行并行计算 3、数据溢写入到磁盘之前,首先会根据 reducer 的数量划分成同数量的分区(partition),每个分区中的都数据会有后台线程根据 map 任务的输出结果 key2 进行内排序(字典顺序、自然数顺序或自定义顺序 comparator),如果有 combiner,它会在溢写到磁盘之前排好序的输出上运行(combiner 的作用是使 map 输出更紧凑,写到本地磁盘和传给 reducer 的数据更少),最后在本地生成分好区且排好序的小文件; 如果 map 向环形缓冲区写入数据的速度大于向本地写入数据的速度,环形缓冲区被写满,向环形缓冲区写入数据的线程会阻塞直至缓冲区中的内容全部溢写到磁盘后再次启动,到阀值后会向本地磁盘新建一个溢写文件; 8、“最终文件”输入到 reduce 进行计算,计算结果输入到 HDFS。 |
6、Yarn的资源调度的过程
1、客户端向resourcemanager发送提交任务的请求
2、在resourcemanager端进行一系列的检查,检查输入和输出目录、权限
3、所有的检查都通过,resourcemanager会为当前的应用程序分配一个nodemanager节点,并在这个节点上启动container。并在这个container中启动MRAppMaster
4、MRAppMaster向resourcemanager申请资源,运行maptask任务和reducetask任务。
5、resourcemanager向MRAppMaster返回资源,优先返回有数据的节点。
6、MRAppMaster到相应的节点上启动container,然后在启动maptask任务和reducetask任务。
7、maptask或reducet任务启动之后需要向MRAppMaster进行汇报自身的运行状态和进度。
8、当maptask或reducetask运行完成,这个时候会向MRAppMaster进行注销自己,释放资源。
9、当整个应用程序运行完后,MRAppMaster向reducemanage注销自己 释放资源
7、job的提交的过程:
共享资源路径:
/tmp/hadoop-yarn/staging/hadoop/.staging/job_1535279614938_0001/job.jar 就是我们应用程序的jar包 wc.jar(放在共享资源路径下就自动改了job名字)
job.split job运行的数据切片信息 FileInputFormat.addInputPath() getSplit():决定启动的maptask的任务数量、决定启动maptask的节点信息
job.splitmetainfo
job.xml job.setJarByClass(Driver.class) 封装的是job的所有信息 配置文件
job.getConfiguration.getClass()
1、客户端向ResourceManager提交job的申请
2、ResourceManager进行一系列的检查,返回一个jobID(表示job提交的先后顺序)和一个共享资源路径HDFS
3、客户端将共享资源job.jar job.split job.xml放在共享资源路径下
4、客户端通知RM资源放置完成,并真正的开始提交应用程序。
5、RM会返回一个NM节点,假设返回的是nodemanager02
6、RM到对应的节点上限启动contaoiner,再启动MRAppMaster
7、MRAppMaster进行初始化,生成一个作业薄。
8、MRAppMaster去共享资源路径下载共享资源nodemanager02
9、MRAppMaster想RM申请资源maptask reducetask
10、RM向MRAppMaster返回资源,优先资源本地node01 node02 node03
11、启动maptask前,先去共享资源下载jar包,MRAppMaster到对应的节点上启动maptask任务
12、maptask向MRAppMaster汇报状态和进度
13、reducetask获取maptask运行完成的时候,启动reducetask,启动之前先去下载jar包。
14、Maptask和reducetask运行过程中,如有运行完成的则会向MRAppMaster注销自己,释放资源
15、所有的maptask和reducetask运行完成,MRAppMaster向ResourceManager注销自己,释放资源
8、Hive是什么?
Hive是一个hadoop的客户端,对外提供sql接口,数据存储在HDFS,计算使用MR
9、产生数据倾斜的原因:
A:key分布不均匀
B:业务数据本身的特性
C:建表考虑不周全
D:某些HQL语句本身就存在数据倾斜
10、Hive中的表数据删除了可以恢复吗?
可以,内部表:原始数据删除了。通过垃圾回收机制可以恢复。但元数据不能恢复。
外部表:原始数据没有被删除,只是删除了表与数据的对应关系。
11、面试题:创建实例对象的五种方式:
- 调用构造器(公开)
- 静态工厂方法(构造器私有) 可以实现单例
- 反射(Class,Constructor,Method,Field)
- 克隆(Object.clone())
- 反序列化(ObjectOutputStream oos / ObjectInputStream ois)
12、DAGScheduler的工作流程:
1、spark-submit提交任务 2、初始化DAGScheduler 和 TaskScheduler 3、接收到applicatoin之后,DAGScheduler 会首先把applicatoin抽象成一个DAG 有向无环图 4、DAGScheduler对这个DAG(DAG中的一个Job)进行stage的切分 5、把每一个stage提交给TaskScheduler |
13、yarn-client、 yarn-cluster两种模式的差别
spark-submit提交给yarn的两种方式总结与区分:
spark-submit提交给yarn有两种方式:1为yarn-cluster, 2为yarn-client
两种方式的区别:
yarn-client主要是用于测试,因为driver运行在本地客户端,负责调度application,会与yarn集群产生大量的网络通信,会导致网卡流量激增!!好处在于直接执行时,本地可以看到所有的log,方便调试
yarn-cluster用户生产环境,以为driver运行在nodemanager,没有网卡流量激增的问题。缺点在于调试不方便,本地用spark-submit提交后,看不到log,只能通过yarn application -logs application_id这种命令来查看,比较麻烦 或者 yarn logs -applicationId application_id
14、Yarn作业执行流程
1、用户向 YARN 中提交应用程序,其中包括 MRAppMaster 程序,启动 MRAppMaster 的命令,用户程序等。
2、ResourceManager 为该程序分配第一个 Container,并与对应的 NodeManager 通讯,要求它在这个 Container 中启动应用程序 MRAppMaster。
3、MRAppMaster 首先向 ResourceManager 注册,这样用户可以直接通过 ResourceManager 查看应用程序的运行状态,然后将为各个任务申请资源,并监控它的运行状态,直到运行结束,重复 4 到 7 的步骤。
4、MRAppMaster 采用轮询的方式通过 RPC 协议向 ResourceManager 申请和领取资源。
5、一旦 MRAppMaster 申请到资源后,便与对应的 NodeManager 通讯,要求它启动任务。
6、NodeManager 为任务设置好运行环境(包括环境变量、JAR 包、二进制程序等)后,将任务启动命令写到一个脚本中,并通过运行该脚本启动任务。
7、各个任务通过某个 RPC 协议向 MRAppMaster 汇报自己的状态和进度,以让 MRAppMaster 随时掌握各个任务的运行状态,从而可以在任务败的时候重新启动任务。
15、Yarn资源调度器
Fifo schedular : 默认的单一队列调度器,先进先出的原则
Capacity schedular : 计算能力调度器,选择占用最小、优先级高的先执行,依此类推。
Fair schedular: 公平调度,所有的 job 具有相同的资源
16、Hive内部表与外部表的区别,如何选用
区别:
删除内部表,删除元数据表和真实数据;
删除外部表,只删除元数据表,不删除真实数据
元数据存在哪里?Derby MySQL
如何选用:
如果一份数据仅仅只是使用 Hive 做统计分析,那么可以使用内部表;
如果一份数据,既需要使用 Hive 去进行分析,还需要用其他计算引擎计算分析,那么就选外部表
17、Hive 支持的文件存储格式
1.行式存储:
textfile、sequencefile
2.(行分块)列式存储:
rcfile、orcfile、parquet
列式存储的优势:
1、更高的压缩比,由于相同类型的数据更容易使用高效的编码和压缩方式。
2、更小的I/O操作,可以减少一大部分不必要的数据扫描,尤其是表结构比较庞大的时候更加明显,由此也能够带来更好的查询性能。
18、Hive 分区表与分桶表
分区在HDFS上的表现形式是一个目录, 分桶是一个单独的文件
分区: 细化数据管理,直接读对应目录,缩小mapreduce程序要扫描的数据量
分桶 1、提高join查询的效率(用分桶字段做连接字段)
2、提高抽样的效率
19、Outer Join、Inner Join的区别
外连: left join/right join返回结果除了连接上的记录外,还有没连接上的记录(未连接的记录字段为null)
內连:join返回结果只有连接上的记录
20:zookeeper的文件系统:
类似于Linux文件系统的树状结构,每个节点叫znode,znode既能是目录也能是文件。
znode的存储数据量的关系:不能超过1M,最好小于1K
21:znode的分类:
按照生命周期分: 临时 和 持久,临时节点下不能创建子节点
按功能分: 带顺序编号 和 不带顺序编号,顺序编号是由当前这个顺序编号节点的父节点进行维护
22:zookeeper事件监听流程
1)client添加监听(哪个znode节点的什么事件)
NodeDataChanged
NodeChildrenChanged
NodeCreated
NodeDeleted
zookeeper系统会存储一些必要的信息:
session1, znode1, NodeDeleted
session2, znode2, NodeChildrenChanged
2)当前这个监听要被注册到zookeeper
3) zookeeper当识别到有对应的客户端对这个数据有对应事件类型的操作时,会封装当前这次事件的各种必要信息为WatchedEvent对象
4) 返回当前这次事件的通知对象WatchedEvent到对应的客户端
5) 去当前客户端的一个守护线程中寻找当时添加的那个监听器对象,这个监听器对象是存储在WatchManager中
6) 最后回调这个监听器对象中的process(WatchedEvent)方法b监听器只生效一次,在回调方法 process 中进行监听的添加能保证循环监听
23:zookeeper的应用场景
1、命名服务/名称服务/namespace管理/名字空间
模拟实现: znode系统中的任何一节点的寻路路径,有一个唯一的绝对路径
你把对应的那个名字在zookeeper的znode中创建一个节点,如果能创建成功,证明取名成功
所有同种类型的名称节点都必须统一的存储在统一目录
2、配置管理:把一个集群的所有配置都放置在zookeeper进行管理
原因:由于zookeeper提供了一个非常好的监听机制,能够让监听程序立即感知到数据的变化
zookeeper的两大核心功能区实现配置管理
模拟实现:
1、创建一个节点存储一个值(删除/修改/增加)
2、添加监听器去监听这个值的对应的事件
3、监听程序就一直等待着zookeeper发送回来的通知(响应的事件)
4、监听程序就按照事件对象WatchEvent对象中包含的信息来进行判断,来做不同的业务处理
5、业务逻辑(当数据发生变化之后重新再查询一次就OK)是独立于zookeeper
3、锁:分为两大类;
1)读写锁
读锁:共享锁
写锁:独占锁 排它锁
2)时序锁
利用创建带顺序编号的节点 就能对应的模拟完成
4、队列:分为两种:
1)同步队列:一个队列中的所有成员都聚齐时,才能进行某个业务操作
2)FIFO : 时序锁几乎是一样的实现逻辑
5、集群管理:分为两种:
1)主节点的管理:主备之间的竞争问题
可以创建一个节点代表一个namenode(最好是临时节点)
只要某个namenode一宕机,那么zookeeper系统中代表这个namenode的对应znode节点就会自动被删除
zookeeper就能发送通知到监听程序
如果说其中一个namenode的监听程序监听到当前这个namenode宕机
那么这个监听程序就会发送通知到另外一个监听程序
这个监听程序就可以发起一次选举来选举新的active 状态的anemnode
当前这个监听程序还会负责;
1、确定之前的那个namenode一定要死亡
2、确保当前要切成成active状态的namenode一定能切换过来
防止脑裂
2)从节点的管理:从节点的 上线管理(创建znode) 和 下线管理(删除一个znode)
利用zookeeper让namenode能够瞬时感知datanode的上线和下线
怎么实现?
在zookeeper系统中创建一个代表该datanode的znode节点(最好是临时的)
当前某个datanode如果宕机,那么对应的znode节点被zookeeper集群自动删除
如果zookeeper识别到代表某个datanode的znode被自动删除,就会发送事件通知到对应的监听程序
监听程序:就是监听/servers节点下的子节点的个数变化事件
当监听程序收到通知时,就能知道整个集群中的子节点(datanode)的个数发生了变化
再从zookeeper的znode系统中再重新查询一次就能知道现在还存活的datanode的列表有那些。
24、 zookeeper 选主过程
选举算法:基于 Fast Paxos :FastLeaderElection 算法
ZooKeeper 的核心是原子广播,这个机制保证了各个 Server 之间的同步。
实现这个机制的协 议叫做 ZAB 协议(Zookeeper Atomic BrodCast)。
5.1 全新集群:----------------------
以五台服务器的选主为例子:启动顺序分别是1,2,3,4,5
1、启动1,1去联系leader,跟leader做状态数据, 因为是第一个启动的。 所以没有寻找到leader那么就发起投票来进行选举leader, 首先选举自己来成为leader,但是发起投票的请求给其他的服务器,这些服务器全部都没有响应。所以最终不能选举成功,当前这个节点1就进入looking状态
2、启动2,2要去联系leader,跟1一样也没有寻找到leader,2节点也要发起投票来选举leader,最终投票结束之后,2节点只能收集到2个赞成票,还不至于能决定当前的2节点成为新的leader,原因是赞成票并没有超过集群的总节点(只有能参与投票的总节点数)的半数, 2节点也进入looking状态
3、启动服务器3,3也没有联系到leader,所以也会发起投票,最终投票结果是3节点获取到3票。所以3票超过了总节点的半数,所以服务器节点3就能成为leader。所以,所有上线了的其他服务器就自动成为规定好的角色:follower
4、启动服务器4,去联系leader,能寻找到该zookeeepr集群有leader,当前服务器4就自动成为follower
5、启动服务器5 和 4结果的过程一样
5.2 非全新集群:------------------------
那么,初始化的时候,是按照上述的说明进行选举的,但是当 zookeeper 运行了一段时间之 后,有机器 down 掉,重新选举时,选举过程就相对复杂了。
需要加入数据 version、serverid 和逻辑时钟。
数据 version:数据新的 version 就大,数据每次更新都会更新
version server id:就是我们配置的 myid 中的值,每个机器一个
逻辑时钟:这个值从 0 开始递增,每次选举对应一个值,也就是说:如果在同一次选举中, 那么这个值应该是一致的;逻辑时钟值越大,说明这一次选举 leader 的进程更新,也就是 每次选举拥有一个 zxid,投票结果只取 zxid 最新的选举的标准就变成:
1、逻辑时钟小的选举结果被忽略,重新投票
2、统一逻辑时钟后,数据 version 大的胜出
3、数据 version 相同的情况下,server id 大的胜出根据这个规则选出 leader。
25、spark应用执行命令是什么
26、 spark分区的概念:
分区是RDD内部并行计算的一个计算单元,RDD的数据集在逻辑上被划分为多个分片,每一个分片称为分区,分区的格式决定了并行计算的粒度,而每个分区的数值计算都是在一个任务中进行的,因此任务的个数,也是由RDD(准确来说是作业最后一个RDD)的分区数决定。
27、spark实现wordCount
28、什么是数据混洗,数据混洗会对性能产生什么样的影响?
定义:shuffle中文一般称为 数据混洗。
shuffle的官方定义是,它是spark的一种让数据重新分布以使得某些数据被放在同一分区里的一种机制。
性能影响:
shuffle操作涉及到网络传输数据,可能还有序列化的问题。它通过map来组织数据,通过reduce来聚集,(这里的mapreduce只是作为Hadoop的mapreduce意义的一种引申)
shuffle操作会占用堆内存,当内存不够用时,就会把数据放到磁盘上。
shuffle操作会在磁盘上产生大量的中间文件,这些文件只有在相关的RDD不再使用并被回收后,才会被删除。这样做的目的是多次shuffle的时候,不用重复进行计算。所以,长时间运行Spark的任务必定消耗巨大的磁盘空间。临时文件的目录可以通过spark.local.dir进行设置。
29、spark应用执行有哪几种模式,其中哪几种是集群模式?
30、常用算子
1、常用的transformation:返回值还是一个RDD,对一个RDD进行计算后,变换成另外一个RDD,然后这个RDD又可以进行另外一次转换。这个过程是分布式的
map、filter、flatMap、mapPartition
union、intersection、distinct
groupByKey、reduceByKey、aggregateByKey、sortByKey、sortBy
2、常用action算子:Action返回值不是一个RDD。它要么是一个Scala 的普通集合,要么是一个值,要么是空,最终或返回到Driver程序,或把RDD写入到文件系统中
Reduce、reduceByKeyLocally、collect、count、countByKey、foreach、aggregate
31、RDD定义广播大变量
1、能不能将一个RDD使用广播变量广播出去?
不能,因为RDD是不存储数据的。可以将RDD的结果广播出去。
2、广播变量只能在Driver端定义,不能在Executor端定义。
3、在Driver端可以修改广播变量的值,在Executor端无法修改广播变量的值。
4、如果executor端用到了Driver的变量,如果不使用广播变量在Executor有多少task就有
多少Driver端的变量副本。
5、如果Executor端用到了Driver的变量,如果使用广播变量在每个Executor中都只有一份
Driver
- Hash表算法处理海量数据处理面试题
- 经典问题分析
- 为什么要根据hash后值映射到不同的机器上?
- 一、Bloom filter:判断元素是否可能在集合中
- 二、Hashing方法处理文件
- 三、bit-map 数据查找判重和删除(元素是否在集合中)
- 四、堆 TopN-大顶堆和小顶堆
- 五、双层桶划分----其实本质上就是【分而治之】的思想,重在“分”的技巧上!
- 六、数据库索引
- 七、倒排索引(Inverted index)
- 八、外排序
- 九、trie树
- 十、分布式处理 mapreduce
主要针对遇到的海量数据处理问题进行分析,参考互联网上的面试题及相关处理方法,归纳为三种问题
(1)数据量大,内存小情况处理方式(分而治之+Hash映射)
上千万or亿数据(有重复),统计其中出现次数最多的前N个数据,分两种情况:可一次读入内存,不可一次读入。
可用思路:trie树+堆,数据库索引,划分子集分别统计,hash,分布式计算,近似统计,外排序
所谓的是否能一次读入内存,实际上应该指去除重复后的数据量。如果去重后数据可以放入内存,我们可以为数据建立字典,比如通过 map,hashmap,trie,然后直接进行统计即可。当然在更新每条数据的出现次数的时候,我们可以利用一个堆来维护出现次数最多的前N个数据,当然这样导致维护次数增加,不如完全统计后在求前N大效率高。
如果数据无法放入内存。一方面我们可以考虑上面的字典方法能否被改进以适应这种情形,可以做的改变就是将字典存放到硬盘上,而不是内存,这可以参考数据库的存储方法。
当然还有更好的方法,就是可以采用分布式计算,基本上就是map-reduce过程,首先可以根据数据值或者把数据hash(md5)后的值,将数据按照范围划分到不同的机子,最好可以让数据划分后可以一次读入内存,这样不同的机子负责处理各种的数值范围,实际上就是map。得到结果后,各个机子只需拿出各自的出现次数最多的前N个数据,然后汇总,选出所有的数据中出现次数最多的前N个数据,这实际上就是reduce过程。
外排序的方法会消耗大量的IO,效率不会很高。而上面的分布式方法,也可以用于单机版本,也就是将总的数据根据值的范围,划分成多个不同的子文件,然后逐个处理。处理完毕之后再对这些单词的及其出现频率进行一个归并。实际上就可以利用一个外排序的归并过程。
实际上可能想直接将数据均分到不同的机子上进行处理,这样是无法得到正确的解的。因为一个数据可能被均分到不同的机子上,而另一个则可能完全聚集到一个机子上,同时还可能存在具有相同数目的数据。比如我们要找出现次数最多的前100个,我们将1000万的数据分布到10台机器上,找到每台出现次数最多的前 100个,归并之后这样不能保证找到真正的第100个,因为比如出现次数最多的第100个可能有1万个,但是它被分到了10台机子,这样在每台上只有1千个,假设这些机子排名在1000个之前的那些都是单独分布在一台机子上的,比如有1001个,这样本来具有1万个的这个就会被淘汰,即使我们让每台机子选出出现次数最多的1000个再归并,仍然会出错,因为可能存在大量个数为1001个的发生聚集。因此不能将数据随便均分到不同机子上,而是要根据hash 后的值将它们映射到不同的机子上处理,让不同的机器处理一个数值范围。
(面试中当给定了大数据量和内存限制解决方案:1.分而治之 2.利用Hash处理文件,大文件拆分为小文件3,对结果合并汇总)