
1) 【一句话结论】采用基于流处理的实时计算架构,结合Kafka数据采集、Flink实时计算、Redis状态缓存与WebSocket输出,通过消息队列持久化、计算引擎容错和状态存储分布式保证低延迟和高可用。
2) 【原理/概念讲解】老师口吻,解释关键组件逻辑:
数据采集:当用户进入/离开课堂时,后端服务发送“进入/离开”事件到Kafka(分布式消息队列),Kafka的持久化+副本机制保证数据不丢失且可快速消费,类比“快递分拣中心”——把每个用户的课堂事件分发给不同处理节点。
实时计算:使用Flink(流处理引擎)消费Kafka事件,通过时间窗口(如1秒)聚合数据,计算当前参与人数(聚合进入事件)、互动率(互动事件/参与人数),Flink的Exactly-Once语义和状态管理保证计算准确性,类比“流水线工人”——快速处理数据并更新状态。
状态管理:用Redis(内存数据库)缓存实时统计结果,因Redis读写延迟极低(毫秒级),适合实时查询,类比“仓库”——存储最新统计结果供前端快速获取。
结果输出:通过WebSocket长连接,将计算结果实时推送给前端,前端展示课堂参与人数/互动率,类比“快递员”——把结果快速送达用户端。
3) 【对比与适用场景】
| 方案 | 定义 | 延迟 | 适用场景 | 注意点 |
|---|---|---|---|---|
| 流处理(Flink) | 实时处理数据流,支持状态管理 | 毫秒级 | 实时统计、实时告警 | 需配置检查点保障容错 |
| 批处理(Spark) | 定期处理历史数据 | 分钟级 | 数据分析、报表 | 不适合实时需求 |
| Kafka | 分布式消息队列 | 毫秒级(生产) | 数据采集、解耦 | 需配置副本+持久化 |
| Pulsar | 分布式消息+存储 | 毫秒级 | 实时+持久化 | 更新速度更快 |
4) 【示例】
// 生产“用户进入课堂”事件
producer.send(new ProducerRecord<>("classroom-events", "class-entered", userId));
DataStream<EventType> events = env.addSource(kafkaSource);
DataStream<StatResult> stats = events
.keyBy(event -> event.classId)
.window(TumblingEventTimeWindows.of(Time.seconds(1)))
.process(new CountProcessFunction())
.connect(env.addSource(redisSource))
.process(new MergeProcessFunction())
.map(stat -> new StatResult(stat.classId, stat.count, stat.interactionRate));
WebSocketServer server = new WebSocketServer();
server.onMessage(message -> {
StatResult stat = getLatestStat(message.getClassId());
server.sendText(stat.toJson());
});
5) 【面试口播版答案】
面试官您好,针对好未来在线直播课的实时统计需求,我设计的方案核心是采用流处理架构,从数据采集到计算输出全链路保障低延迟和高可用。首先数据采集阶段,我们使用Kafka作为消息队列,当用户进入或离开课堂时,后端服务会发送事件到Kafka,Kafka的持久化机制和副本机制保证数据不丢失且可快速消费。然后实时计算阶段,我们选择Flink作为流处理引擎,它支持状态管理和容错,能快速计算当前课堂参与人数(比如聚合进入事件的数量)和互动率(比如互动事件数除以参与人数)。中间状态我们用Redis缓存,因为Redis的内存存储让读写延迟极低,能快速响应前端查询。最后结果输出通过WebSocket长连接,将计算结果实时推送给前端,前端展示课堂参与人数和互动率。为了保证低延迟,我们优化了Flink的并行度,减少中间数据的存储,同时Kafka的生产和消费延迟控制在毫秒级;为了保证高可用,Kafka配置了多个副本,Flink启用了检查点机制,Redis也使用了集群部署,确保任何单点故障都不会影响整体服务。
6) 【追问清单】
7) 【常见坑/雷区】