58同城大数据开发复试面试经验分享(附答案)
本帖最后由 levycui 于 2022-5-10 10:49 编辑问题导读:
1、Flink 如何解决作业资源随着需求的变化而动态调整的?
2、Flink kafka sink 插件如何设计?
3、推理过程中 若是任务突然中止,模型和数据丢失怎么办?
4、资源使用率过低的话,K8S 应该怎么处理?
今天为大家分享 58 同城大数据开发(流计算方向)社招二面、三面面经,附上答案。
二面平台负责人面
由于到了 大数据平台负责人 面试关节,所以不会过多的问一些基础问题,全程从项目的角度出发,通过项目来引发扩展问题,这里我主要分享 4 个通过项目扩展出的知识点。
1 面试官:在你们生产环境上,Flink 如何解决作业资源随着需求的变化而动态调整的?
考察 Flink 资源管理知识点
简答
回答:公司目前一部分业务是将 Flink 任务运行在 K8S 容器上的,使用 Flink Reactive Mode 响应模式,将 Flink 集群部署到 K8S 容器中,通过 K8S 的 Pod 水平自动扩缩容组件来实现 Flink 作业资源 TaskManager 的动态改变。
K8S 的 Pod 水平自动缩放组件会监控所有 TaskManager pods 的 CPU 负载来相应的调整副本因子(replication factor)。当 CPU 负载升高时,autoscaler 会增加 TaskManager 资源来平摊压力;当负载降低时,autoscaler 会减少 TaskManager 资源。
背后原理
首先,在 Flink 1.14.0 最新版本中依旧无法做到 Job 在运行时动态调整并行度 不经历重启 直接拉起新的 Task 实例运行,目前都是基于重启恢复机制来实现的,因为涉及到状态管理。
在资源管理中,资源的获取包含两种模式:
Active 模式:主动式,Flink 可以主动申请、释放资源(通过与资源管理框架集成,如 Yarn、Mesos)。
Reactive 模式:被动响应式,该模式由外部系统来分配,释放资源,Flink 只是简单地对可用资源进行响应。(这种模式对于基于容器环境相当有意义,如 K8S )
现在 Flink 的资源管理模式是 Active 模式,由用户明确指定 Job 需要的资源,JobMaster 会向 ResourceManager 去请求用户指定的全量资源,当 ResourceManager 无法满足 JobMaster 的申请需求时,该 job 将无法正常启动,它会陷入失败重启->再次尝试申请的循环。
为了能够同时支持 Active/Reactive 这两种模式,Flink 1.13.0 版本引入声明式资源管理设计。
该功能与原先最大差别在于:JobMaster 不再去逐个请求 Slot,而是声明需要的资源情况,对资源要求是弹性范围的,不是固定的。
弹性资源包含四件套:(min, target, max, rs),每个元素的含义如下:
[*] min : 执行 Job 的最小资源。
[*] target : JobMaster 期望获得的常规资源需求,它是可变的,这是扩缩容的主要触发机制。
[*] max : 最大资源期望。
[*] rs : resource spec(资源描述信息)。
详细设计原理可以参考如下链接:
https://www.bianchengquan.com/article/574992.html
2 面试官:Flink kafka sink 插件如何设计?
考察 Flink connector sink 知识点
回答:在 Flink 1.14.0 版本,FlinkKafkaProducer 已经被已弃用,将在 Flink 1.15 中删除,新版本使用 KafkaSink 。
设计 Flink kafka sink 时,可以集成 KafkaSink 类,KafkaSink 允许将记录流写入一个或多个 Kafka 主题。
同时 Kafka sink 提供了一个构建器类来构造一个 KafkaSink 的实例。下面的代码片段展示了如何将字符串记录写入 Kafka 主题,并保证至少一次的交付。
DataStream<String> stream = ...
KafkaSink<String> sink = KafkaSink.<String>builder()
.setBootstrapServers(brokers)
.setRecordSerializer(KafkaRecordSerializationSchema.builder()
.setTopic("topic-name")
.setValueSerializationSchema(new SimpleStringSchema())
.setDeliveryGuarantee(DeliveryGuarantee.AT_LEAST_ONCE)
.build()
)
.build();
stream.sinkTo(sink);
KafkaSink 支持三种不同的 DeliveryGuarantees 语义。必须启用DeliveryGuarantee.AT_LEAST_ONCE 和 DeliveryGuarantee.EXACTLY_ONCEcheckpoint 。默认情况下 KafkaSink 使用 DeliveryGuarantee.NONE.
3 面试官:模型推理过程中要是单个模型过大,如何发送到 kafka?
考察 kafka 单个消息体多大 知识点
回答:在 kafka 中,默认单条消息最大为 1 M,当单条消息长度超过 1 M 时,就会出现发送到 broker 失败,从而导致消息在 producer 的队列中一直累积,直到撑爆生产者的内存。
所以在实际生产环境中,由于我们的单个模型是 5 M 多,所以刚开始出现上述的 发送到 broker 失败问题。
解决办法,只往 kafka 中发送消息体的 ID、 Location、Name,这样 消费者消费数据时,直接根据对应ID、Location 可以消费到模型。
4 面试官:推理过程中 若是任务突然中止,模型和数据丢失怎么办?
考察 Flink state、checkpoint 知识点
为了支持 Flink 推理功能,防止模型丢失问题,使用 flink checkpoint 机制实现,让推理算子实现 CheckpointedFunction 接口,将 model 以 value state 写入状态后端。这样,当推理出现故障时,checkpoint 重新启动时,直接从状态后端中拿到模型的 value 值。
三面总监面
面试官:1 Flink 集群为什么要部署到 K8S 上面?上云的好处是什么?
考察 K8S 的优缺点
回答:目前将 组件进行容器化已经成为当前的一个趋势,将 Flink 集群部署到 K8S 上 可以实现资源的合理利用,同时 k8s 是一个开源的容器集群管理系统,可以实现容器集群的 自动化部署、自动扩缩容、维护 等功能,具备很多特点:
1、故障迁移:当某一个 node 节点关机或挂掉后,node 节点上的服务会自动转移到另一个 node 节点上,这个过程所有服务不中断。这是 docker 或普通云主机是不能做到的
2、资源调度:当 node 节点上的 cpu、内存不够用的时候,可以扩充 node 节点,新建的 pod 就会被 kube-schedule 调度到新扩充的node节点上。
3、资源隔离:创建开发、运维、测试三个命名空间,切换上下文后,开发人员就只能看到开发命名空间的所有 pod,看不到运维命名空间的 pod,这样就不会造成影响,互不干扰。
面试官:2 Flink 任务部署到 K8S 和 部署到 yarn 上面的区别是什么?有哪些优点?
Flink on k8s 相比 yarn 的优势
[*] 更好的资源与网络的隔离性、安全性,更适合多租户
[*] 更容易实现与online service的混合部署,提升集群利用率
[*] 可以受益 K8S 丰富的生态系统,例如:ETCD,Prometheus.
以后将 Flink 部署到 K8S 会成为一个趋势,K8S 可以更好的监控到集群资源使用率,从而动态实现扩缩容,降低资源成本。
面试官:3 Flink 集群的资源使用率是多少?资源使用率过低的话,K8S 应该怎么处理?
回答:主要分离线作业资源使用率和流式作业资源使用率。根据具体公司的情况回复,比如:离线资源使用达到60%,流式作业资源使用达到40%。
流式资源使用率过低,这时 K8S 会根据自动扩缩容机制,减少 Pod 节点,降低负载,降低 CPU,资源的利用率。
面试官:4 那负载降低时,有没有遇到什么问题?
回答:我们是采用 Flink 的响应模式 (Reactive Mode),将 Flink 集群部署到 K8S 中的,然后 autoscaler 会监控 K8S 中 pods 的 CPU 负载。监控的指标主要有:
[*] 对 kafka 消费延迟监控
[*] 对 Flink 每秒吞吐量监控
[*] 对每个 TaskManager 的 CPU 负载监控
[*] 对 TaskManager 数量监控。
在生产环境中,的确遇到过 资源负载降低时,导致 Flink 监控出现毛刺等现象。如:TaskManager 数量某些情况下并没有很好的追随吞吐量曲线的变化。导致我们浪费了大量配置的 TaskManager 资源。
原因分析:
在 Flink 中,JobManager 会定期发送心跳信息给 TaskManager 来确定 TaskManager 是否还存活。默认心跳的发送频率是 50s 一次。这个默认值看上去像是很高,但是在高负载情况下可能出现网络波动、gc 停滞或其他情况导致心跳数据发送延迟。
但是,50s 默认值在我们的生产环境带来了一些问题。
当 K8S autoscaler 监控到 CPU 负载降低时,会降低 TaskManager 数量,停止 TaskManager 实例。随之 Flink 会因为数据传输层(data transport layer)与这些 TaskManager 失联而立即停止数据处理,而且 JobMaster 将会等待 50s 后才会认定 TaskManager 真正被关闭了。
在 JobManager 等待期间,吞吐量会降到 0,数据也会因此积压在 Kafka 中(消费延迟看板出现毛刺的原因)。当 Flink 重新运行起来后会对积压数据进行消费,从而造成了 CPU 负载的升高。autoscaler 监控到负载变化后会分配更多的 TaskManager,因此造成了 TaskManager 的浪费。
我们观察发现这种情况只会发生在 缩容 的场景中,因为缩容更加容易引起不稳定的情况的发生相比于扩容。扩容时,TaskManager 资源增加,数据停止处理仅发生在任务重启阶段(重启动作很快,仅会造成 Kafka 少量数据积压);然而缩容时,数据停止处理的时间大约 50s。
我们通过调整 heartbeat.timeout = 8s 来缓解了以上问题的发生。
小伙伴面试完之后,58 集群总监就实时给他反馈了情况,3面技术面都通过~
以上就是 58 集团2、3面所问的重点问题,其中涉及到一些业务场景方面的问题,但回答的套路是可以总结的。
作者:在IT中穿梭旅行
来源:https://mp.weixin.qq.com/s/AnAGlk-1vsVArav0nuAl9w
最新经典文章,欢迎关注公众号http://www.aboutyun.com/data/attachment/forum/201903/18/215536lzpn7n3u7m7u90vm.jpg
页:
[1]