大家好,我是土哥。
周五晚上过来卷大家了,今天为大家带来一位读者面试小红书的 数据平台工程师(实时方向)面经。
面试时间:72 分钟
面试方向:数据平台工程师(实时方向)
面试工具:赛码网
面试难度 : ⭐⭐⭐⭐
原文链接:小红书数据平台工程师(实时方向)社招面经(附答案)
面试官: 不用自我介绍了,直接介绍一下流计算平台
纳尼?好高冷啊!!
具体自我介绍请查看: 58同城大数据开发社招面经(附答案)
面试官:1 你们的 UDF 是怎么管理的?
当自定义 UDF jar 后,
- 如果是 sql 类型以来的 jar , 文件会被上传到 OSS Bucket 中的 sql-artifacts 目录下。此外,sql 执行时,会自动提取类名,填充到 Function Name 字段中。
- 对于 Java 类型的 UDF,其依赖可以打包到 包中,也可以通过依赖文件项进行上传;对于 Python 类型的 UDF,其依赖推荐通过的单独上传依赖文件方式上传。
- 在 UDF Artifact 文件或者其依赖文件比较大时,推荐通过外部 URL 的方式进行上传。需要注意的是,如果外部 URL 是 OSS Bucket 地址,其依赖文件必须位于 目录下。
面试官: 2 任务和那些 jar 包的依赖关系是怎么管理的?
当提交一个 任务,如果该任务依赖一些 包,我们专门设计了一个资源管理模块,会通过该资源管理模块上传 jar 包,该 jar 包上传后,会被放入 HDFS 目录下,在任务提交时,通过 获取资源配置项进行解析。
面试官:3 Flink 应用提交包含哪些模式?
远程提交方式:分为 Standalone 方式、yarn 方式、K8s 方式
Standalone:包含 session 模式
Yarn 方式分为三种提交模式:Yarn-perJob 模式、Yarn-Sessionmo 模式、YarnApplication 模式。
K8s 方式:包含 session 模式
面试官:4 yarn per job 模式和 yarn session 模式以及 application 模式的优缺点说一下?
1 Yarn-Session 模式:所有作业共享集群资源,隔离性差,JM 负载瓶颈,main 方 法在客户端执行。适合执行时间短,频繁执行的短任务,集群中的所有作业只有一个 JobManager,另外,Job 被随机分配给 TaskManager。
Session-Cluster 模式需要先启动集群,然后再提交作业。
2 Yarn-Per-Job 模式:每个作业单独启动集群,隔离性好,JM 负载均衡,main 方法在客户端执行。在 per-job 模式下,每个 Job 都有一个 JobManager,每个 TaskManager 只有单个 Job。
一个任务会对应一个 Job,每提交一个作业会根据自身的情况,都会单独向 yarn 申请资源,独享 Dispatcher 和 ResourceManager,按需接受资源申请;适合 规模大长时间运行的作业。
3 application 模式: main 方法在 JM 中执行,入口点位于 ApplicationClusterEntryPoint,客户端只需要负责发起部署请求。
优点: 减轻客户端的压力,避免客户端资源成为瓶颈。
面试官:5 State 可以介绍一下吗?
(1) 按照由 Flink 管理 还是 用户管理,状态可以分为 原始状态(Raw State) 和 托管状态(ManagedState)。
托管状态(ManagedState):由 Flink 自行进行管理的 State。
原始状态(Raw State):由用户自行进行管理。
两者区别:
- Managed State 由 Flink Runtime 管理,自动存储,自动恢复,在内存管理上有优化;而 Raw State 需要用户自己管理,需要自己序列化。
- Managed State 支持已知的数据结构,如 Value、List、Map 等。而 Raw State 只支持 字节 数组,所有状态都要转换为二进制字节数组才可以。
(2)State 按照是否有 key 划分为 KeyedState 和 OperatorState 两种。
KeyedState 只能用在 keyedStream 上的算子中,状态跟特定的 key 绑定。keyStream 流上的每一个 key 对应一个 state 对象。若一个 operator 实例处理多个 key,访问相应的多个 State,可对应多个 state。
keyedState 保存在 StateBackend 中,通过 RuntimeContext 访问,实现 Rich Function 接口。支持多种数据结构:ValueState、ListState、ReducingState、 AggregatingState、MapState。
OperatorState 可以用于所有算子,但整个算子只对应一个 state。
OperatorState 实现 CheckpointedFunction 或者 ListCheckpointed 接口。目前只支持 ListState 数据结构。
(3)在 Flink 中, state 一般被存储在 StateBackend 里面。
总共包含三种存储方式,内存、文件、RocksDB 等。
面试官:6 什么样的业务场景你会选择 FsBackend 或者 RocksDB ?
1 MemoryStateBackend,运行时所需的 State 数据全部保存在 TaskManager JVM 堆上内存中,执行检查点的时候,会把 State 的快照数据保存到 JobManager 进程 的内存中。基于内存的 Stateßackend 在生产环境下不建议使用,可以在本地开发调试测试 。
- State 存储在 JobManager 的内存中.受限于 JobManager 的内存大小。
- 每个 State 默认 5MB,可通过 MemoryStateBackend 构造函数调整。
- 每个 Stale 不能超过 Akka frame 大小。
2 FSStateBackend,运行时所需的 State 数据全部保存在 TaskManager 的内存 中, 执行检查点的时候,会把 State 的快照数据保存到配置的文件系统中。
:
FSStateBackend 适用于处理大状态、长窗口、或者大键值状态的有状态处理任务。
- State 数据首先被存在 TaskManager 的内存中。
- State 大小不能超过 TM 内存。
- TM 异步将 State 数据写入外部存储。
3 RocksDBStateBackend 使用嵌入式的本地数据库 RocksDB 将流计算数据状态存 储在本地磁盘中。在执行检查点的时候,再将整个 RocksDB 中保存的 State 数据全量或者增量持久化到配置的文件系统中。
:
- 最适合用于处理大状态、长窗口,或大键值状态的有状态处理任务。
- RocksDBStateBackend 非常适合用于高可用方案。
- RocksDBStateBackend 是目前唯一支持增量检查点的后端。 增量检查点非常适用于超大状态的场景。
面试官: 1 在 java 高并发时,会用到锁,你说一下 synchronized 和 ReenTrantLock的区别?
1 synchronized 是java内置关键字,在JVM层面,ReentrantLock是个java类
2 ReentrantLock包含等待可中断锁,意味着持有锁的线程长期不释放锁,正在等待的线程可以选择放弃等待,可以避免死锁
3 synchronized 自动释放锁 ReentrantLock需要在finally中手工释放锁,否则容易造成线程死锁 Lock.unlock()
4 ReentrantLock可以实现公平锁,公平锁就是先等待的线程先获得锁。
面试官:2 一个任务消费延迟了,你会怎么解决?
如果 一个任务消费延迟了,可以在 Flink WEBUI 上查看是否存在反压情况。
若看到 Flink 的哪个算子和 task 出现了反压。可以从资源调优和算子调优等方面进行解决。
资源调优即是对作业中的 Operator 的并发数(parallelism)、CPU(core)、堆内存(heap_memory)等参数进行调优。
作业参数调优包括:并行度的设置,State 的设置,checkpoint 的设置、Buffer 个数设置、Buffer 缓冲设置等。
面试官:3 你是怎么判断哪个算子存在反压呢?
在 Flink WEBUI 中,通过颜色和数值来判断任务的繁忙和反压情况,若颜色为红色,表示任务繁忙,若算子指标大于 0.5,表现为 High,证明该算子存在高度反压情况。
面试官:4 Flink 反压检测逻辑了解吗?(内部使用什么算法?)
Flink 1.13 版本以前,使用的堆栈采样式方式判断 反压,在 1.13 版本开始使用基于任务 Mailbox 计时方式判断反压。
面试官:5 反压有哪些危害呢?
反压如果不能得到正确的处理,可能会影响到 checkpoint 时长和 state 大小,甚至 可能会导致资源耗尽甚至系统崩溃。
1)影响 checkpoint 时长:barrier 不会越过普通数据,数据处理被阻塞也会导致 checkpoint barrier 流经整个数据管道的时长变长,导致 checkpoint 总体时间(End to End Duration)变长。
2)影响 state 大小:barrier 对齐时,接受到较快的输入管道的 barrier 后,它后面数 据会被缓存起来但不处理,直到较慢的输入管道的 barrier 也到达,这些被缓存的数据会 被放到 state 里面,导致 checkpoint 变大。
这两个影响对于生产环境的作业来说是十分危险的,因为 checkpoint 是保证数据一 致性的关键,,而 state 大小同样可能拖慢 checkpoint 甚至导致 OOM (使用 Heap-based StateBackend)或者物理内存使用超出容器资源(使用 RocksDBStateBackend)的稳定性问题。
面试官:6 反压如何解决,排查方式有哪些?
- 解决反压首先要做的是定位到造成反压的节点,排查的时候,先把 operator chain 禁用,方便定位到具体算子。
因为 Flink 默认是开启 operator chain 的,他会将多个 operator 串在一起作为一个 operator chain, 以便提高程序的性能,禁用后 每个 operator 都会执行。
- 在 WEBUI 上看到某个算子出现反压,若该节点的发送速率跟不上它的产生数据速率。这一般会发生在一条输入多条输出的 operator 上,该节点是反压的根源节点,它是从 Source Task 到 Sink Task 的第一个出现反压的节点。 若下游的节点接受速率较慢,通过反压机制限制了该节点的发送速率。这种情况,需要继续排查下游节点,一直找到第一个为 OK 的一般就是根源节点。
- 利用 Metrics 定位,因为数据在传输过程中,会和 Channel 接受端的 Buffer 使用率有关。 例如 发送端 Buffer 使用率、接收端 Buffer 的使用率等。
如果 Subtask 发送端 Buffer 使用率高,代表被下游反压限速了,如果 Subtask 接收端 Buffer 使用率高,表明将反压传导至上游。
具体看如下图:
- 使用火焰图功能判断用户的代码是否存在性能问题,,Flink 1.13 直接在 WebUI 提供 JVM 的 CPU 火焰图,默认是不开启的,需要修改参数:rest.flamegraph.enabled: true #默认 false。修改后,用来分析 Task Thread 是否跑满一个 CPU 核。
火焰图是通过对堆栈跟踪进行多次采样来构建的,火焰图纵向代表调用链,横向代表样本出现次数。看顶层的哪个函数占据的宽度最大。只要有"平顶"(plateaus),就表示该函数可能存在性能问题,具体如下图。
- 分析 GC 情况,TaskManager 的内存以及 GC 问题也可能会导致反压,包括 TaskManager JVM 各区内存不合理导致的频繁 Full GC 甚至失联。通常建议使用默认的 G1 垃圾回收器。可以通过打印 GC 日志 使用 GC 分析器(GCViewer 工具)来验证这种情况。
- 也有可能是数据倾斜所造成的反压。
面试官:7 为什么数据倾斜会造成反压?
首先,数据倾斜 是由于不同的 key 对应的数据量不同,而导致不同 task 所处理的数据量不同的问题。如果在 Flink 相同 Task 的多个 Subtask 中,个别 Subtask 接收到的数据量明显大于其他 Subtask 接收到的数据量,就会造成数据倾斜,这样就会导致任务执行过慢,从而引起反压情况。
Flink Web UI 可以精确地看到每个 Subtask 处理了多少数据,即可判断出 Flink 任务是否存在数据倾斜。
面试官:8 Flink 中数据倾斜有哪些解决办法?
先分析是 keyBy 前还是 keyBy 后发生数据倾斜。
- keyBy 后的聚合操作存在数据倾斜。使用 LocalKeyBy 的思想,在 keyBy 上游算子数据发送之前,首先在上游算子的本地对数据进行聚合后,再发送到下游,使下游接收到的数据量大大减少,从而使得 keyBy 之后的聚合操作不再是任务的瓶颈。
- keyBy 之前发生数据倾斜。产生该情况可能是因为数据源的数据本身就不均匀,例如由于某些原因 Kafka 的 topic 中某些 partition 的数据量较大,某些 partition 的数据量较少。 解决办法:需要让 Flink 任务强制进行 shuffle。使用 shuffle、rebalance 或 rescale 算子即可将数据均匀分配,从而解决数据倾斜的问题。
- keyBy 后的窗口聚合操作存在数据倾斜。因为使用了窗口,变成了有界数据(攒批)的处理,窗口默认是触发时才会输出一条结果发往下游,所以可以使用两阶段聚合的方式。
解决办法:
第一阶段聚合:key 拼接随机数前缀或后缀,进行 keyby、开窗、聚合。
第二阶段聚合:按照原来的 key 及 windowEnd 作 keyby、聚合
面试官:1 写一个算法吧,求 两数之和
解题思路:
创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N) 降低到 O(1)。
复杂度分析:
时间复杂度:O(N),其中 N 是数组中的元素数量。对于每一个元素 x,我们可以O(1) 地寻找 target - x。
空间复杂度:O(N),其中 N 是数组中的元素数量。主要为哈希表的开销。
面试官:2 再写个 三数之和
解题思路:
ArrayList 集合 + 排序 + 双指针
- 先创建集合 ArrayList。
- 判断数组长度小于3,返回定义的集合。
- 对数组排序 Arrays.sort(nums);
- for循环遍历数组;
- 判断,当nums[i] >0 返回 break;因为nums[i] 大于0了,后面的都大于0了
- 判断 当nums[i] ==nums[i+1],continue;
- 定义双指针 L = i+1; R = len-1;
- while(R>L) 定义 sum = nums[i] + nums[L] + nums[R];
- 判断 当sum == 0, 将三个数封装成集合,装进 listArray.
- 当 sum > 0,证明R 往后更大,所以 R–;
- 当 sum < 0,证明 R已经是最大了,L应该往右移,L++。
- 返回 listArray
时间复杂度:O(n^2)
以上就是小红书数据平台工程师(实时方向)社招的面试内容,觉得内容对你有帮助,请点赞、收藏、关注三连走起!
========土哥的升级服务
如果你因为找工作而烦恼,不会做简历,不会备战复习,不会面试技巧,不会 HR 面,不会谈薪,不用怕,有土哥。
你可以找土哥修改简历,1 对 1 辅导项目、面试技巧,HR 面以及谈薪等,同时发你总结的最新面经试题(有偿哈),具体价格私信土哥。备注:【简历修改+面试辅导】
毕竟免费的东西,不仅你不会上心,土哥也没有多大精力认真去修改和辅导。