大数据学习笔记(持续更新)

大数据学习笔记(持续更新)

写在前面:本博客是用于记录以及总结大数据学习过程中的笔记,会持续更新

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指令杀掉原有进程

posted @ 2021-12-06 11:36  醉生梦死_0423  阅读(251)  评论(0)    收藏  举报