大数据学习笔记(持续更新)
大数据学习笔记(持续更新)
写在前面:本博客是用于记录以及总结大数据学习过程中的笔记,会持续更新
20211206更新===
-
HDFS的实现思想:
- hdfs是通过分布式集群(一个文件会被分成许多块,每一块可能不在同一个主机上)来存储文件,为客户端提供了一个便捷的访问方式(客户端不需要知道文件散落在哪里,只需要知道文件名以及集群中的虚拟文件路径即可,集群内部会完成检索以及分配任务),就是一个虚拟的目录结构
- 文件存储到hdfs集群中去的时候是被切分成block的
- 文件的block存放在若干台datanode节点上
- hdfs文件系统中的文件与真实的block之间有映射关系,由namenode管理
- 每一个block在鸡群中会存储多个副本,好处是可以提高数据可靠性,还可以提高访问的吞吐量
-
HDFS内部文件不可修改(可以追加,不能更改指定位置内容)
-
namenode通过ssh远程登录来启动datanode上的HDFS
-
免秘钥流程(如图):
1、请求登录(主机1请求主机2)
2、查看授权列表
3、主机2用主机1的公钥加密一个随机字符串给主机1
4、主机1用自己的私钥解密随机字符串
5、将解密结果发送给主机2
6、主机2验证解密结果,若正确则通过
7、通过验证
注:公钥私钥产生以及传输流程:
- 主机1本地通过对应算法产生私钥和公钥
- 主机1将公钥复制给主机2
- 主机2将公钥添加到授权列表文件“authorized_keys”————>保存公钥
- 生成秘钥对指令:
ssh-keygen -t rsa
,生成后的输出信息中有生成路径,沿着路径找到后,复制到需要免密主机,使用scp指令传输;在被传输的主机上.ssh文件夹下(每个用户都有一个.ssh文件夹,对应每个用户的免秘登录)的authorized-keys后追加公钥
NN元数据管理机制
写在前面:下文中NameNode用NN简写代替,DataNode使用DN代替
-
副本由DN集群中内部传递
-
客户端请求上传文件流程
1、向NN申请上传文件
2、NN返回给客户端分配好的DN
3、客户端向分配好的DN写入数据(客户端不用关分块的事情,集群内部会自我进行传输,客户端只要专注传输逻辑即可)
-
元数据如何存储
-
首先需要明确一点,元数据肯定是需要再内存中有一份的,因为内存快,方便查询
-
然后整个流程分为两个文件,两个节点(NN和secondNN),三个文件-->内存中的记录表、edits log日志文件(防止突然宕机数据丢失)、fsimage文件,后两者都是在硬盘中的(持久化文件防止丢失)
-
流程如下:
1、客户端向NN请求上传
2、客户端将分配信息以及即将进行的操作写入edits log
3、NN将分配信息返回client
4、client接收到信息后向DN集群写入数据
5、client告诉NN写完了
6、NN将元数据写入内存
注:关于fsimage和edits log 以及内存中的元数据意义以及关系如下:
- 内存中存储的是最完整的元数据信息以供读写,但是内存是非持久化的,断电宕机都有可能丢失数据
- edits log记录的是操作信息,同时宕机未完成的操作也会记录进去,恢复之后可以读取日志然后重新操作
- fsimage是内存中信息在硬盘中的持久化镜像,保证信息不会丢失
- edits log容量有一个上限,如果上限满了,就和fsimage进行一次合并操作,然后清空原有edits log(刷新操作)==>该操作在secondNN上进行(该阶段NN会产生一个新的edits log.new文件用于写入数据,然后老edits log和fsimage合并完之后就被删除,新edits log.new文件被重命名为edits log(防止log满了之后client还有请求,写入需要时间)
- 三者关系:内存的内容=edits log内容 + fsimage内容
- second NN存在意义:防止NN负载过大(同时要接收请求和合并文件)
-
-
NN和SN之间的关系以及工作流程
-
NN主要职责:
- 维护元数据信息
- 维护HDFS的目录树
- 相应客户端的请求
-
工作流程:
1、通知SN进行checkpoint
2、停止往edits log写入
3、NN生成新的edits文件用于写入
4、SN从NN下载fsimage文件
5、SN将edits log和fsimage合并成新的镜像文件
6、SN向NN上传新镜像
7、NN删除旧的fsimage和edits log保留新的fsimage以及将edits log.new更名为edits log
-
什么时候checkpoint:
- fs.checkpoint.period 指定来那个词checkpoint的最大时间间隔---->默认3600秒(1h)
- fs.checkpoint.size 规定edits文件的最大容量,一旦超过,则强制flush,不管是否到达规定时间间隔,默认大小为64M
-
调用远程服务工作原理
-
DN要定期向NN汇报block情况(可能会有意外情况)
-
RPC(Remote Procedure Call):远程过程调用==>一个节点请求另一个节点提供的服务
-
hadoop中RPC实现流程(前四个流程在控制器端-->客户端)
1、生成调用端socket程序动态代理对象
2、通过proxy调用业务方法
3、调用socket的请求方法
4、发送调用请求(向服务端-->Service)
5、生成impl的动态代理对象
6、调用业务代理对象的具体业务方法
7、获取调用结果
8、向控制器返回调用结果
9、socket程序向代理返回结果
注:其实就是一个socket通信过程,因为本地无法直接调用远端的方法,需要通过socket传输的方式来实现调用服务器上的方法
-
贴一段实现代码(分服务器端和控制器端以及共同实现的接口(协议))
- 控制器端
//LoginController import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; import java.io.IOException; import java.net.InetSocketAddress; public class LoginController { public static void main(String[] args) throws IOException { LoginServiceInterface hadoop01 = RPC.getProxy(LoginServiceInterface.class, 1L, new InetSocketAddress("hadoop01", 10000), new Configuration()); String result = hadoop01.login("admin", "123456"); System.out.println(result); } }
- 共同接口
public interface LoginServiceInterface { public static final long versionID=1L; public String login(String username,String password); }
- 服务器端
//LoginService public class LoginServiceImpl implements LoginServiceInterface{ @Override public String login(String username, String password) { return username + "logged in successfully!"; } }
Map-Reduce模型工作原理
-
模型分为Map和Reduce两个部分
- Map部分先分布式执行任务,然后每触发一个条件,就传输到Reduce,Reduce再进行整合,最终输出,传输都是使用键值对的方式
- 下面是一个小小的例子的代码,用于统计文件中单词的数量(分隔符为空格)
//Map程序,触发一次条件,就输出一次 package cn.itcast.hadoop.mr.wordcount; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.io.LongWritable;// 传递的数据更加精简 import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; //<KEYIN, VALUEIN, KEYOUT, VALUEOUT>四个泛型中前两个是指定mapper输入数据<key,value>的类型,后面两个是指定输出的类型 // map和reduce的数据输入输出都是以key-value对的形式封装的 // 默认情况下,框架传递给我们的mapper的输入数据中,key是要处理的文本中一行的起始偏移量,这一行的内容定义为value public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable> { //mapreducr框架每读一行数据就调用一次该方法 @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //具体业务逻辑就写在此方法体中,而且我们业务要处理的数据已经被框架传递进来,在方法的参数中key-value //key 是这一行数据的起始偏移量 value是这一行的文本内容 String line = value.toString(); String[] words = StringUtils.split(line, " "); //遍历数组并输出 for (String word : words) { context.write(new Text(word),new LongWritable(1)); } } }
//Reduce程序,将接受到的所有信息做一个汇总,然后输出 package cn.itcast.hadoop.mr.wordcount; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class WCReducer extends Reducer<Text, LongWritable,Text, LongWritable> { //框架在map处理完成之后,将所有kv对缓存起来,进行分组,然后传递一个组<key,values{}>,调用一次reduce方法 //举例:<hello,{1,1,1,1,1,1……}> @Override protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException { long count = 0; //遍历value的list,进行累加求和 for (LongWritable value : values) { count += value.get(); } //输出这一个单词的统计结果 context.write(key,new LongWritable(count)); } }
//入口程序,配置地址之类的东西 package cn.itcast.hadoop.mr.wordcount; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; /** * 用来描述一个特定的作业 * 比如,该作业使用那个类作为逻辑处理中的map,那个作为reduce * 还可以指定该作业要处理的数据所在的路径 * 还可以指定目标路径 */ public class WCRunner { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); Job job = Job.getInstance(conf); //设置整个job所用的那些类在哪个jar包内 job.setJarByClass(WCRunner.class); //本job使用的mapper和reducer的类 job.setMapperClass(WCMapper.class); job.setReducerClass(WCReducer.class); //指的是reduce的输出==>可对reduce和map都起作用(如果map不单独设置的话),如果reduce和map输入输出类型相同,则只要配一次就行 job.setOutputKeyClass(Text.class); job.setOutputValueClass(LongWritable.class); //指的是map的输出 job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(LongWritable.class); //指定要处理的输入数据存放在哪里 FileInputFormat.setInputPaths(job, new Path("/wc/srcdata")); //指定要处理的输出数据存放在哪里 FileOutputFormat.setOutputPath(job, new Path("/wc/output")); //将job提交给集群运行 job.waitForCompletion(true); } }
- 最终程序需要打包成jar在集群上运行,入口程序设置为WCRunner(如果在本地运行,就是本地的程序,不会调用集群,只是把文件存储到集群上去而已,而在集群上执行,就是调用集群的资源以及方法)
job提交的逻辑
写在前面:以下文章中,ResourceManager简写为RM;NodeManager简写为NM
-
一个main方法中可以有多个job,但是设置起来不灵活,所以在实际应用中都是一个main方法对应一个job然后使用shell脚本文件来控制运行顺序
-
这一块主要讲上述WCRunner执行之后再集群和WCRunner中发生的事情的一个逻辑
1、Run.jar向ResourceManager申请一个job
2、RM返回job相关资源自交的路径和为本job产生的jobID
3、Run.jar提交资源
4、Run.jar向RM汇报提交结果
5、RM在内部将本次job加入任务队列
6、各个NM在RM队列中领取任务
7、NM在内部分配运行资源并产生容器
8、第七步产生的同时,RM会启动在NM容器中的MRAppMaster(用于管理MapReduce程序)==>它是集群动态生成的yarnchild进程,在jps查询结果中可以查询得到
9、MRappMaster向RM注册(防止它出问题或者意外情况,这样RM是知情的)
10、注册之后启动Map任务进程(由MRAppMaster管理)
11、启动Reduce任务进程
12、job完成后,向RM发出请求注销自己
注:yarn只管资源调度,不懂MapReduce逻辑(yarn是NM中的ResourceManager,只管分配MRAppMaster yarn子程序来管理资源调度,其他的MapReduce工作由NM来完成==>这样的模式会让yarn与MapReduce解耦合,让yarn变得更通用,从而只要有程序符合它的标准,就可以把工作交给它)
MR程序的几种提交运行的方法
本地运行模式
- windows中编译器直接运行main方法==>将job提交给本地执行器LocaljobRunner执行
- 输入输出数据可放在本地路径下(需要绝对路径,而且conf中不能有东西)
- 输入输出数据也可以放在hdfs中(远端路径)
- 在linux中编译器直接运行main方法,但是不添加yarn相关的配置,也是提交给本地执行
集群运行模式
- 将工程打包成jar,上传到服务器,然后用hadoop命令提交
hadoop jar wc.jar xx.WCRunner
- 在linux中的编译器直接运行main方法,也可以提交到集群中运行,但必须采取以下措施:
- 在工程src目录下加入mapred-site.xml和yarn-site.xml配置文件
- 将工程打包成jar,同时在main方法中添加conf的配置参数
conf.set("mapreducejob.jar","wc.jar")
- 在windowns编译器运行main方法,也可以提交到集群中运行,但因为平台不兼容要做很多设置
- 要在windows中存放一份hadoop的安装包(不必安装)
- 要将其中lib和bin目录替换成根据你windows版本重新编译出来的文件
- 要配置系统环境变量HADOOP_HOME和PATH
- 修改YarnRunner这个类的源码
20211217更新=
-
java中,要实现反射的类中必须要有空构造,否则通过反射机制实现这个类会报错
-
WritableComparable类继承之后(Bean继承)——[注意不是继承writable和comparable两个类,这样无法实现排序;writableComparable是],重写CompareTo方法,会实现自动排序
-
1、排序是 MR 中非常重要的操作之一,MapTask 和 ReduceTask 都会对数据按照 key 进行排序。该操作是默认行为。任何 MR 程序中数据均会被排序,而不看逻辑是否需要。
2、MapTask 中,它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率到一定的阈值,再对缓冲区数据进行一次快排,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行归并排序。
3、ReduceTask 中,它从每个 MapTask 上远程拷贝相应的数据文件,如果文件大小超过一定阈值,则溢写到磁盘上,否则储存在内存上。如果磁盘上文件数目达到一定阈值,则进行一次归并排序以生成一个更大文件。如果内存中文件大小或者数目超过一定阈值,则进行一次合并后将数据溢写到磁盘上。当所有数据拷贝完后,ReduceTask 统一对内存和磁盘上的所有数据进行一次归并排序。
————————————————
版权声明:本文为CSDN博主「火成哥哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a1786742005/article/details/104529572
-
map task的并发数是由切片的数量决定的,有多少个切片,就启动多少个map task
-
切片是一个逻辑的概念,指的就是文件中数据的偏移量范围
-
切片的具体大小因该根据所处理的文件大小来调整
-
一个超大文件在HDFS上存储时,是以多个Block存储在不同的节点上,比如一个512M的文件,HDFS默认一个Block为128M,那么1G的文件分成4个Block存储在集群中4个节点上。
Hadoop在map阶段处理上述512M的大文件时分成几个MapTask进行处理呢?Hadoop的MapTask并行度与数据切片有有关系,数据切片是对输入的文件在逻辑上进行分片,对文件切成多少份,Hadoop就会分配多少个MapTask任务进行并行执行该文件,原理如下图所示。
Block与Splite区别:Block是HDFS物理上把数据分成一块一块;数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。如下图所示,一个512M的文件在HDFS上存储时,默认一个block为128M,那么该文件需要4个block进行物理存储;若对该文件进行切片,假设以100M大小进行切片,该文件在逻辑上需要切成5片,则需要5个MapTask任务进行处理。————————————————
版权声明:本文为CSDN博主「苍鹰蛟龙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010502101/article/details/104012173
shuffle机制
-
通俗来说,就是处理文件碎片,然后收集排序合并,类似洗牌的流程
-
流程:
1、MRAPPMASTER启动各个NodeManager中的map task
2、NodeManager返回完成信息
3、通知Reduce Task要取哪个分区的数据以及数据的位置
4、Reduce Task所在的NodeManager从有数据的NN磁盘中下载数据
5、将下载的多分数据合并成一个文件
6、将合并的数据交给reduce mask运算处理
7、输出结果到文件中(例:part_r_00000)
注:一个Node只管本地的数据=>将数据排序溢出到磁盘文件中
MapReduce架构
- 头:InputFormat接口=>可自定义
- 尾:OutputFormat接口=>可自定义
- 意义:将读文件和MapReduce分开,这样文件源头可以是多样化的:
- 本地
- 网络
- hdfs
- 数据库
- ...
Zookeeper分布式协调服务
-
Zookeeper主要提供少量数据的存储和管理(存储状态信息之类的小数据)
-
提供对数据节点的监听
-
会在所有节点中产生leader和follower结点,通过选举产生的(不固定)
-
Zookeeper集群中结点至少存活一半才能运行(由于选举投票机制,人数不够无法产生投票结果)
NN SN模式并非高可用模式
-
NN高可用方案1:
-
能否让两个NN都正常响应客户端请求?
- 应该让两个NN结点在某个时间只能有一个节点能响应客户端请求,响应请求的必须为active的那一台
-
standby状态的结点必须能够快速无缝的切换为active状态
- 意味着两个NN必须时刻保持元数据的一致
-
解决方案:
- 将edits文件放入Zookeeper(实现无缝切换,因为硬盘的数据不会丢失,但是edits文件大小不会太大,所以放在zookeeper内不怕一台NN宕机,因为zookeeper切换很快
- 使用依赖zookeeper实现的qjournal
-
如何避免切换状态的时候出现brain split(脑裂)现象:
- 脑裂就是说集群在有一个NN死掉的时候,会切换另一个结点为active,但是如果切换完成之前之前的NN复活,就会有两个active结点
- 使用ssh发送kill指令杀掉原有进程
-