
1) 【一句话结论】:采用“实时流处理+离线批处理”双轨架构,通过前端埋点+Kafka采集数据,结合跨设备ID关联(设备指纹+用户画像ID),实时存储用ClickHouse(按时间分区、用户ID分桶,行为类型列),离线存储用HDFS+Hive;实时计算用Flink(低延迟状态管理),离线用Spark;可视化用DataV。通过数据校验(时间戳/事件有效性)、冗余存储(Kafka多副本/ClickHouse主从)、容错(Flink Checkpointing)保障准确性与实时性。
2) 【原理/概念讲解】:老师口吻解释各环节。数据采集:前端埋点SDK记录用户行为(注册、购买等),包含用户ID、时间戳、行为类型、属性(渠道、设备),发送到Kafka。跨设备ID关联:用设备指纹+用户画像ID匹配,确保注册到付费的完整路径(比如用户换手机时能关联)。存储:实时流存储用Kafka(高吞吐持久化);离线存储用ClickHouse(时序/宽列优化,支持实时查询,表结构按时间戳分区,按用户ID分桶,行为类型作为列,如user_behavior表结构:partition_date Date, bucket_user_id UInt64, event_type String, ...)。计算:实时用Flink(流处理引擎,低延迟、状态管理,处理实时路径分析,如7天转化率);离线用Spark(批处理引擎,处理历史数据,如月度漏斗图)。可视化:DataV集成内部数据平台,支持实时数据连接和交互式图表。数据准确性保障:用户ID唯一性校验(去重),埋点错误检测(时间戳无效、事件类型异常、属性合理性,如渠道为“app”但设备是“web”则标记异常),冗余存储(Kafka多副本、ClickHouse主从)。实时性保障:Flink算子并行化降低延迟,Kafka缓冲机制,ClickHouse批量写入优化(如每批1000条)。跨设备关联机制类比:就像给每个用户一个“身份证”(用户画像ID),即使换手机(设备指纹变化),也能通过设备指纹+用户画像ID匹配到同一用户,确保路径不中断。
3) 【对比与适用场景】:
| 方案 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 实时计算(Flink) | 流式处理,处理实时数据流 | 低延迟(秒级)、高吞吐、状态管理、容错 | 实时路径分析(如注册到购买的转化率)、实时预警、实时用户分群 | 需处理状态,容错复杂,资源消耗高 |
| 离线批处理(Spark) | 批量处理历史数据 | 高吞吐、支持复杂分析、易调试、延迟较长(小时/天级) | 历史路径分析(如月度转化趋势)、用户分群、长期行为模式 | 延迟较长,不适合实时需求 |
4) 【示例】:前端埋点请求示例(注册后换设备购买,跨设备场景):
前端发送事件:
{
"event": "user_register",
"userId": "u_001",
"deviceFingerprint": "f_abc123",
"timestamp": 1671234567890,
"properties": {
"gameId": "g_123",
"channel": "app",
"device": "Android"
}
}
跨设备ID关联逻辑(伪代码):
def cross_device_match(event):
if 'deviceFingerprint' in event and 'userId' in event:
user_profile_id = get_user_profile_id_by_fingerprint(event['deviceFingerprint'])
if user_profile_id:
event['userId'] = user_profile_id # 统一使用用户画像ID
return event
存储表结构示例(ClickHouse表):
CREATE TABLE user_behavior (
partition_date Date,
bucket_user_id UInt64,
event_type String,
timestamp UInt64,
gameId String,
channel String,
device String,
time_diff UInt32 -- 注册到购买的时间差(秒)
) PARTITION BY toYYYYMMDD(timestamp)
BUCKET BY bucket_user_id
ORDER BY (partition_date, bucket_user_id, event_type)
计算逻辑(Flink处理跨设备路径):
def process_event(event):
if event['event'] == 'user_register':
register_events[event['userId']] = event['timestamp']
elif event['event'] == 'user_purchase':
purchase_timestamp = event['timestamp']
if event['userId'] in register_events:
time_diff = (purchase_timestamp - register_events[event['userId']]) / 1000
save_to_clickhouse(event, time_diff) # 写入ClickHouse
查询示例(实时查询注册后7天购买的用户比例):
SELECT
SUM(CASE WHEN time_diff <= 7*24*3600 THEN 1 ELSE 0 END) AS registered_7d_purchase,
COUNT(*) AS total_registered
FROM user_behavior
WHERE event_type IN ('user_register', 'user_purchase')
AND partition_date >= toYYYYMMDD(now() - INTERVAL 7 DAY)
GROUP BY partition_date
5) 【面试口播版答案】:
“面试官您好,针对用户从注册到付费的转化路径追踪,我设计的系统采用‘实时流处理+离线批处理’双轨架构。数据采集通过前端埋点SDK记录用户行为(注册、购买等),包含用户ID、时间戳、行为类型及属性,发送到Kafka。存储分为实时流存储(Kafka)和离线存储(ClickHouse),ClickHouse表按时间戳分区、用户ID分桶,行为类型作为列,保证查询性能。计算部分,实时用Flink处理流数据,实时计算用户注册到购买的转化路径(如7天转化率),结果写入ClickHouse;离线用Spark处理历史数据,生成漏斗图。可视化通过DataV展示路径图,直观呈现转化瓶颈。为保证数据准确性,采用数据校验(如用户ID唯一性、时间戳有效性、事件类型合理性),埋点错误检测(异常事件标记),冗余存储(Kafka多副本、ClickHouse主从);实时性通过Flink低延迟、Kafka缓冲实现秒级延迟(受资源限制)。跨设备用户ID关联通过设备指纹+用户画像ID匹配,确保注册到付费的完整路径追踪。这样既能实时预警,又能支持历史分析,满足业务需求。”
6) 【追问清单】:
7) 【常见坑/雷区】: