【面试】大数据开发面经整理

一、大数据组件

  • Hadoop、Hive、Spark的区别是什么?
  • Sqoop的工作原理

(一)Hadoop

1. HDFS的读写流程 ❤

  • HDFS写入流程:

    1. Client(客户端)发送文件上传请求,通过RPC与NameNode建立通信,NameNode检查该用户是否有上传权限,并检查目标文件及父目录是否存在,返回是否可以上传;
    2. Client根据文件大小进行切分(默认128m一块),切分完成后向NameNode请求第一个block该发送到哪些DataNode服务器上;
    3. NameNode收到请求后,根据网络拓扑、机架感知以及副本机制进行文件分配,返回可用的DataNode地址,如A、B、C;
    4. Client收到地址之后与服务器列表中的一个节点如A进行通信(本质上就是RPC调用,建立pipeline),A收到请求后会继续调用B,然后B再调用C,将整个pipeline建立完成,逐级返回Client;
    5. Client开始向A上发送第一个block(先从磁盘读取数据到然后放到本地内存缓存),以packet为单位(默认64k),A收到一个packet就会发送给B,然后B发送给C,A每传完一个packet就会放入一个应答队列等待应答;
    6. 数据被分割成一个个的packet数据包在pipeline上依次传输,在pipeline反向传输中,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipeline ack发送给Client;
    7. 当一个block传输完成之后,Client再次请求NameNode上传第二个block,NameNode重新选择三台DataNode给Client。
  • HDFS读取流程:

    1. Client向NameNode发起RPC请求,确定文件block所在的位置;

    2. NameNode收到请求后检查用户权限及该文件是否存在,若全都满足则视情况返回文件的部分或者全部block列表,对于每个block,NameNode都会返回含有该block副本的DataNode地址;

      这些返回的DataNode地址,会按照集群拓扑结构得出DataNode与客户端的距离,然后进行排序,排序的两个规则:①网络拓扑结构中距离Client近的排靠前;②心跳机制中超时汇报的DataNode状态为STALE,排靠后;

    3. Client选取排序靠前的DataNode来读取block,如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性);

      底层上本质是建立Socket Stream(FSDataInputStream),重复调用父类DataInputStream的read方法,直到这个块上的数据读取完毕;

    4. 当读完列表的block后,若文件读取还没有结束,客户端会继续向NameNode获取下一批的block列表;

    5. 读取完一个block都会进行checksum验证,如果读取DataNode时出现错误,客户端会通知NameNode,然后再从下一个拥有该block副本的DataNode继续读;

    6. read方法是并行地读取block信息,不是一块一块地读取;NameNode只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;

    7. 最终读取来所有的block会合并成一个完整的最终文件。

2. HDFS的副本机制,为什么三副本?副本存放策略

3. HDFS容错机制

4. HDFS在读取文件的时候,如果其中一个块突然损坏了怎么办?

  • 客户端读取完DataNode上的块之后会进行checksum验证,也就是把客户端读取到本地的块与HDFS上的原始块进行数据校验,如果发现校验结果不一致,客户端会通知NameNode,然后再从下一个拥有该block副本的DataNode继续读。

5. HDFS在上传文件的时候,如果其中一个DataNode突然挂掉了怎么办?

6. NameNode在启动的时候会做哪些操作?

7. Secondary NameNode的工作机制是怎样的?

8. Secondary NameNode不能恢复NameNode的全部数据,如何保证

9. NameNode数据存储安全?

10. 在NameNode HA中,会出现脑裂问题吗?怎么解决脑裂?

11. 小文件过多会有什么危害,如何避免?❤

  • Hadoop上大量HDFS元数据信息存储在NameNode内存中,因此过多的小文件必定会压垮NameNode的内存。
  • 每个元数据对象约占150byte,如果有1千万个小文件,每个文件占用一个block,则NameNode大约需要 2G 空间。如果存储1亿个文件,则 NameNode需要20G空间。
  • 解决方法:合并小文件,可以选择在客户端上传时执行一定的策略先合并,或者使用 Hadoop的CombineFileInputFormat<K,V>实现小文件的合并。

12. HDFS的组织架构 ❤

  • Client:客户端
    • 切分文件。文件上传 HDFS 的时候,Client 将文件切分成一个一个的 Block,然后进行存储;
    • 与 NameNode 交互,获取文件的位置信息;
    • 与 DataNode 交互,读取或者写入数据;
    • Client 提供一些命令来管理 HDFS,比如启动关闭 HDFS、访问 HDFS目录及内容等。
  • NameNode:名称节点,也称主节点。存储数据的元数据信息,不存储具体的数据
    • 管理 HDFS 的名称空间;
    • 管理数据块(Block)映射信息;
    • 配置副本策略;
    • 处理客户端读写请求。
  • DataNode:数据节点,也称从节点。 NameNode 下达命令,DataNode 执行实际的操作
    • 存储实际的数据块;
    • 执行数据块的读/写操作
  • Secondary NameNode:并非 NameNode 的热备。当 NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务;
    • 辅助 NameNode,分担其工作量;
    • 定期合并 Fsimage 和 Edits,并推送给 NameNode;
    • 在紧急情况下,可辅助恢复 NameNode

13. MapReduce的具体过程 ❤

14. MR流程中用了多少次排序,用的什么排序?❤

  • 在Map任务和Reduce任务的过程中,一共发生了3次排序
    1. 当map函数产生输出时,会首先写入内存的环形缓冲区,当达到设定的阀值,在刷写磁盘之前,后台线程会将缓冲区的数据划分成相应的分区。在每个分区中,后台线程按键进行内排序
    2. 在Map任务完成之前,磁盘上存在多个已经分好区,并排好序的,大小和缓冲区一样的溢写文件,这时溢写文件将被合并成一个已分区且已排序的输出文件。由于溢写文件已经经过第一次排序,所有合并文件只需要再做一次排序即可使输出文件整体有序。
    3. 在reduce阶段,需要将多个Map任务的输出文件copy到ReduceTask中后合并,由于经过第二次排序,所以合并文件时只需再做一次排序即可使输出文件整体有序
  • 在这3次排序中第一次是内存缓冲区做的内排序,使用的算法使快速排序,第二次排序和第三次排序都是在文件合并阶段发生的,使用的是归并排序。

15. MR中Map Task的工作机制

  • 简单概述:
    inputFile 通过 split 被切割为多个 split 文件,通过 Record 按行读取内容给 map(自己写的处理逻辑的方法) ,数据被 map 处理完之后交给 OutputCollect 收集器,对其结果 key 进行分区(默认使用的 hashPartitioner),然后写入 buffer,每个 maptask 都有一个内存缓冲区(环形缓冲区),存放着 map 的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式溢写到磁盘,当整个 maptask 结束后再对磁盘中这个 maptask 产生的所有临时文件做合并,生成最终的正式输出文件,然后等待 reduce task 的拉取。
  • 详细步骤:
    1. 读取数据组件 InputFormat (默认 TextInputFormat) 会通过 getSplits 方法对输入目录中的文件进行逻辑切片规划得到 block,有多少个 block 就对应启动多少个 MapTask
    2. 将输入文件切分为 block 之后,由 RecordReader 对象 (默认是
      LineRecordReader) 进行读取,以 \n 作为分隔符, 读取一行数据, 返回<key,value>, Key 表示每行首字符偏移值,Value 表示这一行文本内容。
    3. 读取 block 返回 <key,value>, 进入用户自己继承的 Mapper 类中,执行用户重写的 map 函数,RecordReader 读取一行这里调用一次。
    4. Mapper 逻辑结束之后,将 Mapper 的每条结果通过 context.write 进行collect 数据收集。在 collect 中,会先对其进行分区处理,默认使用HashPartitioner

16. MR中Reduce Task的工作机制

  • 简单描述:
    • Reduce 大致分为 copy、sort、reduce 三个阶段,重点在前两个阶段。
    • copy 阶段包含一个 eventFetcher 来获取已完成的 map 列表,由 Fetcher 线程去copy 数据,在此过程中会启动两个 merge 线程,分别为 inMemoryMerger 和onDiskMerger,分别将内存中的数据 merge 到磁盘和将磁盘中的数据进行 merge。
    • 待数据 copy 完成之后,copy 阶段就完成了。开始进行 sort 阶段,sort 阶段主要是执行 finalMerge 操作,纯粹的 sort 阶段,
    • 完成之后就是 reduce 阶段,调用用户定义的 reduce 函数进行处理。
  • 详细步骤:
    1. Copy 阶段:简单地拉取数据。Reduce 进程启动一些数据 copy 线程(Fetcher),通过 HTTP 方式请求 maptask 获取属于自己的文件(map task 的分区会标识每个 map task 属于哪个 reduce task ,默认 reduce task 的标识从 0 开始)。

    2. Merge 阶段:在远程拷贝数据的同时,ReduceTask 启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。

      merge 有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。
      默认情况下第一种形式不启用。当内存中的数据量到达一定阈值,就直接启动内存到磁盘的 merge。与 map 端类似,这也是溢写的过程,这个过程中如果你设置有 Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。内存到磁盘的 merge 方式一直在运行,直到没有 map 端的数据时才结束,然后启动第三种磁盘到磁盘的 merge 方式生成最终的文件。

    3. 合并排序:把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。

    4. 对排序后的键值对调用 reduce 方法:键相等的键值对调用一次 reduce 方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到HDFS 文件中。

17. MR的shuffle过程具体怎么进行的?❤

  • shuffle 阶段分为四个步骤:依次为 分区,排序,规约,分组,其中前三个步骤在 map 阶段完成,最后一个步骤在 reduce 阶段完成。
  • shuffle 是 Mapreduce 的核心,它分布在 Mapreduce 的 map 阶段和 reduce 阶段。一般把从 Map 产生输出开始到 Reduce 取得数据作为输入之前的过程称作shuffle。
  1. Collect阶段:将MapTask的结果输出到默认大小为100M的环形缓冲区,保存的是key/value,Partition分区信息等。

    map的输出被分配到哪个reducer上,是由partitioner决定的;

    • 输入的是map的结果对<key,value>和reducer的数目,返回的则是分配的reducer的编号(整数)。系统缺省的partitioner是HashPartitioner,它以key的Hash值对reducer的数目取模,得到对应的reducer。这样可以保证如果有相同的key值则肯定会被分配到同一个reducer上;
    • 和combiner一样,一般使用默认的,但是特殊情况也可以自定义
  2. Spill阶段:当内存中的数据量达到一定的阀值的时候,就会将数据写入本地磁盘,在将数据写入磁盘之前需要对数据进行一次排序的操作,如果配置了combiner,还会将有相同分区号和key的数据进行排序。

  3. MapTask阶段的Merge:把所有溢出的临时文件进行一次合并操作,以确保一个 MapTask 最终只产生一个中间数据文件。

  4. Copy阶段:ReduceTask 启动 Fetcher 线程到已经完成 MapTask 的节点上复制一份属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值的时候,就会将数据写到磁盘之上。

  5. ReduceTask阶段的Merge:在 ReduceTask 远程复制数据的同时,会在后台开启两个线程对内存到本地的数据文件进行合并操作。

  6. Sort阶段:在对数据进行合并的同时,会进行排序操作,由于 MapTask 阶段已经对数据进行了局部的排序,ReduceTask 只需保证 Copy 的数据的最终整体有效性即可。

18. shuffle阶段的数据压缩机制 ❤

  • 在 shuffle 阶段,可以看到数据通过大量的拷贝,从 map 阶段输出的数据,都要通过网络拷贝,发送到 reduce 阶段,这一过程中,涉及到大量的网络 IO,如果数据能够进行压缩,那么数据的发送量就会少得多。
  • hadoop 当中支持的压缩算法:
    • gzip、bzip2、LZO、LZ4、Snappy
    • 这几种压缩算法综合压缩和解压缩的速率,谷歌的 Snappy 是最优的,一般都选择 Snappy 压缩。

19. 在写MR时,什么情况下可以使用规约(combiner)?❤

  • 规约(combiner)是不能够影响任务的运行结果的局部汇总,适用于求和类,不适用于求平均值,如果 reduce 的输入参数类型和输出参数的类型是一样的,则规约的类可以使用 reduce 类,只需要在驱动类中指明规约的类即可。
  • Combiner 是什么?
    • Combiner 是 MR 程序中 Mapper 和 Reducer 之外的一种组件。
    • Combiner 组件的父类是 Reducer。
    • Combiner 和 Reducer 的区别在于运行的位置
      • Combiner 是在每一个 MapTask 所在的节点运行
      • Reducer 是接收全局所有 Mapper 的输出结果
  • Combiner 的意义就是对每一个 MapTask 的输出进行局部汇总,以减小网络传输量。
  • Combiner 能够应用的前提是不能影响最终的业务逻辑,而且,Combiner 的输出 kv 应该和 Reducer 的输入 kv 类型要对应起来。
  • ① Combiner属于MR的优化方案,使用时不能影响不使用时的reduce结果输出;因此Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大/小值等
  • ② Combiner的作用是在对map端有大量输出时,对输出先做一次合并,以减少传输到reducer的数据量;
  • ③ Combiner最基本是实现本地key的归并,Combiner具有类似本地的reduce功能;
  • ④ Combiner的适用的条件是你可以任意的改变值的顺序,并且可以随意的将计算进行分组,同时需要注意的是一个combiner函数只对一个map函数有作用
  • ⑤ Combiner,在Mapper之后Reducer之前运行。Combiner是可选操作,并非每个MR程序都需要
  • ⑥ 与mapper与reducer不同的是,combiner没有默认的实现,需要显式的设置在conf中才有作用。Combiner的实现一般继承Reducer。

20. yarn 集群的架构和工作原理 ❤

  • YARN 的基本设计思想是将 MapReduce V1 中的 JobTracker 拆分为两个独立的服务:ResourceManager 和 ApplicationMaster。
    ResourceManager 负责整个系统的资源管理和分配,ApplicationMaster 负责单个应用程序的的管理。
  1. ResourceManager: RM 是一个全局的资源管理器,负责整个系统的资源管理和分配,它主要由两个部分组成:调度器(Scheduler)和应用程序管理器(Application Manager)。
    • 调度器根据容量、队列等限制条件,将系统中的资源分配给正在运行的应用程序,在保证容量、公平性和服务等级的前提下,优化集群资源利用率,让所有的资源都被充分利用。
    • 应用程序管理器负责管理整个系统中的所有的应用程序,包括应用程序的提交、与调度器协商资源以启动 ApplicationMaster、监控ApplicationMaster的运行状态并在失败时重启它。
  2. ApplicationMaster: 用户提交的一个应用程序会对应于一个
    ApplicationMaster,它的主要功能有:
    • 与 RM 调度器协商以获得资源,资源以 Container 表示。
    • 将得到的任务进一步分配给内部的任务。
    • 与 NM 通信以启动/停止任务。
    • 监控所有的内部任务状态,并在任务运行失败的时候重新为任务申请资源以重启任务。
  3. NodeManager: NodeManager 是每个节点上的资源和任务管理器
    • 一方面,它会定期地向 RM 汇报本节点上的资源使用情况和各个 Container 的运行状态;
    • 另一方面,他接收并处理来自 AM 的 Container 启动和停止请求。
  4. Container: Container 是 YARN 中的资源抽象,封装了各种资源。一个应用程序会分配一个 Container,这个应用程序只能使用这个 Container 中描述的资源。不同于 MapReduceV1 中槽位 slot 的资源封装,Container 是一个动态资源的划分单位,更能充分利用资源。

21. yarn 的任务提交流程 ❤

  • 当 jobclient 向 YARN 提交一个应用程序后,YARN 将分两个阶段运行这个应用程序:
    • 一是启动 ApplicationMaster;
    • 第二个阶段是由 ApplicationMaster 创建应用程序,为它申请资源,监控运行直到结束。
  • 具体步骤如下:
    1. 用户向 YARN 提交一个应用程序,并指定ApplicationMaster 程序、启动ApplicationMaster 的命令、用户程序。
    2. RM 为这个应用程序分配第一个 Container,并与之对应的 NM 通讯,要求它在这个 Container 中启动应用程序 ApplicationMaster。
    3. ApplicationMaster 向 RM 注册,然后拆分为内部各个子任务,为各个内部任务申请资源,并监控这些任务的运行,直到结束。
    4. AM 采用轮询的方式向 RM 申请和领取资源。
    5. RM 为 AM 分配资源,以 Container 形式返回。
    6. AM 申请到资源后,便与之对应的 NM 通讯,要求 NM 启动任务。
    7. NodeManager 为任务设置好运行环境,将任务启动命令写到一个脚本中,并通过运行这个脚本启动任务。
    8. 各个任务向 AM 汇报自己的状态和进度,以便当任务失败时可以重启任务。
    9. 应用程序完成后,ApplicationMaster 向 ResourceManager 注销并关闭自己。

22. yarn 的资源调度三种模型 ❤

  • 在 Yarn 中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,Fair Scheduler。Apache 版本的 hadoop 默认使用的是 Capacity Scheduler 调度方式。CDH 版本的默认使用的是 Fair Scheduler 调度方式。
  • FIFO Scheduler(先来先服务):
    • FIFO Scheduler 把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。
    • FIFO Scheduler 是最简单也是最容易理解的调度器,也不需要任何配置,但它并不适用于共享集群。大的应用可能会占用所有集群资源,这就导致其它应用被阻塞,比如有个大任务在执行,占用了全部的资源,再提交一个小任务,则此小任务会一直被阻塞。
  • Capacity Scheduler(能力调度器):
    • 对于 Capacity 调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用 FIFO 调度器时的时间。
  • Fair Scheduler(公平调度器):
    • 在 Fair 调度器中,我们不需要预先占用一定的系统资源,Fair 调度器会为所有运行的 job 动态的调整系统资源。
      比如:当第一个大 job 提交时,只有这一个 job 在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair 调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
    • 需要注意的是,在 Fair 调度器中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的 Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终的效果就是 Fair 调度器即得到了高的资源利用率又能保证小任务及时完成。

(二)Hive

1. hive的工作原理 ❤

2. hive 内部表和外部表的区别 ❤

  • 修饰词: 内部表未被external修饰;外部表被external修饰。
  • 数据管理: 内部表数据由Hive自身管理,Hive完全管理数据的生命周期,删除内部表时会直接删除元数据及存储数据;外部表数据由HDFS管理,Hive只管理表结构,不管理数据,删除外部表时仅会删除元数据,HDFS上的数据并不会被删除;
  • 数据存储位置: 内部表数据存储在Hive的数据仓库中hive.metastore.warehouse.dir(默认:/user/hive/warehouse);外部表数据存储在HDFS中,具体位置由自己指定
  • 数据共享: 内部表数据存储在Hive的数据仓库中,因此不能与外部应用程序共享数据,而外部表数据存储在HDFS中,因此可以被外部应用程序读取。
  • 在Hive中,内部表适用于临时存储数据,外部表适用于永久存储数据,并与外部应用程序共享数据。

3. hive 有索引吗?

4. 运维如何对hive进行调度?

5. 文件存储格式

6. 文件压缩算法

7. ORC、Parquet等列式存储的优点

8. Hive解析JSON串

9. sort by 和 order by 的区别 ❤

  1. order by:用于对查询结果进行全局排序
    • 将所有数据收集到一个节点上进行排序,然后输出有序的结果。
    • 使用order by时,Hive会将整个数据集加载到内存中进行排序,因此适用于数据量较小的情况。然而,由于需要加载全部数据到内存,对于大规模数据集来说,可能导致内存不足的问题。
    • 使用场景:当需要对查询结果进行全局排序,并且数据量较小的情况下,可以使用order by。
  2. sort by:用于对查询结果按照指定的列进行局部排序
    • 将数据根据指定的列进行排序,但不保证全局有序。
    • Hive会将数据按照指定的列进行划分和排序,每个划分内的数据是有序的,但不同划分之间的顺序是未定义的。sort by可以配合使用分区(partition)来实现更细粒度的排序。
    • 使用场景:当需要按照指定的列对查询结果进行局部排序,而不要求全局有序时,可以使用sort by。
  3. distribute by:用于指定数据的分发方式
    • 用于控制将数据发送到不同的reducer节点上。
    • distribute by通常与sort by或cluster by一起使用,以控制数据的分区和排序。
    • 使用场景:当需要按照指定的列对数据进行分发,并且可能需要后续的排序操作时,可以使用distribute by。
  4. cluster by:用于对数据进行分区和排序
    • 类似于distribute by,但它会尝试将数据按照指定的列进行排序,并将相邻的值放置在相同的分区中。
    • cluster by会自动执行分区和排序的操作。
    • 使用场景:当需要将数据按照指定的列进行分区和排序,并且希望相邻值在同一分区中时,可以使用cluster by。
  • 总结:
    • order by适用于全局排序,但对内存的需求较高,适用于数据量较小的情况。
    • sort by适用于局部排序,可以与分区结合使用,适用于需要排序的局部数据集。
    • distribute by用于数据的分发,并且可以与sort by或cluster by一起使用,控制分区和排序。
    • cluster by用于数据的分区和排序,尝试将相邻值放在同一分区中。

10. 怎么排查是哪里出现了数据倾斜?

11. 数据倾斜怎么解决?❤

  1. 空值引发的数据倾斜

    • 当表中有大量的null值,如果表之间进行join操作,就会有shuffle产生,这样所有的null值都会被分配到一个reducer中,必然产生数据倾斜。
    • 解决方案:
      • (1)可以直接不让null值参与join操作,即不让null值有shuffle阶段;
      	select *
      	FROM log a
       	JOIN users b
       	ON a.user_id IS NOT NULL AND a.user_id = b.user_id
      	
      	UNION ALL
      	SELECT *
      	FROM log a
      	WHERE a.user_id IS NULL;
      
      • (2)因为null值参与shuffle时的hash结果是一样的,那么我们可以给null值随机赋值,这样它们的hash结果就不一样,就会进到不同的reducer中:
      	select *
      	FROM log a
      	LEFT JOIN users b ON CASE 
      		WHEN a.user_id IS NULL THEN concat('hive_', rand())
      		ELSE a.user_id END = b.user_id;
      
  2. 不同数据类型引发的数据倾斜

    • 对于两个表join,表a中需要join的字段key为int,表b中key字段既有string类型也有int类型。当按照key进行两个表的join操作时,默认的Hash操作会按int型的id来进行分配,这样所有的string类型都被分配成同一个id,结果就是所有的string类型的字段进入到一个reduce中,引发数据倾斜。
    • 解决方案:
      • 如果key字段既有string类型也有int类型,默认的hash就都会按int类型来分配,那我们直接把int类型都转为string就好了,这样key字段都为string,hash时就按照string类型分配了:
      	SELECT *
      	FROM users a
       	LEFT JOIN logs b ON a.usr_id = CAST(b.user_id AS string);
      
  3. 不可拆分大文件引发的数据倾斜

    • 当集群的数据量增长到一定规模,有些数据需要归档或者转储,这时候往往会对数据进行压缩;当对文件使用GZIP压缩等不支持文件分割操作的压缩方式,在日后有作业涉及读取压缩后的文件时,该压缩文件只会被一个任务所读取。如果该压缩文件很大,则处理该文件的Map需要花费的时间会远多于读取普通文件的Map时间,该Map任务会成为作业运行的瓶颈。这种情况也就是Map读取文件的数据倾斜
    • 解决方案:
      • 这种数据倾斜问题没有什么好的解决方案,只能将使用GZIP压缩等不支持文件分割的文件转为bzip和zip等支持文件分割的压缩方式。
      • 所以,我们在对文件进行压缩时,为避免因不可拆分大文件而引发数据读取的倾斜,在数据压缩的时候可以采用bzip2和Zip等支持文件分割的压缩算法
  4. 数据膨胀引发的数据倾斜

    • 在多维聚合计算时,如果进行分组聚合的字段过多,如下:
      select a,b,c,count(1)from log group by a,b,c with rollup;

      with rollup是用来在分组统计数据的基础上再进行统计汇总,即用来得到group by的汇总信息。

    • 如果上面的log表的数据量很大,并且Map端的聚合不能很好地起到数据压缩的情况下,会导致Map端产出的数据急速膨胀,这种情况容易导致作业内存溢出的异常。如果log表含有数据倾斜key,会加剧Shuffle过程的数据倾斜。

    • 解决方案:

      • 可以拆分上面的sql,将with rollup拆分成如下几个sql:
      	SELECT a, b, c, COUNT(1)
      	FROM log
      	GROUP BY a, b, c;
      	
      	SELECT a, b, NULL, COUNT(1)
      	FROM log
      	GROUP BY a, b;
      	
      	SELECT a, NULL, NULL, COUNT(1)
      	FROM log
      	GROUP BY a;
      	
      	SELECT NULL, NULL, NULL, COUNT(1)
      	FROM log;
      
      • 在Hive中可以通过参数 hive.new.job.grouping.set.cardinality 配置的方式自动控制作业的拆解,该参数默认值是30。表示针对grouping sets/rollups/cubes这类多维聚合的操作,如果最后拆解的键组合大于该值,会启用新的任务去处理大于该值之外的组合。如果在处理数据时,某个分组聚合的列有较大的倾斜,可以适当调小该值。
  5. 表连接时引发的数据倾斜

    • 两表进行普通的repartition join时,如果表连接的键存在倾斜,那么在 Shuffle 阶段必然会引起数据倾斜。
    • 解决方案:
      • 通常做法是将倾斜的数据存到分布式缓存中,分发到各个Map任务所在节点。在Map阶段完成join操作,即MapJoin,这避免了 Shuffle,从而避免了数据倾斜。

      MapJoin是Hive的一种优化操作,其适用于小表JOIN大表的场景,由于表的JOIN操作是在Map端且在内存进行的,所以其并不需要启动Reduce任务也就不需要经过shuffle阶段,从而能在一定程度上节省资源提高JOIN效率。

  6. 确实无法减少数据量引发的数据倾斜

    • 在一些操作中,我们没有办法减少数据量,如在使用 collect_list (将分组中的某列转为一个数组返回)函数时:collect_list输出一个数组,中间结果会放到内存中,所以如果collect_list聚合太多数据,会导致内存溢出。
    • 解决方案:
      • 这类问题最直接的方式就是调整reduce所执行的内存大小。调整reduce的内存大小使用mapreduce.reduce.memory.mb这个配置。

12. hive 小文件过多怎么解决 ❤

  • 小文件的影响:
    • 从HIVE角度来看的话呢,小文件越多,map的个数也会越多,每一个map都会开启一个JVM虚拟机,每个虚拟机都要创建任务,执行任务,这些流程都会造成大量的资源浪费,严重影响性能;
    • 在HDFS中,每个小文件约占150byte,如果小文件过多则会占用大量的内存。这样namenode内存容量严重制约了集群的发展。
  • 小文件的解决方案:
    • 从小文件的产生途径解决:
      1. 使用sequencefile作为表存储形式,不要使用textfile,在一定程度上可以减少小文件;
      2. 减少reduce的个数(减少生成分区数量);
      3. 少用动态分区,使用distribute by分区。
    • 对已经存在的小文件如何解决:
      1. 使用Hadoop archive把小文件进行归档
        set hive.archive.enabled=true;
        set hive.archive.har.parentdir.settable=true;
        set har.partfile.size=1099511627776;	
        alter table srcpart archive partition(ds='2008-04-08', hr='12');
        alter table srcpart unarchive partition(ds='2008-04-08', hr='12');
        
         如果使用的不是分区表,则可创建成外部表,并使用har://协议来指定路径。
        
      2. HDFS Federation
        Hadoop V2引入了HDFS Federation的概念,实则是将NameNode做了拆分,从而增强了它的扩展性,小文件的问题也能够得到缓解。
      3. 重建表,建表时减少reducer的数量
      4. 通过参数调节,设置map/reduce的数量,对于通常的应用,使用Hive结果合并就能达到很好的效果。
        设置map输入合并小文件的相关参数:
        
        //每个Map最大输入大小(这个值决定了合并后文件的数量)
        set mapred.max.split.size=256000000;
        //一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
        set mapred.min.split.size.per.node=100000000;
        //一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
        set mapred.min.split.size.per.rack=100000000;
        //执行Map前进行小文件合并
        set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
        
        设置map输出和reduce输出进行合并的相关参数:
        
        //设置map端输出进行合并,默认为true
        set hive.merge.mapfiles = true;
        //设置reduce端输出进行合并,默认为false
        set hive.merge.mapredfiles = true;
        //设置合并文件的大小
        set hive.merge.size.per.task = 256*1000*100;
        //当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
        set hive.merge.smallfiles.avgsize=16000000;
        

13. hive性能优化(列裁剪、谓词下推)❤

  • 当我们发现一条SQL语句执行时间过长或者不合理时,我们就要考虑对SQL进行优化,优化首先得进行问题排查
  • Hive对SQL语句性能问题排查的方式:
    1. 使用explain查看执行计划

      Hive提供的执行计划目前可以查看的信息有以下几种:
      1. 查看执行计划的基本信息,即explain
      2. 查看执行计划的扩展信息,即explain extended;
      3. 查看SQL数据输入依赖的信息,即explain dependency;
      4. 查看SQL操作相关权限的信息,即explain authorization;
      5. 查看SQL的向量化描述信息,即explain vectorization。

      • 在查询语句的SQL前面加上关键字explain是查看执行计划的基本方法
      • 用explain打开的执行计划包含以下两部分:
        • 作业的依赖关系图,即STAGE DEPENDENCIES;
        • 每个作业的详细信息,即STAGE PLANS。
    2. 查看YARN提供的日志

  • Hive性能调优的方式
    1. SQL语句优化

      • union all
      • distinct
    2. 数据格式优化

    3. 小文件过多优化

    4. 并行执行优化

    5. JVM优化

    6. 预测执行优化

14. hive on spark 和 hive on hadoop 的执行顺序有什么不一样?❤

15. hive SQL底层怎么执行?

16. hive怎么把HQL编译成MapReduce?❤

Alt

  1. 在编译器中,用Antlr语言识别工具对HQL的输入进行词法和语法解析,将HQL语句转换成**抽象语法树(AST Tree)**的形式;
  2. 遍历抽象语法树,转化成QueryBlock查询块。因为AST结构复杂,不方便直接翻译成MR算法程序。其中QueryBlock是一条最基本的SQL语法组成单元,包括输入源、计算过程、和输入三个部分;
  3. 遍历QueryBlock,生成OperatorTree(操作树),OperatorTree由很多逻辑操作符组成,如TableScanOperator、SelectOperator、FilterOperator、JoinOperator、GroupByOperator和ReduceSinkOperator等。这些逻辑操作符可在Map、Reduce阶段完成某一特定操作;
  4. Hive驱动模块中的逻辑优化器对OperatorTree进行优化,变换OperatorTree的形式,合并多余的操作符,减少MR任务数、以及Shuffle阶段的数据量;
  5. 遍历优化后的OperatorTree,根据OperatorTree中的逻辑操作符生成需要执行的MR任务;
  6. 启动Hive驱动模块中的物理优化器,对生成的MR任务进行优化,生成最终的MR任务执行计划;
  7. 最后,由Hive驱动模块中的执行器,对最终的MR任务执行输出。
  • Hive驱动模块中的执行器执行最终的MR任务时,Hive本身不会生成MR算法程序。它通过一个表示“Job执行计划”的XML文件,来驱动内置的、原生的Mapper和Reducer模块。
  • Hive通过和JobTracker通信来初始化MR任务,而不需直接部署在JobTracker所在管理节点上执行
  • 通常在大型集群中,会有专门的网关机来部署Hive工具,这些网关机的作用主要是远程操作和管理节点上的JobTracker通信来执行任务
  • Hive要处理的数据文件常存储在HDFS上,HDFS由名称节点(NameNode)来管理。

(三)Spark

1. 为什么Spark比MapReduce运行效率高?❤

  1. DAG相比Hadoop的MapReduce在大多数情况下可以减少磁盘IO次数。
    • MapReduce计算模型只能包含一个map和一个reduce,所以reduce完后必须进行落盘,而DAG可以连续shuffle,也就是说一个DAG可以完成好几个MapReduce,所以DAG只需要在最后一个reduce落盘,比MapReduce少,总shuffle次数越多,减少的落盘次数越多。
  2. Spark shuffle的优化。
    • MapReduce在shuffle时默认进行排序,而Spark在shuffle时只有部分场景才需要排序(bypass机制不需要排序)。排序时非常耗时的,这样就可以加快shuffle速度。
  3. Spark支持将需要反复用到的数据进行缓存。
    • 对于下次再次使用此RDD时,不用再次计算,而是直接从缓存中获取,可以减少数据加载耗时。因此更适合需要迭代计算的机器学习算法。
  4. 任务级别并行度上的不同。
    • MapReduce采用了多进程模型,而Spark采用了多线程模式。
    • 多进程模型的好处是便于细粒度控制每个任务占用的资源,但每次任务的启动都会消耗一定的启动时间,即MapReduce的Map Task和Reduce Task是进程级别的,都是JVM进程,每次启动都需要重新申请资源,消耗了不必要的时间。
    • 而Spark Task则是基于线程模型的,通过复用线程池中的线程来减少启动,关闭task所需要的开销。(多线程模型也有缺点:由于同节点上所有任务运行在一个进程中,因此,会出现严重的资源争用,难以细粒度控制每个任务的占用资源)

2. MR和Spark的shuffle有什么不同?为什么?❤

  • 相同点
    都是将 mapper(Spark 里是 ShuffleMapTask)的输出进行 partition,不同的 partition 送到不同的 reducer(Spark 里 reducer 可能是下一个stage 里的 ShuffleMapTask,也可能是 ResultTask)
  • 不同点:
    • MapReduce 默认是排序的,spark 默认不排序,除非使用 sortByKey 算子。
    • MapReduce 可以划分成 split,map()、spill、merge、shuffle、sort、reduce()等阶段,spark 没有明显的阶段划分,只有不同的 stage 和算子操作。
    • MapReduce落盘,Spark 不落盘,spark 可以解决MapReduce落盘导致效率低下的问题。
  1. Hadoop和Spark的使用场景
  2. Spark如何保证宕机迅速恢复?
  3. Hadoop和Spark的异同点
  4. Spark和MR的异同点

7. RDD持久化原理?

8. checkpoint检查点机制?

9. checkpoint和持久化机制的区别?

10. RDD机制理解吗?

  1. Spark streaming以及基本工作原理?
  2. DStream以及基本工作原理?

13. Spark的运行流程 ❤

Spark运行流程图

  1. Driver启动,创建一个SparkContext对象
  2. SparkContext 向资源管理器(Cluster Manager)注册并申请资源
  3. 资源管理器分配资源( Executor),WorkerNode启动 Executor
  4. Executor 向SparkContext注册并申请Task
  5. SparkContext 构建 DAG 有向无环图
  6. DAGScheduler将 DAG 划分成 Stage(TaskSet),然后把 Stage 发送给 TaskScheduler
  7. TaskScheduler 将 Task 提交给 Executor
  8. 同时 SparkContext 将应用程序代码发放给 Executor
  9. Task 在 Executor 上运行,运行完毕后注销,释放所有资源

14. spark有哪些节点?❤

  1. Master:管理集群和节点,不参与计算。
  2. Worker:计算节点,进程本身不参与计算,和 master 汇报。
  3. Driver:运行程序的 main 方法,创建 spark context 对象。(SparkContext:控制整个 application 的生命周期,包括DAGScheduler 和 TaskScheduler 等组件。)
  4. Client:用户提交程序的入口。

15. spark工作机制?❤

16. 宽依赖和窄依赖 ❤

  • 窄依赖:父 RDD 的一个分区只会被子 RDD 的一个分区依赖;
  • 宽依赖:父 RDD 的一个分区会被子 RDD 的多个分区依赖(涉及到 shuffle)
  • 为什么要设计宽窄依赖:
    • 对于窄依赖:窄依赖的多个分区可以并行计算;窄依赖一个分区的数据如果丢失,只需要重新计算对应分区的数据就可以了(容错)
    • 对于宽依赖:划分stage的依据,必须等到上一阶段的计算完成才能计算下一阶段。
  1. Spark主备切换机制原理知道吗?
  2. spark解决了hadoop的哪些问题?

19. 数据倾斜的产生和解决办法?❤

  • 数据倾斜以为着某一个或者某几个 partition 的数据特别大,导致这几个partition 上的计算需要耗费相当长的时间。
  • 在 spark 中同一个应用程序划分成多个 stage,这些 stage 之间是串行执行的,而一个 stage 里面的多个 task 是可以并行执行,task 数目由 partition 数目决定,如果一个 partition 的数目特别大,那么导致这个 task 执行时间很长,导致接下来的 stage 无法执行,从而导致整个 job 执行变慢。
  • 避免数据倾斜,一般是要选用合适的 key,或者自己定义相关的 partitioner,通过加盐或者哈希值来拆分这些 key,从而将这些数据分散到不同的 partition 去执行。
  • 如下算子会导致 shuffle 操作,是导致数据倾斜可能发生的关键点所在:groupByKey;reduceByKey;aggregaByKey;join;cogroup;
  1. 前提是定位数据倾斜,是 OOM 了,还是任务执行缓慢,看日志,看 WebUI
  2. 解决方法,有多个方面:
    • 避免不必要的 shuffle,如使用广播小表的方式,将 reduce-side-join 提升为 map-side-join
    • 分拆发生数据倾斜的记录,分成几个部分进行,然后合并 join 后的结果
    • 改变并行度,可能并行度太少了,导致个别 task 数据压力大
    • 两阶段聚合,先局部聚合,再全局聚合
    • 自定义 paritioner,分散 key 的分布,使其更加均匀

20. Spark的部署、调度原理

21. Spark的stage是怎么划分的?❤

  • 对于窄依赖,partition 的转换处理在 stage 中完成计算,不划分(将窄依赖尽量放在同一个 stage 中,可以实现流水线计算)。
  • 对于宽依赖,由于有 shuffle 的存在,只能在父 RDD 处理完成后,才能开始接下来的计算,也就是说需要划分 stage。
  • 核心算法:回溯算法
    • 从后往前回溯/反向解析,遇到窄依赖加入本 Stage,遇见宽依赖进行 Stage 切分。
    • Spark 内核会从触发 Action 操作的那个 RDD 开始从后往前推,首先会为最后一个 RDD 创建一个 Stage,然后继续倒推,如果发现对某个 RDD 是宽依赖,那么就会将宽依赖的那个 RDD 创建一个新的 Stage,那个 RDD 就是新的Stage 的最后一个 RDD。
    • 然后依次类推,继续倒推,根据窄依赖或者宽依赖进行 Stage 的划分,直到所有的 RDD 全部遍历完成为止。
  1. reduce join如何执行?
  2. 大数据量如何优化join?
  3. RDD中reduceBykey与groupByKey哪个性能好,为什么?
  4. Spark master HA主从切换过程不会影响到集群已有作业的运行,为什么?
  5. Spark master使用zookeeper进行HA,有哪些源数据保存到Zookeeper里面?

27. 哪些算子需要shuffle?

  1. Hadoop和Spark内存管理
  2. Spark物理优化做了什么?
  3. Spark SQL的执行原理,从anltr4到catalyst里面的逻辑优化,一直到物理计划的生成

(四)Kafka

  1. 为什么要使用 kafka?
  2. Kafka消费过的消息如何再消费?
  3. kafka的数据是放在磁盘上还是内存上,为什么速度会快?
  4. Kafka数据怎么保障不丢失?
  5. 采集数据为什么选择kafka?
  6. kafka 重启是否会导致数据丢失?
  7. kafka 宕机了如何解决?
  8. 为什么Kafka不支持读写分离?
  9. kafka数据分区和消费者的关系?
  10. kafka的数据offset读取流程
  11. kafka内部如何保证顺序,结合外部组件如何保证消费者的顺序?
  12. Kafka消息数据积压,Kafka消费能力不足怎么处理?
  13. Kafka单条日志传输大小
  14. kafka怎么保证数据一致性?

(五)Hbase

  1. Hbase是怎么写数据的?
  2. HDFS和HBase各自使用场景
  3. Hbase的存储结构
  4. 热点现象(数据倾斜)怎么产生的,解决方法有哪些?
  5. HBase的 rowkey 设计原则
  6. HBase的列簇设计
  7. HBase 中 compact 用途是什么,什么时候触发,分为哪两种,有什么区别?
  8. Hbase和Redis的应用场景有什么不同?为什么?

(六)Flink

  1. Flink 的容错机制(checkpoint)
  2. Flink checkpoint与 Spark Flink 有什么区别或优势吗?
  3. Flink 中的 Time 有哪几种?
  4. 对于迟到数据是怎么处理的?
  5. Flink 的运行必须依赖 Hadoop组件吗?
  6. Flink集群有哪些角色?各自有什么作用?
  7. Flink 资源管理中 Task Slot 的概念
  8. Flink的重启策略
  9. Flink是如何保证Exactly-once语义的?
  10. 如果下级存储不支持事务,Flink 怎么保证 exactly-once?
  11. Flink是如何处理反压的?
  12. Flink中的状态存储
  13. Flink是如何支持批流一体的?
  14. Flink的内存管理是如何做的?
  15. Flink CEP 编程中当状态没有到达的时候会将数据保存在哪里?
  16. Flink的水印机制

二、数据库&数据仓库

1. MySQL为什么使用B+树,而不是B树?❤

2. MySQL如何进行优化?

3. 数据库有哪些引擎?解释一下InnoDB?

  • 存储引擎: 存储数据、建立索引、更新/查询数据等技术的实现方式;存储引擎是基于表的,而不是基于库的(表类型)。
  • 类型: InnoDB | MyISAM | Memory
  • InnoDB: 是MySQL的默认存储引擎,支持事务、外键。
    • 【适用场景】事务完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操作。
    • DML操作遵循ACID模型,支持事务
    • 行级锁,提高并发访问性能;
    • 支持外键 FOREIGN KEY约束,保证数据的完整性和正确性。
  • MyISAM: 是MySQL早期的默认存储引擎,不支持事务和外键。
    • 【适用场景】读和插入操作为主,只有很少的更新和删除操作,对事务的完整性、并发性要求不高
    • 不支持事务,不支持外键
    • 支持表锁,不支持行锁;
    • 访问速度快。
  • Memory: 将所有数据保存在内存中,访问速度很快,通常用于临时表及缓存
    • 对表的大小有限制,太大的表无法缓存在内存中;
    • 无法保障数据的安全性(受硬件问题或断电问题的影响)
    • 支持表锁和hash索引

4. 常用的关系型数据库和非关系型数据库

  • 关系型数据库: MySQL、Oracle、SQLServer、
  • 非关系型数据库:

5. 数据仓库的分层架构

  • 数据仓库是面向主题的、集成的、非易失的和时变的数据集合,用以支持管理决策。数据库是面向事务的设计,数据仓库是面向主题设计的。数据库一般存储业务数据,数据仓库存储的一般是历史数据。
  • 源数据 -> 数据仓库 -> 数据应用
  • ETL(抽取Extra、转化Transfer、装载Load)

6. 为什么要对数据仓库分层?❤

  • 用空间换时间,通过大量的预处理来提升应用系统的用户体验(效率),因此数据仓库会存在大量冗余的数据;不分层的话,如果源业务系统的业务规则发生变化将会影响整个数据清洗过程,工作量巨大。
  • 通过数据分层管理可以简化数据清洗的过程,因为把原来一步的工作分到了多个步骤去完成,相当于把一个复杂的工作拆成了多个简单的工作,把一个大的黑盒变成了一个白盒,每一层的处理逻辑都相对简单和容易理解,这样我们比较容易保证每一个步骤的正确性,当数据发生错误的时候,往往我们只需要局部调整某个步骤即可。

7. 数仓建模的方法 ❤

  • 范式建模法
  • 实体建模法
  • 维度建模法
    • 事实表:表示对分析主题的度量。比如一次购买行为我们就可以理解为是一个事实。

    • 维度表:

    • 星型模型

    • 雪花模型

8. 数据库三范式,举例说明 ❤

  1. 第一范式(1NF):
  2. 第二范式(2NF):
  3. 第三范式(3NF):

9. 什么是索引,有哪些索引?

10. 索引的优缺点

11. B树和B+树的优缺点 ❤

12. MySQL索引失效的原因 ❤

  1. 数据类型不匹配,索引列发生了隐式类型转换
    • 解决方法:保持数据类型的一致性;或在查询条件中使用显式类型转换。
  2. 模糊查询,使用like左模糊匹配,以%开头
    • 以%开头的模糊匹配无法确定索引列的起始位置,所以无法利用索引进行快速查找。
    • 解决方法:避免使用以%开头的模糊匹配;或使用覆盖索引(只包含索引列的查询)。
  3. 索引列使用了函数或运算
    • 使用函数或运算会改变索引的值,使得原来的索引无法使用。
    • 解决方法:避免对索引列使用函数或运算;或建立基于函数或运算的索引。
  4. 索引列包含空值(NULL),查询条件中使用is not null
    • MySQL在建立索引时不会存储空值,所以无法通过索引来判断是否为空。
    • 解决方法:避免让索引列包含空值;或建立索引时指定NOT NULL约束。
  5. 查询条件中使用了OR关键字,并且OR两边的条件涉及到不同的索引列或非索引列
    • MySQL无法同时使用多个索引进行查询优化,所以只能选择全表扫描。
    • 解决方法:避免使用OR关键字;或将OR两边的条件分别用括号括起来,并在括号内部使用相同的索引列。
  6. 违反了联合索引的最左前缀匹配原则
    • 最左前缀匹配原则:MySQL 建立联合索引时,首先根据联合索引中最左边的、也就是第一个字段进行排序,在第一个字段排序的基础上,再对联合索引中后面的第二个字段进行排序,依此类推。检索数据时从联合索引的最左边开始匹配。
    • 解决方法:按照最左前缀匹配原则使用联合索引,并且将区分度高的列放在前面。
  7. 全表扫描比使用索引更快
    • MySQL的优化器会根据表中的数据量和分布情况,预估使用索引和全表扫描的代价,选择一个更快的方案。
    • 例如:表中数据量很小,或查询条件中过滤条件很宽松,导致命中的记录很多,那么全表扫描可能比使用索引更快。
    • 解决方法:根据实际情况调整查询条件或索引设计;或强制使用索引(FORCE INDEX或USE INDEX)

13. 索引的底层结构

14. SQL查询语言分类

15. 事务的定义 ❤

事务: 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失效

16. 事务的四大特性(ACID)❤
  • 原子性Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败;
  • 一致性Consistency):事务完成时,必须使所有的数据保持一致状态;
  • 隔离性Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行;
  • 持久性Durability):事务一旦提交或回滚,它对数据库中数据的改变就是永久的。

17. 并发事务问题 ❤

  • 并发事务问题: 多个并发事务在执行过程中出现的问题
    • 脏读: 一个事务读到另外一个事务还没有提交的数据;
    • 不可重复读: 一个事务重复读取同一条记录两次,但得到的数据不同;【update】
    • 幻读: 一个事务执行两次查询,第二次查询的结果中出现了第一次查询时未出现的数据。【insert】

18. 事务隔离级别 ❤

√:可避免 | ×:不可避免

事务隔离级别脏读不可重复读幻读
Read uncommitted(读未提交)×××
Read committed(读已提交)××
Repeatable Read(可重复读)【MySQL默认】×
Serializable(串行化)

#19. MVCC的作用及实现原理

  1. drop、truncate、delete的区别
  2. 数据库的锁机制
  3. 乐观锁和悲观锁
  4. 死锁
  5. 数据库MySQL编码方式区别
  6. uuid和主键id区别

26. 谓词下推 ❤

27. 执行计划 ❤

三、数据结构&算法&机器学习

  1. 判断链表是否是循环链表(判断是否有环)
  2. 排序算法及时间空间复杂度
  3. 介绍一下逻辑回归
  4. 逻辑回归中sigmoid函数的作用
  5. 逻辑回归的损失函数
  6. 广义线性模型和其他模型的区别
  7. 分类模型的评估方式
  8. 拟合模型的评估方式
  9. 朴素贝叶斯的假设是什么?
  10. 斐波那契数列
  11. 爬楼梯
  12. 字符串中第一个只出现一次的字符,返回其位置,如何优化?(哈希)
  13. 数组和链表的区别是什么,以及各种的使用场景
  14. 队列和栈的区别
  15. 堆和栈的主要区别
  16. 树的遍历方式
  17. 快速排序的过程
  18. 二叉树的深度
  19. 最长公共子序列
  20. 判断二叉树是否对称
  21. 滑动窗口最大值
  22. 最小栈
  23. 删除链表的倒数第n个节点
  24. 数组中的逆序对
  25. 树的镜像

四、计算机网络&计算机基础

  1. 网络协议有哪些?

2. http是什么?❤

  • HTTP全称为Hyper Text Transfer Protocol,被译为超文本传输协议,是互联网上应用最为广泛的—种网络协议。被用于在web浏览器和网站服务器之间传递信息。
  • **HTTP协议是在Web上进行数据交换的基础,是一种“客户端-服务器端”协议。**也就是说,请求通常是由像浏览器这样的接受方发起的。
  • 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。

3. TCP/IP五层协议 ❤

  • 应用层:http、https、ftp、smtp等协议;
  • 传输层:为应用程序提供端到端的可靠数据传输,常见协议有TCP和UDP;
  • 网络层:负责将数据包从一个网络传输到另一个网络,使用IP地址进行寻址和路由选择;
  • 数据链路层:负责通过MAC地址寻址以及数据帧的传输;ARP协议
  • 物理层:定义电缆、光纤等物理设备的连接方式和传输速率等基本特性。

4. http属于哪一层?TCP属于哪一层?❤

  • http属于应用层协议,通常运行在TCP之上
  • TCP是传输层协议
  1. post和get请求的区别

6. TCP三次握手&四次挥手 ❤

7. TCP和UDP的区别 ❤

8. http和https的区别 ❤

  • HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。
  • 简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
  • HTTPS和HTTP的区别主要如下:
    1. https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
    2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协
    3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
    4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
  1. 访问一个网址会经过哪些步骤?
  2. 访问一个http接口很慢,如何排查可能出现问题的地方?

11. Linux操作系统常见命令 ❤

  • vim
  1. 操作系统如何解决内存碎片的
  2. 单核CPU同一时刻能处理多少个进程?
  3. 多线程和多进程的优缺点
  4. arp协议

五、SQL题

  1. rank、dense rank、row number的区别
  2. 为什么group by去重比distinct效率高?
  3. 最大连续天数
  4. join、inner join、left join、right join、outer join
  5. union和union all的区别

六、Python

  1. 逆序对取模
  2. 合并有序数组

七、Java

  1. hashmap是线程安全的吗?
  • 不是,hashmap是非线程安全的,不适用于多线程资源共享场景,在单线程场景下性能最好

2. 重载(overload)和重写 (overwrite)❤

  • 定义不同:重载是定义相同的方法名,参数不同;重写是子类重写父类的方法;
  • 范围不同:重载是在一个类中,重写是子类与父类之间的;
  • 多态不同:重载是编译时的多态性,重写是运行时的多态性;
  • 返回不同:重载对返回类型没有要求,重写要求返回类型,有兼容的返回类型;
  • 参数不同:重载的参数个数、参数类型、参数顺序可以不同,重写父子方法的参数必须相同;
  • 修饰不同:重载对访问修饰没有特殊要求,重写访问修饰符的限制一定要大于被重写方法的访问修饰符

3. 进程与线程 ❤

  • 进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
  • 线程:是进程的一个执行单元,是CPU调度和分派的基本单位。比进程更小的能独立运行的基本单位。线程也被称为轻量级进程。
  • 协程:是一种比线程更加轻量级的存在。一个线程也可以拥有多个协程。其执行过程更类似于子例程,或者说不带返回值的函数调用。
  • 进程与线程的区别
    • 本质区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
    • 包含关系:一个进程至少有一个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
    • 资源开销:每个进程都有独立的地址空间,进程之间的切换会有较大的开销;线程可以看做轻量级的进程,同一个进程内的线程共享进程的地址空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。
    • 影响关系:一个进程崩溃后,在保护模式下其他进程不会被影响,但是一个线程崩溃可能导致整个进程被操作系统杀掉,所以多进程要比多线程健壮。
  • 对资源的管理和保护要求高,不限制开销和效率时,使用多进程;要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
  1. 多线程代码实现
  2. 单例代码实现
  3. LinkedBlockingQueue原理
  4. 模板设计模式
  5. 观察者模式
  6. 单例模式
  7. 如何设计一个 生产者-消费者 队列
  8. 堆内存和栈内存
  9. ThreadLocal底层
  10. synchronized的原理,缺点是什么,如何解决?
  11. volatile的使用场景和原理,与synchronized的区别

15. Java内存模型

16. JVM内存模型 ❤

17. hashmap、hashtable、concurrenthashmap原理 ❤

  1. 如何提高hashtable、hashmap的性能?
  2. hashmap的扩容机制
  3. redis的缓存问题
  4. 布隆过滤器

22. 多线程的实现方式和区别 ❤

  1. 继承Thread类
    • 优点:简单,且只需要实现父类的run方法即可(start方法中含有run方法,会创建一个新的线程,而run是执行当前线程)
    • 缺点:Java的单继承,如果对象已经继承了其他的类则不能使用该方法。且不能获取线程的返回值
  2. 实现Runnable接口
    • 优点:简单,实现Runnable接口必须实现run方法
    • 缺点:创建一个线程就必须创建一个Runnable的实现类,且不能获取线程的返回值
  3. 使用Callable和FutureTask实现有返回值的多线程
    • 优点:可以获取多线程的返回值
    • 缺点:每个多线程都需要创建一个Callable的实现类
  4. 线程池:使用ExecutorService和Executors工具类实现线程池(如果需要线程的返回值,需要在线程中实现Callable和Future接口)
    • 优点:可以根据实际情况创建线程数量,且只需要创建一个线程池即可,也能够通过Callable和Future接口得到线程的返回值,程序的执行时间与线程的数量紧密相关。
    • 缺点:需要手动销毁该线程池(调用shutdown方法)。
  • 尽量不要使用 继承Thread类 和 实现Runnable接口;尽量使用线程池。否则项目导出都是线程。

23. 线程池的作用及如何实现 ❤

  • 线程池是一种池化的技术,类似的还有数据库连接池、HTTP 连接池等等。
  • 池化的思想主要是为了减少每次获取和结束资源的消耗,提高对资源的利用率。
  • 线程池的好处
    1. 降低资源消耗:通过重复利用现有的线程来执行任务,避免多次创建和销毁线程。
    2. 提高响应速度:因为省去了创建线程这个步骤,所以在拿到任务时,可以立刻开始执行。
    3. 提供附加功能:线程池的可拓展性使得我们可以自己加入新的功能,比如说定时、延时来执行某些线程。
  • 线程池的实现
    • ThreadPoolExecutor
    • ScheduledThreadPoolExecutor
    • ForkJoinPool
  1. Java虚拟机的内存管理
  2. ArrayList和LinkedList
  3. final、finalize和finally
  4. 事务的实现方式

28. Java垃圾回收机制 ❤

  • 垃圾回收是指在程序运行过程中,自动回收不再使用的内存空间,以便程序能够更有效地使用内存。
  • Java的垃圾回收机制是一种自动化的内存管理技术,它可以自动回收不再使用的内存空间,从而避免了程序员手动管理内存的繁琐工作。Java的垃圾回收机制是基于垃圾回收算法垃圾回收器实现的。
  • 垃圾回收算法是指在垃圾回收过程中,如何判断哪些内存空间是垃圾,哪些是可用的。Java的垃圾回收算法主要有两种:标记-清除算法和复制算法。
    • 标记-清除算法(最基本的垃圾回收算法)
      • 基本思想:在垃圾回收过程中,首先标记所有可达对象,然后清除所有未标记的对象。
      • 可达对象是指程序中仍然被引用的对象,未标记的对象是指程序中不再被引用的对象。
      • 优点:可以回收任意大小的内存空间。
      • 缺点:会产生内存碎片,导致内存利用率降低。
    • 复制算法(更高效的垃圾回收算法)
      • 基本思想:将内存空间分为两个区域,一部分是正在使用的内存空间,另一部分是空闲的内存空间。在垃圾回收过程中,将正在使用的内存空间中的可达对象复制到空闲的内存空间中,然后清除正在使用的内存空间中的未复制对象。
      • 优点:可以避免内存碎片。
      • 缺点:需要额外的空间来存储复制对象。
  • 垃圾回收器是Java虚拟机中的一个组件,它负责执行垃圾回收算法。Java的垃圾回收器主要有两种:串行垃圾回收器和并行垃圾回收器。
    • 串行垃圾回收器单线程的垃圾回收器)
      • 基本思想:在垃圾回收过程中,暂停程序的执行,然后执行垃圾回收算法。
      • 优点:简单、稳定。
      • 缺点:效率低下,不能充分利用多核处理器的优势。
    • 并行垃圾回收器多线程的垃圾回收器)
      • 基本思想:在垃圾回收过程中,利用多个线程并行执行垃圾回收算法。
      • 优点:效率高,可以充分利用多核处理器的优势
      • 缺点:实现复杂,容易出现线程安全问题。
  1. docker和虚拟机的区别,以及虚拟化层次区别
  2. Java异常分类
  3. Java并发

32. 深拷贝和浅拷贝 ❤

  • 深拷贝:深拷贝是指拷贝对象的具体内容,内存地址是自主分配的,拷贝结束之后俩个对象虽然存的值是一样的,但是内存地址不一样,俩个对象页互相不影响,互不干涉。
  • 浅拷贝:浅拷贝对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。
    - 注意:当内存销毁的时候,指向对象的指针,必须重新定义,才能够使用。

33. 线程之间是如何通信的?❤

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只喵喵豚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值