目录
  1. 1. 面试相关问题整理
  • Spring、SpringMVC、SpringBoot、SpringCloud的区别与联系
    1. 1. 总结
  • 线程有哪些状态
  • jvm调优
  • flink旁路输出后的数据怎么处理
  • flink重启策略处理
  • flink如何保证 Exactly-Once
    1. 1. checkpoint 如何保证 Exactly-Once
    2. 2. 两阶段提交协议
  • kafka分区计算出来的
    1. 1. 分区
    2. 2. 有做什么自定义分区的策略吗?为什么
  • kafka 备份
    1. 1. ISR参数
    2. 2. kafka 采用多服务端冗余副本
    3. 3. 数据是怎么同步的
  • kafka副本策略
  • hbase底层数据结构
  • hdfs写入流程
  • flink加盐
    1. 1. 数据倾斜
    2. 2. 解决
  • java
    1. 1. jvm区
  • 面试相关问题整理

    面试相关问题整理

    Spring、SpringMVC、SpringBoot、SpringCloud的区别与联系

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring使你能够编写更干净、更可管理、并且更易于测试的代码。

    Spring MVC是Spring的一个模块,一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。主要针对的是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等

    Spring配置复杂,繁琐,所以推出了Spring boot,约定优于配置,简化了spring的配置流程。

    Spring Cloud构建于Spring Boot之上,是一个关注全局的服务治理框架。

    总结

    Spring是核心,提供了基础功能;
    Spring MVC 是基于Spring的一个 MVC 框架;
    Spring Boot 是为简化Spring配置的快速开发整合包;
    Spring Cloud是构建在Spring Boot之上的服务治理框架

    线程有哪些状态

    1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
    2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
      线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
    3. 阻塞(BLOCKED):表示线程阻塞于锁。
    4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
    5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
    6. 终止(TERMINATED):表示该线程已经执行完毕。

    jvm调优

    涉及到的设计模式:
    适配器模式:不同平台不同的编译结果;
    控制反转、依赖倒置:内存、锁由jvm控制
    java、kotlin、grorvy、scala

    class文件通过class Loader加载到 runtimeData areas 运行区内,通过执行引擎(jit complier、GC)执行,由natice methode interface提供硬件支撑(cpu 内存)

    flink旁路输出后的数据怎么处理

    这个问题没啥营养可能问的是出现问题后怎么处理
    首先查看延迟有多大如果延迟不大的就调整下watermark
    如果延迟很大,要找原因 看是不是数据倾斜了导致单点负载太大等问题

    flink重启策略处理

    flink如何保证 Exactly-Once

    通过checkpoint确保 Exactly-Once
    两阶段提交协议保证端到端 Exactly-Once 语义

    checkpoint 如何保证 Exactly-Once

    Checkpoint Barrier 对齐机制(Asynchronous barrier snapshots 基于 Chandy-Lamport 算法)
    当 ExecutionGraph 物理执行图中的 subtask 算子实例接收到 Barrier 的时候,subtask 会记录它的状态数据。如果 subtask 有2个上游(例如 KeyedProcessFunction、CoProcessFunction等),subtask 会收齐上游的2个 Barrier 后再触发 Checkpoint(即 Barrier 对齐)。

    1. 运行任务
    2. JobManager 发起CheckPoint
      JobManager 向任务流中发送 barrier (栅栏)
    3. source上报CheckPoint
      source收到barrier 向JobManager上报完成CheckPoint 将source的数据存储(保存位置由设置的StateBackend确定)。并将barrier 通过广播方式发送到下个task
    4. 数据处理
      在barrier到达task之前的数据按业务继续处理。收到barrier后的数据需要缓存
      这里有精确一次处理(数据缓存) 和 至少一次处理(不缓存继续发送给下个task)的区别
    5. barrier对齐
      在所有的barrier到达后,对task的状态进行checkpoint并将barrier发送到下个task
      这里如何判断所有的barrier都到了?
    6. 缓存数据处理
      在所有的barrier到达最后的Sink后,上报JobManager完成checkPoint. 通知存储checkpoint结束

    两阶段提交协议

    checkpoint 保证作业出现fail-over后可以从最新的快照进行恢复,即分布式快照机制可以保证flink系统内部的”精确一次“处理
    一旦Flink作业出现失败,作业会重新消费旧数据,这个时候就会出现重新消费的情况,也就是重复消费。

    在Flink中两阶段提交的实现方式被封装到TwoPhaseCommitSinkFunction这个抽象类中,我们只需要实现其中的beginTransaction,preCommit,commit,abort四个方法就可实现”精确一次“的处理语义。

    beginTransaction,在开启事务之前,我们在目标文件系统的临时目录中创捷一个临时文件,后面在处理数据时将数据写入此文件。
    preCommit,在预提交阶段,刷写(flush)文件,然后关闭文件,之后就不能再写入文件了。我们还将为属于下一个检查点的任何后续写入启动新事务。
    commit,在提交阶段,我们将预提交的文件原子性的移动到真正的目标目录中,这里会增加输出数据可见性的延迟
    abort,在中止阶段,删除临时文件。

    kafka分区计算出来的

    分区

    Kafka使用分区将topic的消息打散到多个分区分布保存在不同的broker上,实现了producer和consumer消息处理的高吞吐量。Kafka的producer和consumer都可以多线程地并行操作,而每个线程处理的是一个分区的数据。因此分区实际上是调优Kafka并行度的最小单元。对于producer而言,它实际上是用多个线程并发地向不同分区所在的broker发起Socket连接同时给这些分区发送消息;而consumer,同一个消费组内的所有consumer线程都被指定topic的某一个分区进行消费。

    创建一个只有1个分区的topic,然后测试这个topic的producer吞吐量和consumer吞吐量。假设它们的值分别是Tp和Tc,单位可以是MB/s。然后假设总的目标吞吐量是Tt,那么分区数 = Tt / max(Tp, Tc)
    机子几核设定多少个分区

    有做什么自定义分区的策略吗?为什么

    默认分区策略 hash(key) % partition;
    例如:订单数据有外卖、堂食、外带。其中订单量比例 外卖:堂食:外带 = 1:3:1。 按正常的订单类型分区的话会导致数据倾斜。所以我们将堂食做了拆分通过

    kafka 备份

    ISR参数

    min.insync.relicas
    默认值1, 用于表明限定在ISR 列表里面 至少有几个副本, 如果设定为2,如果ISR中只有一个副本的情况下,往该分区插入数据就会报错。

    kafka 采用多服务端冗余副本

    副本关系:
    leader partition:
      客户端写数据 消费者读数据操作的都是lead partition
      会维护一个ISR in-sync-replica 副本列表 写数据的时候会往副本列表中的所有副本写入数据 所有都成功了才会认为写入成功,如果有个副本写入不成功可能会将副本移出ISR中
    follwer partition:
      定期去lead partition同步数据

    数据是怎么同步的

    kafka副本策略

    hbase底层数据结构

    mysql底层数据结构是B+tree
    hbase底层数据结构是LSMtree

    hdfs写入流程

    1. 客户端(通过Distributed FileSystem模块)向NameNode发出写文件请求。
    2. 检查是否已存在文件、检查权限。若通过检查,直接先将操作写入EditLog,并返回输出流对象。
      (注:WAL,write ahead log,先写Log,再写内存,因为EditLog记录的是最新的HDFS客户端执行所有的写操作。如果后续真实写操作失败了,由于在真实写操作之前,操作就被写入EditLog中了,故EditLog中仍会有记录,我们不用担心后续client读不到相应的数据块,因为在第5步中DataNode收到块后会有一返回确认信息,若没写成功,发送端没收到确认信息,会一直重试,直到成功)
    3. client端按128MB的块切分文件。
    4. client将NameNode返回的分配的可写的DataNode列表和Data数据一同发送给最近的第一个DataNode节点,此后client端和NameNode分配的多个DataNode构成pipeline管道,client端向输出流对象中写数据。client每向第一个DataNode写入一个packet,这个packet便会直接在pipeline里传给第二个、第三个…DataNode。
      (注:并不是写好一个块或一整个文件后才向后分发)
      ps:这里被问到一个问题- client怎么知道哪个是第一个DataNode的
      NameNode返回的DataNode地址,会按照集群拓扑结构得出DataNode与客户端的距离,然后进行排序。排序有两个规则:
      网络拓扑结构中距离客户端近的则靠前;心跳机制中超时汇报的DataNode状态为无效的,则排靠后。NetworkTopology将整个集群中的DN存储成了一个树状网络拓扑图,
    5. 每个DataNode写完一个块后,会返回确认信息。
      (注:并不是每写完一个packet后就返回确认信息,个人觉得因为packet中的每个chunk都携带校验信息,没必要每写一个就汇报一下,这样效率太慢。正确的做法是写完一个block块后,对校验信息进行汇总分析,就能得出是否有块写错的情况发生)
    6. 写完数据,关闭输输出流。
    7. 发送完成信号给NameNode。
      (注:发送完成信号的时机取决于集群是强一致性还是最终一致性,强一致性则需要所有DataNode写完后才向NameNode汇报。最终一致性则其中任意一个DataNode写完后就能单独向NameNode汇报,HDFS一般情况下都是强调强一致性)

    看这里

    flink加盐

    问道flink 数据倾斜的时候 我回答了从source地方解决。 然后反问我有没有通过flink加盐的方式处理过 表示没有。。。

    数据倾斜

    1. 单点问题
      数据集中在某些分区上(Subtask),导致数据严重不平衡。
    2. GC 频繁
      过多的数据集中在某些 JVM(TaskManager),使得JVM 的内存资源短缺,导致频繁 GC。
    3. 吞吐下降、延迟增大
      数据单点和频繁 GC 导致吞吐下降、延迟增大。
    4. 系统崩溃
      严重情况下,过长的 GC 导致 TaskManager 失联,系统崩溃

    解决

    1. 并发度
      并发度设置的比分区数要低时,就会造成上面所说的消费不均匀的情况
    2. key 分布不均匀 (上游 源头)
      通过添加随机前缀打散它们的分布,使得数据不会集中在几个 Task 中
    3. key 分布不均匀 (transformation阶段)
      聚合统计前,先进行预聚合,例如两阶段聚合(加盐局部聚合+去盐全局聚合)
      具体措施:
      ① 预聚合:加盐局部聚合,在原来的 key 上加随机的前缀或者后缀。
      ② 聚合:去盐全局聚合,删除预聚合添加的前缀或者后缀,然后进行聚合统计。

    java

    jvm区

    public static String aaa = “aa”;
    这个是在哪个内存区里面的?
    第一种,static的,作为类信息在类被加载时被存在静态的方法区。
    第二种,非static的,作为对象属性,在对象创建的时候被初始化,存在堆里。
    第三种,在方法里的。我们知道在方法被调用时会被加载到栈中进行执行,所以写在方法里的变量存在栈中,也没毛病。

    文章作者: Fibonacci
    文章链接: http://sovwcwsfm.com/blog/page/interview.html
    版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Blog