字节最全数开面试题|有同学拿了字节提前批offer

推荐阅读文章列表:大数据开发面试笔记V4.0 || 面试聊数仓第一 || 小白大数据学习路线

全文1.5w字,题目比较多,请耐心阅读!!!

一、前言

原文链接:https://www.nowcoder.com/share/jump/1689088775835

之前发过一篇字节跳动面经汇总的帖子,但是当时答案并没有更新完全,最近在字节开了提前批后,我立马更新了所有的题目答案,发出来供大家面试参考!!!

赶紧投递!!!赶紧投递!!!赶紧投递!!!

二、面经汇总

Hadoop篇

1.介绍一下Hadoop hadoop是什么

Hadoop是一个由Apache基金会所开发的分布式系统基础架构,主要解决海量数据存储与计算的问题,主要包括HDFS、MapReduce和Yarn框架。

2.谷歌的三篇论文是否了解,三驾马车GFS,BigTable,MapReduce

了解(建议浅看一下)

3.hdfs源码你知道的话,讲讲元数据怎么管理的?

Namenode对元数据的管理采用了三种形式:

  1. 内存元数据:基于内存存储元数据,元数据比较完整
  2. fsimage文件:磁盘元数据镜像文件,在NameNode工作目录中,它不包含block所在的Datanode 信息
  3. edits文件:数据操作日志文件,用于衔接内存元数据和fsimage之间的操作日志,可通过日志运算出元数据

4.hdfs 你知道namenode的问题吗?怎么解决?应该就是联邦机制

为了能够水平扩展Namenode,HDFS2.X提供了Federation架构。Federation架构的HDFS集群可以定义多个Namenode/Namespace,这些Namenode之间相互独立,各自分工管理自己的命名空间。HDFS集群中的Datanode提供数据块的共享存储功能,每个Datanode都会向集群中所有的Namenode注册,且周期性地向所有的Namenode发送心跳和块汇报,然后执行Namenode通过响应发回的Namenode指令。

5.hdfs写数据流程

  • 首先客户端会向namenode进行请求,然后namenode会检查该文件是否已经存在,如果不存在,就会允许客户端上传文件;
  • 客户端再次向namenode请求第一个block上传到哪几个datanode节点上,假设namenode返回了三个datanode节点;
  • 那么客户端就会向datanode1请求上传数据,然后datanode1会继续调用datanode2,datanode2会继续调用datanode3,那么这个通信管道就建立起来了,紧接着dn3,dn2,dn1逐级应答客户端;
  • 然后客户端就会向datanode1上传第一个block,以packet为单位(默认64k),datanode1收到后就会传给datanode2,dn2传给dn3
  • 当第一个block传输完成之后,客户端再次请求namenode上传第二个block。【写的时候,是串行的写入 数据块】

6.namenode如果挂掉了怎么办 【HA配置】

  • 当namenode发生故障宕机时,secondary namenode会保存所有的元数据信息,在namenode重启的时候,secondary namenode会将元数据信息发送给namenode。

7.说一下mapredeuce

  • map阶段:首先通过把输入目录下的文件进行逻辑切片,默认大小等于block大小,并且每一个切片由一个maptask来处理,同时将切片中的数据解析成<key,value>的键值对,k表示偏移量,v表示一行内容;紧接着调用Mapper类中的map方法。将每一行内容进行处理,解析为<k,v>的键值对,在wordCount案例中,k表示单词,v表示数字1 ;
  • shuffle阶段map端shuffle:将map后的<k,v>写入环形缓冲区【默认100m】,一半写元数据信息(key的起始位置,value的起始位置,value的长度,partition号),一半写<k,v>数据,等到达80%的时候,就要进行spill溢写操作,溢写之前需要对key按照【分区算法默认是,分区号是根据key的hashcode对reduce task个数取模得到的。这时候有一个优化方法可选,combiner合并,就是预聚合的操作,将有相同Key 的Value 合并起来, 减少溢写到磁盘的数据量,只能用来累加、最大值使用,不能在求平均值的时候使用】;然后到文件中,并且进行(多个溢写文件);reduce端shuffle:reduce会同一分区的各个maptask的结果到内存中,如果放不下,就会溢写到磁盘上;然后对内存和磁盘上的数据进行(这样就可以满足将key相同的数据聚在一起); 【Merge有3种形式,分别是内存到内存,内存到磁盘,磁盘到磁盘。默认情况下第一种形式不启用,第二种Merge方式一直在运行(spill阶段)直到结束,然后启用第三种磁盘到磁盘的Merge方式生成最终的文件。】
  • reduce阶段:key相同的数据会调用一次reduce方法,每次调用产生一个键值对,最后将这些键值对写入到HDFS文件中。

8.哪个阶段最费时间,环形缓冲区的调优以及什么时候需要调

shuffle:排序和溢写磁盘 原则上说,缓冲区越大,磁盘 io 的次数越少,执行速度就越快

9.环形缓冲区了不了解?说一下他的那个阈值高低的影响

  • 环形缓冲区底层就是一个数组,默认大小是100M
  • 数组中存放着key和value的数据,以及关于key和value的元数据信息。每个key, value对应一个元数据,元数据由4个int组成,第一个int存放value的起始位置,第二个int存放key的起始位置,第三个int存放partition,第四个int存放value的长度。
  • key/value数据和元数据在环形缓冲区中的存储是由equator(赤道)分隔的,key/value按照索引递增的方向存储,元数据则按照索引递减的方向存储。将数组抽象为一个环形结构之后,以equator为界,key/value顺时针存储,元数据逆时针存储。

10.写一个wordcount

public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
    Text k = new Text();
    IntWritable v = new IntWritable(1);
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // 1 获取一行
        String line = value.toString();
        // 2 切割
        String[] words = line.split(" ");
        // 3 输出
        for (String word : words) {
            k.set(word);
            context.write(k, v);
        }
    }
}
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
    int sum;
    IntWritable v = new IntWritable();
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
        // 1 累加求和
        sum = 0;
        for (IntWritable count : values) {
            sum += count.get();
        }
        // 2 输出
           v.set(sum);
        context.write(key,v);
    }
}

11.WordCount在MapReduce中键值对变化

<偏移量, 一行数据> => <单词1, 1> <单词2, 1> .... => <单词1,10> <单词2,15>

12.map端为什么要排序?

是为了通过外排(外部排序)降低内存的使用量:因为reduce阶段需要分组,将key相同的放在一起进行规约,使用了两种算法:hashmap和sort,如果在reduce阶段sort排序(内部排序),太消耗内存,而map阶段的输出是要溢写到磁盘的,在磁盘中外排可以对任意数据量分组(只要磁盘够大),所以,map端排序(shuffle阶段),是为了减轻reduce端排序的压力。

13.map端输出的文件组织形式是什么样的?

多个溢写文件合并后的大文件

14.reduce怎么知道从哪里下载map输出的文件

通过MRAPPMaster获取哪些节点有map输出,当map执行结束后,会汇报给MRAPPMaster。reduce中的一个线程会定期询问MRAPPMaster以便获取map输出的位置

15.如果map输出太多小文件怎么办

开启combiner合并,但是在求平均值的时候是不能使用的

16.MapReduce优化的case

  • 输入端:合并小文件 combineinputformat
  • map端:提高环形缓冲区的大小,减少IO次数 开启combiner

zookeeper篇

1.zookeeper简单介绍一下,为什么要用zk?

Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目(文件系统+通知机制)

zk的应用场景:

  • 统一命名服务:在分布式环境下,经常需要对服务进行统一命名,便于识别,例如ip地址
  • 统一配置管理:在一个集群中,要求所有节点的配置信息是一致的
  • 统一集群管理:在一个集群中,需要实时监控每个节点的状态变化
  • 负载均衡:在zookeeper中记录每台服务器的访问数,再次请求的时候,让访问最少的服务器去处理当前请求

2.zk的数据存储,当重启后怎么重构zk的数据模型

zk中的数据是保存在节点上的,节点就是znode,多个znode之间构成一棵树的目录结构

zk的数据是运行在内存中,zk提供了两种持久化机制:

  • 事务日志:zk把执行的命令以日志形式保存在dataLogDir指定的路径中的文件中(如果没有指定dataLogDir,则按照 dataDir指定的路径)。
  • 数据快照:zk会在一定的时间间隔内做一次内存数据快照,把时刻的内存数据保存在快照文件中。

zk通过两种形式的持久化,在恢复时先恢复快照文件中的数据到内存中,再用日志文件中的数据做增量恢复,这样恢复的速度更快

3.zk的选举机制

  • zookeeper刚启动的时候投票过半数时,服务器id大的胜出
  • 我举个例子吧,假设有3台服务器,服务器1先启动,此时只有它一台服务器启动了,没有任何服务器可以进行通信,因此处于Looking状态,紧接着服务器2启动,它就会和1进行通信,交换选举结果,此时id较大的2胜出,并且满足半数以上的服务器同意选举2,所以2就成为了leader,最后服务器3启动,虽然自己的id大一些,但是前面已经选出了leader,因此自己就成为了follower

4.follower和observer的区别

  • follower与老大Leader保持心跳连接,当Leader挂了的时候,经过投票后成为新的leader

5.zk基于什么协议,zab和raft的区别

zookeeper基于zab协议

zab和raft主要有四点区别:

  • 一致性模型:ZAB协议和Raft协议都采用Leader-Follower模型,但ZAB协议只能保证强一致性,而Raft协议可以根据需要保证强一致性或弱一致性。
  • 选主过程:ZAB协议的选主过程中只有当前Leader节点参与,而Raft协议的选主过程中所有节点都参与,更容易实现节点间的负载均衡。
  • 日志复制机制:ZAB协议将每个节点的事务日志存储在Leader节点中,然后通过Leader节点进行复制,而Raft协议将每个节点的日志直接复制到其他节点,降低了中心化的压力。
  • 可扩展性:ZAB协议的可扩展性受限于Leader节点的性能,而Raft协议可以通过水平扩展来增加整个系统的容量和性能。
  • 6.zk怎么扩容,zk机房扩容有什么要注意的吗

    zookeeper集群的数量应为奇数:因为根据paxos理论,只有集群中超过半数的节点还存活才能保证集群的一致性。

    7.cap原则

    • C表示Consitency(一致性,也就是从每个节点读取的数据是一样的),A表示Avaliablity(可用性,也就是整个系统一直处于可用的状态),P表示Partition tolerance(分区容错性,分布式系统在 任何网络分区故障问题的时候,仍然能正常工作),对于一个分布式系统来说的话,最多只能满足其中的两项,并且满足P是必须的,所以往往选择就在CP或者AP中。而zookeeper就是满足了一致性和分区容错性因为leader节点挂掉的时候,集群会重新选举出leader,在这个期间集群是不满足可用性的

    Flume篇

    1.Flume都有什么组件,channel的特性以及什么时候该用什么类型的channel,除了Flume还有什么数据收集工具

    DataX,Sqoop

    Kafka篇

    1.Kafka在项目中起到的作用,如果挂掉怎么保证数据不丢失,不使用Kafka会怎样

    kafka提供了3种ack应答级别:ack=0,生产者发送过来的数据,不需要等数据落盘就会应答,一般不会使用;ack=1,生产者发送过来的数据,Leader收到数据后就会应答,因为这个级别也会丢失数据,所以一般用于传输普通日志;ack=-1(默认级别),生产者发送过来的数据,Leader和ISR队列里面的所有节点收到数据后才会应答,不会丢失数据,一般用于传输和钱相关的数据,那么为什么提出了这个ISR呢?因为如果我们等待所有的follower都同步完成,才发送ack,假设有一个follower迟迟不能同步,那怎么办呢?难道要一直等吗?因此就出现了ISR队列,这里面会存放和leader保持同步的follower集合,如果长时间(30s)未和leader通信或者同步数据,就会被踢出去。

    2.Kafka呢 怎么保证数据一致性 引申到exactly once

    分别从如何保证数据不丢失以及数据不重复两个方面来回答:

    数据不丢失:......

    数据不重复:0.11版本之后,kafka提出了一个非常重要的特性,幂等性(默认是开启的),也就是说无论producer发送多少次重复的数据,kafka只会持久化一条数据,把这个特性和至少一次语义(ack级别设置为-1+副本数>=2+ISR最小副本数>=2)结合在一起,就可以实现精确一次性(既不丢失又不重复)。我大致介绍一下它的底层原理:在producer刚启动的时候会分配一个PID,然后发送到同一个分区的消息都会携带一个SequenceNum(单调自增的),broker会对<PID,partition,SeqNum>做缓存,也就是把它当做主键,如果有相同主键的消息提交时,broker只会持久化一条数据。但是这个机制只能保证单会话的精准一次性,如果想要保证跨会话的精准一次性,那么就需要事务的机制来进行保证(producer在使用事务功能之前,必须先自定义一个唯一的事务id,这样,即使客户端重启,也能继续处理未完成的事务;并且这个事务的信息会持久化到一个特殊的主题当中)

    3.Kafka通过哪些机制实现了高吞吐量?

    • kafka本身是分布式集群,并且采用分区技术,并行度高
    • 读数据采用稀疏索引,可以快速定位要消费的数据
    • 写log文件的时候,一直是追加到文件末端,是顺序写的方式,官网中说了,同样的磁盘,顺序写能达到600M/s,而随机写只有100K/s
    • 实现了零拷贝技术,只用将磁盘文件的数据复制到页面缓冲区一次,然后将数据从页面缓冲区直接发送到网络中,这样就避免了在内核空间和用户空间之间的拷贝

    Hive篇

    1.如何理解Hive,为什么使用Hive

    hive就是一款构建数据仓库的工具,它可以将结构化的数据映射为一张表,并且可以通过SQL语句进行查询分析。本质上是将SQL转换为MapReduce或者spark来进行计算,数据是存储在hdfs上,简单理解来说hive就是MapReduce的一个客户端工具

    2.Hive的实现逻辑,为什么处理小表延迟比较高

    因为其计算是通过MapReduce,MapReduce是批处理,高延迟的。小文件也要执行MapReduce。Hive的优势在于处理大数据,对于处理小数据没有优势

    HBase篇

    1.Hbase的架构

    HBase主要包括region server和master,region server主要用于region的管理,而master主要用于管理region server,另外还有zookeeper和hdfs,zookeeper主要是用来保证master的高可用,hdfs提供存储服务。

    2.Hbase的读写流程

    写流程:

    • 客户端先访问zookeeper,获取元数据表hbase:meta在哪个region server中
    • 访问对应的region server,获取到元数据表,根据写的请求,确定数据应该写到哪个region server的哪个region中,然后将region信息和元数据表的信息缓存在客户端的meta cache中,以便下次访问
    • 与对应的region server进行通讯
    • 将数据先写入到WAL文件中,然后再写入memstore中,数据会在memstore中进行排序
    • 写入完成后,region server会向客户端发送ack
    • 等到达memstore的刷写时机(达到一个默认值大小或者达到刷写的时间),将数据刷写到HFile中

    读流程:

    • 客户端先访问zookeeper,获取元数据表hbase:meta在哪个region server中
    • 访问对应的region server,获取到元数据表,根据读的请求,确定数据位于哪个region server的哪个region中,然后将region信息和元数据表的信息缓存在客户端的meta cache中,以便下次访问
    • 与对应的region server进行通讯
    • 先在block cache(读缓存)中读,如果没有,然后去memstore和hfile中读取,将读到的数据返回给客户端并且写入block cache中,方便下一次读取

    3.blockcache的底层实现?你提到了LRU那除了LRU还可以有什么方案?

    三种实现方案:

    LRUBlockCache

    SlabCache

    BucketCache

    4.Hbase有哪几种写入方式,应用场景

    • 单条put:线上业务
    • 批量put:数据量较大
    • 使用Mapreduce:数据量非常大
    • bluckload:速度快

    Spark篇

    1.Spark有哪几种部署模式

    • 本地模式:常用于本地开发程序与测试
    • 集群模式:
    • standalone模式:只使用spark自身节点的运行模式
    • yarn模式:yarn作为资源调度框架的运行模式
    • mesos模式:Mesos与Yarn同样是一款资源调度管理系统,可以为Spark提供服务

    2.spark on yarn的工作流程

    • 首先spark的客户端将作业提交给yarn的RM,然后RM会分配container,并且选择合适的NM启动ApplicationMaster,然后AM启动Driver,紧接着向RM申请资源启动executor,Executor 进程启动后会向 Driver 反向注册,全部注册完成后 Driver 开始执行main 函数,当执行到行动算子,触发一个 Job,并根据宽依赖开始划分 stage(阶段的划分),每个 stage 生成对应的 TaskSet(任务的切分),之后将 task 分发到各个 Executor 上执行。

    3.怎样提高并行度 相关参数

    spark.defalut.parallelism

    4.client和cluster模式的区别

    • client模式下,driver运行在客户端;
    • cluster模式下,driver运行在yarn集群

    5.Spark shuffle的过程

    • spark的shuffle分为两种实现,分别为HashShuffle(spark1.2以前)和SortShuffle(spark1.2以后)
    • HashShuffle分为普通机制和合并机制,分为write阶段和read阶段,write阶段就是根据key进行分区,开始先将数据写入对应的buffer中,当buffer满了之后就会溢写到磁盘上,这个时候会产生mapper的数量*reduer的数量的小文件,这样就会产生大量的磁盘IO,read阶段就是 reduce去拉取各个maptask产生的同一个分区的数据;HashShuffle的合并机制就是让多个mapper共享buffer,这时候落盘的数量等于reducer的数量*core的个数,从而可以减少落盘的小文件数量,但是当Reducer有很多的时候,依然会产生大量的磁盘小文件。
    • SortShuffle分为普通机制和bypass机制
    • 普通机制:map task计算的结果数据会先写入一个(默认5M)中,每写一条数据之后,就会判断一下,是否达到了阈值,如果达到阈值的话,会先尝试增加内存到当前内存的2倍,如果申请不到才会溢写,溢写的时候先按照key进行分区和排序,然后将数据溢写到磁盘,最后会将所有的临时磁盘文件合并为一个大的磁盘文件,同时生成一个索引文件,然后reduce task去map端拉取数据的时候,首先解析索引文件,根据索引文件再去拉取对应的数据。
    • bypass机制:将普通机制的排序过程去掉了,它的触发条件是而当shuffle map task数量小于200(配置参数)并且算子不是聚合类的shuffle算子(比如reduceByKey)的时候,该机制不会进行排序,极大的提高了其性能。

    6.讲讲Spark为什么比Hadoop快

    • MapReduce需要将计算的中间结果写入磁盘,然后还要读取磁盘,从而导致了;而Spark不需要将计算的中间结果写入磁盘,这得益于Spark的RDD弹性分布式数据集和DAG有向无环图,中间结果能够以RDD的形式存放在内存中,这样大大减少了磁盘IO。(假设有多个转换操作,那么spark是不需要将第一个job的结果写入磁盘,然后再读入磁盘进行第二个job的,它是直接将结果缓存在内存中)
    • MapReduce在shuffle时需要花费大量时间排序,而spark在shuffle时如果选择基于hash的计算引擎,是不需要排序的,这样就会节省大量时间。
    • MapReduce是多进程模型,每个task会运行在一个独立的JVM进程中,每次启动都需要重新申请资源,消耗了大量的时间;而Spark是多线程模型,每个executor会单独运行在一个JVM进程中,每个task则是运行在executor中的一个线程。

    7.RDD是什么,有什么特点

    • 它翻译过来就叫做,是一种数据结构,可以理解成是一个集合。在代码中的话,RDD是一个抽象类。还有一个非常重要的特点:RDD是不保存数据的,仅仅封装了计算逻辑,也就是你直接打印RDD是看不见具体值的。

    8.RDD的血缘

    • 多个连续的RDD的依赖关系,称之为血缘关系;每个RDD会保存血缘关系

    9.宽窄依赖

    • 宽依赖:父的RDD的一个分区的数据会被子RDD的多个分区依赖,涉及到Shuffle
    • 窄依赖:父的RDD的一个分区的数据只会被子RDD的一个分区依赖

    10.stage划分

    • 对于窄依赖,不会进行划分,也就是将这些转换操作尽量放在在同一个 stage中,可以实现流水线并行计算。 对于宽依赖,由于有 shuffle 的存在,只能在父 RDD 处理完成后,才能开始接下来的计算,也就是说需要要划分 stage(从后往前,遇到宽依赖就切割stage

    11.Transform和Action算子分别列举一些常用的,他们的区别是什么

    • 转换算子主要是将旧的RDD包装成新的RDD,行动算子就是触发任务的调度和作业的执行。
    • 转换算子:map flatMap filter reducebykey union
    • 行动算子:collect foreach take

    12.Spark 能产生shuffle的算子

    • reduceByKey、sortByKey
    • repartition、coalesce
    • join、cogroup

    13.Spark里的reduce by key和group by key两个算子在实现上的区别并且说一下性能

    • groupByKey只能分组,不能聚合,而reduceByKey包含分组和聚合两个功能
    • reduceByKey会在shuffle前对分区内相同key的数据进行预聚合(类似于MapReduce的combiner),减少落盘的数据量,而groupByKey只是shuffle,不会进行预聚合的操作,因此reduceByKey的会高一些

    14.Spark内存管理

    • spark分为堆内内存和堆外内存,堆内内存由JVM统一管理,而堆外内存直接向操作系统进行内存的申请,不受JVM控制 spark.executor.memoryspark.memory.offHeap.size
    • 堆内内存又分为存储内存和执行内存和其他内存和预留内存,存储内存主要存放缓存数据和广播变量,执行内存主要存放shuffle过程的数据,其他内存主要存放rdd的元数据信息,预留内存和其他内存作用相同。

    15.看过Spark底层源码没有

    • 看过,比如spark shuffle源码,...

    16.Spark 数据倾斜

    见之前的文章

    17.用Spark遇到了哪些问题

    • 聚合函数导致内存溢出
    • 广播join导致内存溢出
    • 数据倾斜

    18.Spark join的有几种实现 *

    • 包括 broadcast hash join,shuffle hash join,sort merge join,前两种都是基于hash join;broadcast 适合一张很小的表和一张大表进行join,shuffle适合一张较大的小表和一张大表进行join,sort适合两张较大的表进行join。
    • 先说一下hash join吧,这个算法主要分为三步,首先确定哪张表是build table和哪张表是probe table,这个是由spark决定的,通常情况下,小表会作为build table,大表会作为probe table;然后构建hash table,遍历build table中的数据,对于每一条数据,根据join的字段进行hash,存放到hashtable中;最后遍历probe table中的数据,使用同样的hash函数,在hashtable中寻找join字段相同的数据,如果匹配成功就join到一起。这就是hash join的过程
    • broadcast hash join分为broadcast阶段和hash join阶段,broadcast阶段就是 将小表广播到所有的executor上,hash join阶段就是在每个executor上执行hash join,小表构建为hash table,大表作为probe table
    • shuffle hash join分为shuffle阶段和hash join阶段,shuffle阶段就是 对两张表分别按照join字段进行重分区,让相同key的数据进入同一个分区中;hash join阶段就是 对每个分区中的数据执行hash join
    • sort merge join分为shuffle阶段,sort阶段和merge阶段,shuffle阶段就是 将两张表按照join字段进行重分区,让相同key的数据进入同一个分区中;sort阶段就是 对每个分区内的数据进行排序;merge阶段就是 对排好序的分区表进行join,分别遍历两张表,key相同就join输出,如果不同,左边小,就继续遍历左边的表,反之,遍历右边的表

    19.背压机制应用场景 底层实现

    • 背压机制就是根据JobScheduler 反馈作业的执行信息来动态调整receiver的数据接收率

    20.spark RDD持久化

    • 因为RDD实际上是不存储数据的,那么如果RDD要想重用,那么就需要重头开始再执行一遍,所以为了提高RDD的重用性,就有了RDD持久化
    • 分类:缓存和检查点

    Flink篇

    1.Flink的组成

    • jobmanager:相当于一个集群的Master,是整个集群的协调者,负责接收job
    • taskmanager:实际负责的Worker
    • client:flink程序提交的客户端,当用户提交一个Flink程序时,会首先创建一个Client

    2.Flink流批一体解释一下

    • Flink 使用一个引擎就支持了DataSet API 和 DataStream API。其中DataSet API用来处理有界流,DataStream API既可以处理有界流又可以处理无界流,这样就实现了流批一体

    3.Flink和SparkStreaming区别

    • 第一,计算速度的不同,flink是真正的实时计算框架,而sparkstreaming是一个准实时微批次的计算框架,也就是说,sparkstreaming的实时性比起flink,差了一大截。
    • 第二,架构模型的不同,Spark Streaming 在运行时的主要角色包括:Driver、Executor,而Flink 在运行时主要包含:Jobmanager、Taskmanager。
    • 第三,时间机制的不用,Spark Streaming 只支持处理时间,而Flink支持的时间语义包括处理时间、事件时间、注入时间,并且还提供了watermark机制来处理迟到数据。

    4.那Flink shuffle呢?你了解吗?

    • 其实就是redistribute,一对多

    5.watermark用过吗

    • 它就是一种特殊的时间戳,作用就是为了让事件时间慢一点,等迟到的数据都到了,才触发窗口计算
    • 当watermark等于窗口时间的时候,就会触发计算

    6.checkpoint Chandy-Lamport算法

    • flink应用在启动的时候,flink的JobManager创建CheckpointCoordinator
    • CheckpointCoordinator(检查点协调器) 周期性的向该流应用的所有source算子发送 barrier(屏障)
    • 当某个source算子收到一个barrier时,便暂停数据处理过程,然后将自己的当前状态制作成快照,并保存到指定的持久化存储(hdfs)中,最后向CheckpointCoordinator报告自己快照制作情况,同时向自身所有下游算子广播该barrier,恢复数据处理
    • 下游算子收到barrier之后,会暂停自己的数据处理过程,然后将自身的相关状态制作成快照,并保存到指定的持久化存储中,最后向CheckpointCoordinator报告自身快照情况,同时向自身所有下游算子广播该barrier,恢复数据处理。
    • 每个算子按照 上面这个操作 不断制作快照并向下游广播,直到最后barrier传递到sink算子,快照制作完成。
    • 当CheckpointCoordinator收到所有算子的报告之后,认为该周期的快照制作成功; 否则,如果在规定的时间内没有收到所有算子的报告,则认为本周期快照制作失败。

    7.如何用checkpoint和watermark防止读到乱序数据

    • watermark设置延迟时间
    • checkpoint进行持久化

    8.Kafka和Flink分别怎么实现exactly once,问的比较深入,我只回答了一些用法,二阶段提交说了流程,没说出来机制。

    kafka:ack=-1+幂等性

    flink利用checkpoint检查点保证精准一次性【超级重点,checkpoint的细节需要知道】

    java基础篇

    1.java限定词(private那些)

    public > protected > default > private

    2.ArrayList原理,为什么初始是10,为什么扩容1.5倍

    ArrayList是基于动态数组的数据结构;

    因为对于1.2倍来说,它的扩容空间很小,很容易就会被装满,就需要不停的去扩容,而对于2倍来说,它的扩容空间很大,反而很难被装满,就很难被扩容。所以最终选择了1.5倍最为扩容的倍数。

    3.hashmap的实现原理

    jdk1.8之前,hashmap由 数组-链表数据结构组成,在jdk1.8之后hashmap由 数组-链表-红黑树数据结构组成;当我们创建hashmap对象的时候,jdk1.8以前会创建一个长度为16的Entry数组jdk1.8以后就不是初始化对象的时候创建数组了,而是在第一次put元素的时候,创建一个长度为16的Node数组;当我们向对象中插入数据的时候,首先调用hashcode方法计算出key的hash值,然后对数组长度取余((n-1)&hash(key)等价于hash值对数组取余)计算出向Node数组中存储数据的索引值;如果计算出的索引位置处没有数据,则直接将数据存储到数组中;如果计算出的索引位置处已经有数据了,此时会比较两个key的hash值是否相同,如果不相同,那么在此位置划出一个节点来存储该数据(拉链法);如果相同,此时发生hash碰撞,那么底层就会调用equals方法比较两个key的内容是否相同,如果相同,就将后添加的数据的value覆盖之前的value;如果不相同,就继续向下和其他数据的key进行比较,如果都不相等,就划出一个节点存储数据;如果链表长度大于阈值8(链表长度符合泊松分布,而长度为8个命中概率很小),并且数组长度大于64,则将链表变为红黑树,并且当长度小于等于6(不选择7是防止频繁的发生转换)的时候将红黑树退化为链表。

    4.实现单例模式

    // 饿汉式-静态常量方式
    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton() {}
        public static Singleton getSingleton () {
            return instance;
        }
    }
    // 饿汉式-静态代码块
    public class Singleton {
        private static Singleton instance;
        static {
            instance = new Singleton();
        }
        private Singleton() {}
        public static Singleton getSingleton () {
            return instance;
        }
    }
    // 懒汉式  第一次调用才初始化,实现了懒加载特性,线程不安全
    public class Singleton {
        private static Singleton instance;
        private Singleton() {}
        public static Singleton getSingleton() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    // 懒汉式 线程安全
    public class Singleton {
        private static Singleton instance;
        private Singleton() {}
        public static synchronized Singleton getSingleton() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    // 双重校验锁 线程安全,效率高
    public class Singleton {
        private volatile static Singleton instance;
        private Singleton() {}
        public static Singleton getSingleton() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    // 静态内部类 线程安全,效率高
    public class Singleton {
        private static class SingleHolder {
            private static final Singleton INSTANCE = new Singleton();
        }
        private Singleton() {}
        public static Singleton getSingleton() {
            return SingleHolder.INSTANCE;
        }
    }
    

    5.多路复用,NIO这些了解过吗?

    BIO是同步阻塞的IO模型,NIO是同步非阻塞的IO模型,IO多路复用是异步阻塞的IO模型,AIO是异步非阻塞的IO模型

    6.100M的数组 随机查快还是顺序查快 解释为什么?

    CPU内部的数据预取机制,会假设短时间内的读取最可能就会发生在下一个(或后边离得不远)的地址上。顺序读取最有利于命中CPU的一二三级缓存。

    并发编程篇

    1.如何实现多线程 写过多线程吗

    class RunnableDemo implements Runnable {
        private String threadName;
        public RunnableDemo(String name) {
            threadName = name;
        }
        @Override
        public void run() {
            System.out.println(threadName);
        }
    }
    public class Main {
        public static void main(String[] args) {
            RunnableDemo thread01 = new RunnableDemo("thread01");
            new Thread(thread01).start();
            RunnableDemo thread02 = new RunnableDemo("thread02");
            new Thread(thread02).start();
            RunnableDemo thread03 = new RunnableDemo("thread03");
            new Thread(thread03).start();
        }
    }
    

    2.4种线程池功能

    • 通过ThreadPoolExecutor构造函数实现(推荐)
    • CachedThreadPool:返回一个可根据实际情况调整线程数量的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
    • FixedThreadPool:返回一个固定线程数量的线程池,可控制线程最大并发数,超过的线程会在队列中等待
    • SingleThreadExecutor:返回一个只有一个线程的线程池,它只会用唯一的线程来执行任务,保证所有任务按照执行顺序执行。

    3.java内存模型

    java内存模型是一套规范,描述了java程序中各种变量(线程共享变量)的访问规则,其规定所有的共享变量都存储在主内存中,每一个线程都有自己的工作内存,工作内存中只存储该线程对共享变量的副本,线程对变量的所有操作都必须在工作内存中完成,而不能直接读写主内存的变量。

    4.volatile的作用

    • 保证可见性:如果变量被 volatile 修饰,那么每次修改之后,接下来在读取这个变量的时候一定能读取到该变量最新的值
    • 保证有序性:因为编译器或 CPU会对代码的执行顺序进行优化,导致代码的实际执行顺序可能与我们编写的顺序是不同的,在多线程的场景下就会出现问题,利用volatile可以禁止这种重排序的发生

    5.synchronized和volatile的区别

    • volatile只能修饰变量,synchronized可以用来代码块或者方法
    • volatile不能保证数据的原子性,synchronized可以保证原子性
    • volatile不会造成线程的阻塞,synchronized会造成线程的阻塞
    • volatile主要用于解决变量在多个线程之间的可见性,synchronized主要用于解决多个线程之间访问资源的同步性

    6.公平锁与非公平锁的区别

    • 公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁。
    • 非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁。

    7.lock是公平的还是非公平的

    可以根据逻辑自己实现是否公平

    8.sychornized怎么优化

    • 减少synchronized的范围:同步代码块中尽量短
    • 降低synchronized锁的粒度:将一个锁拆分为多个锁提高并行度 (HashTable -> ConcurrentHashMap)
    • 读写分离:读取时不加锁,写入和删除时加锁 (ConcurrentHashMap)

    9.volatile可以保证原子性吗?

    不能

    10.reentrantlock底层原理

    ReentrantLock先通过CAS尝试获取锁如果获取了就将锁状态state设置为1(state=0表示无锁),但是如果锁已经被占用,先判断当前的锁是否是自己占用了,如果是的话就将锁计数器会state++(可重入性),如果是被其他线程占用,那么将该线程加入AQS队列并wait()

    11.synchronize底层实现

    synchronized的锁对象会关联一个monitor(监视器,它才是真正的锁对象),这个monitor不是我们主动创建的,是JVM的线程执行到这个同步代码块,发现锁对象没有monitor就会创建monitor,monitor内部有两个重要的成员变量owner:拥有这把锁的线程,recursions:记录线程拥有锁的次数,当一个线程拥有monitor后,其他线程只能等待。当执行到monitorexit时,recursions会减1,当计数器为0时,这个线程会释放锁

    算法篇

    都是网上的一些原题,自行寻找答案

    1.岛屿问题

    2.矩阵最小路径和问题 求矩阵最短路径

    3.判断一棵二叉树是否镜像对称

    4.判定二叉排序树

    5.二叉树之Z遍历

    6.非递归实现中序遍历

    7.二叉搜索树查找第k个

    8.堆排序

    9.桶排序

    10.股票交易1 2

    11.二分查找

    12.k个一组反转

    13.重排链表

    14.链表排序(归并排序实现)

    15.包含min函数的栈 O(1)

    16.搜索旋转排序数组

    17.最长回文子串

    18.LRU

    19.数据结构 让你设计一个hash表 怎么设计?

    20.那设计一个hashtable

    21.string转int

    ---------------------------------------------------------

    最全的大数据笔记点击下方 ↓

    2023最新大数据开发面试笔记V4.0

    ----------------------------------------------------------

    #数据人的面试交流地##2024提前批##大数据开发##字节跳动##面经#
    全部评论
    全是java啊
    点赞 回复
    分享
    发布于 2023-07-14 00:23 北京
    有些没写全啊
    点赞 回复
    分享
    发布于 2023-08-11 13:11 安徽
    联易融
    校招火热招聘中
    官网直投

    相关推荐

    22 154 评论
    分享
    牛客网
    牛客企业服务