51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

投放系统中需要实时计算广告曝光、点击率等指标,请说明如何设计实时数据处理流(如使用Flink或Kafka+Spark),并解释各组件的作用。

360Web服务端开发工程师-投放方向难度:中等

答案

1) 【一句话结论】

采用基于消息队列(如Kafka)的流处理架构,结合Flink或Spark Structured Streaming实时计算引擎,构建从数据采集、缓冲、实时计算到指标输出的完整流处理链路,实现广告曝光、点击率等指标的实时计算。

2) 【原理/概念讲解】

老师口吻:我们来拆解核心组件的作用。

  • 消息队列(如Kafka):数据源(如广告曝光、点击事件)通过生产者发送到Kafka,Kafka作为“数据缓冲区”,解耦数据生产与消费,保证高吞吐和可靠性(类比:超市货架,生产者把商品(数据)放到货架,消费者(计算引擎)按需取用,避免生产与消费直接耦合)。
  • 实时计算引擎(如Flink):消费Kafka数据流,通过状态管理(如Flink的键值状态)维护实时统计状态(如曝光计数、点击计数),使用窗口操作(如滑动窗口)计算指标(如点击率=点击数/曝光数),并将结果输出到存储(如Redis)或实时服务(如ES)。
  • 数据源:广告曝光、点击等事件通过API或日志系统产生,作为流处理的源头。

3) 【对比与适用场景】

框架/方案定义核心特性适用场景注意点
Flink端到端流处理框架,支持状态管理、窗口、容错状态管理高效、低延迟、端到端流处理、exactly-once语义复杂状态计算(如用户行为序列分析)、秒级低延迟指标(如CTR)部署复杂度较高,状态存储需考虑持久化(如RocksDB)
Kafka + Spark Structured Streaming消息队列(Kafka)+ Spark批处理引擎的流处理基于批处理优化,支持流批一体,代码复用已有Spark批处理代码迁移、大规模数据批处理场景状态管理依赖Spark,可能比Flink复杂,延迟略高(通常秒级)

4) 【示例】

假设广告曝光事件为JSON,包含事件类型(exposure)、广告ID、用户ID等。生产者将事件推送到Kafka主题(如ad_exposure)。Flink作业处理逻辑伪代码:

DataStream<AdEvent> stream = env
    .addSource(kafkaSource(...))  // 消费Kafka
    .filter(event -> event.getType().equals("exposure"));  // 筛选曝光事件

stream
    .keyBy(adEvent -> adEvent.getAdId())  // 按广告ID分组
    .window(TumblingEventTimeWindows.of(Time.seconds(10)))  // 10秒滑动窗口
    .aggregate(new AggregateFunction<AdEvent, Tuple2<Long, Long>, Tuple2<Long, Long>>() {
        @Override
        public Tuple2<Long, Long> createAccumulator() {
            return new Tuple2<>(0L, 0L);  // (曝光数, 点击数)
        }
        @Override
        public Tuple2<Long, Long> add(AdEvent adEvent, Tuple2<Long, Long> acc) {
            if (adEvent.getType().equals("exposure")) {
                return new Tuple2<>(acc.f0 + 1, acc.f1);
            } else if (adEvent.getType().equals("click")) {
                return new Tuple2<>(acc.f0, acc.f1 + 1);
            }
            return acc;
        }
        @Override
        public Tuple2<Long, Long> merge(Tuple2<Long, Long> a, Tuple2<Long, Long> b) {
            return new Tuple2<>(a.f0 + b.f0, a.f1 + b.f1);
        }
    })
    .process(new ProcessWindowFunction<Tuple2<Long, Long>, CTRResult, String, TimeWindow>() {
        @Override
        public void process(String adId, TimeWindow window, Iterable<Tuple2<Long, Long>> values, Context ctx, Collector<CTRResult> out) {
            long exposure = values.iterator().next().f0;
            long click = values.iterator().next().f1;
            double ctr = exposure > 0 ? (click * 1.0 / exposure) : 0;
            out.collect(new CTRResult(adId, window.getEnd(), ctr));  // 输出点击率
        }
    })
    .addSink(redisSink(...));  // 存储到Redis或实时服务

5) 【面试口播版答案】

面试官您好,关于实时计算广告曝光、点击率等指标,我会设计一个基于Kafka和Flink的流处理架构。首先,数据源(如广告曝光、点击事件)通过生产者发送到Kafka,作为缓冲区解耦生产与消费。然后,Flink消费Kafka数据流,通过状态管理维护实时统计(如曝光数、点击数),使用滑动窗口计算指标(如点击率=点击数/曝光数),结果存储到Redis或实时服务。核心是利用流处理实现低延迟计算,保证指标实时性。具体来说,Kafka负责数据缓冲和高吞吐,Flink负责实时计算和状态管理,通过窗口操作计算指标,最终输出到存储或服务,满足投放系统的实时监控需求。

6) 【追问清单】

  • 问:如何保证数据一致性?
    答:通过Kafka的幂等消费(生产者重试机制)和Flink的exactly-once状态提交(检查点+状态后端),确保数据不丢失或重复。
  • 问:如何处理延迟?
    答:通过调整窗口大小(如10秒)平衡延迟和实时性,同时监控延迟指标(如窗口结束时间与事件产生时间的差值)。
  • 问:如何扩展?
    答:Kafka分区扩展生产者/消费者,Flink并行度调整,支持水平扩展(如增加机器提升吞吐)。
  • 问:状态存储如何?
    答:Flink使用本地/分布式状态后端(如RocksDB),保证状态持久化,避免故障恢复时数据丢失。
  • 问:流批一体如何实现?
    答:通过Flink的批处理模式(如批量计算历史数据)或Spark Structured Streaming的流批统一API,实现流批代码复用。

7) 【常见坑/雷区】

  • 坑1:忽略数据源多样性,只考虑单一事件类型,未考虑其他指标(如转化率)的扩展。
  • 坑2:未说明容错机制,比如Kafka的rebalance或Flink的检查点,导致数据丢失。
  • 坑3:状态管理复杂,未解释如何处理状态过期或恢复,导致指标计算错误。
  • 坑4:延迟与实时性的平衡,比如窗口过大导致延迟高,未说明如何优化(如调整窗口大小或使用更细粒度窗口)。
  • 坑5:未考虑流批一体,只说实时处理,未说明如何与批处理数据结合(如历史数据补全实时指标)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1