levycui 发表于 2022-5-10 10:48:07

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]
查看完整版本: 58同城大数据开发复试面试经验分享(附答案)