面试题答案
一键面试实现思路
- 数据读取:使用HBase InputFormat读取HBase中的用户行为数据,将每行数据解析为包含用户ID、行为时间、行为类型的键值对。
- Map阶段:
- 输入:键为行键(可忽略),值为HBase一行数据。
- 处理:解析数据,提取用户ID作为键,一个固定值(如1)作为值输出。这样每个用户行为记录都输出为<用户ID, 1>。
- 输出:<用户ID, 1>键值对。
- Reduce阶段:
- 输入:<用户ID, [1, 1, ...]>(同一个用户ID对应的所有1组成的列表)。
- 处理:对值列表进行累加,得到每个用户的行为频率count。将<用户ID, count>键值对输出。
- 输出:<用户ID, 行为频率>键值对。
- 排序输出:在Reduce输出后,使用一个额外的MapReduce作业,将<用户ID, 行为频率>键值对中的行为频率作为新的键,用户ID作为值,重新进行排序输出,得到按行为频率排序的结果。
处理数据倾斜的方法
- 加盐处理:
- Map阶段:在解析出用户ID后,给每个用户ID随机添加一个前缀(如0 - 9的数字),形成新的键。这样原本相同用户ID的数据会分散到不同的键上。例如,原用户ID为
user1
,可能变成0_user1
、1_user1
等。 - Reduce阶段:在Reduce输入时,去掉前缀,恢复原用户ID进行累加计算行为频率。
- Map阶段:在解析出用户ID后,给每个用户ID随机添加一个前缀(如0 - 9的数字),形成新的键。这样原本相同用户ID的数据会分散到不同的键上。例如,原用户ID为
- 预聚合:
- Map阶段:在Map端对同一用户ID的数据先进行局部聚合,例如将<用户ID, 1>聚合成<用户ID, n>,n为该Map任务中该用户ID出现的次数。
- Reduce阶段:对Map端聚合后的结果再进行最终聚合,得到每个用户的总行为频率。这样可以减少数据传输量,缓解数据倾斜。
- 动态负载均衡:
- 在MapReduce运行过程中,监控每个Reduce任务的负载情况。
- 如果发现某个Reduce任务负载过高(数据倾斜),将该任务中的部分数据拆分出来,分配给其他负载较低的Reduce任务进行处理。这可以通过自定义的分区器和调度器来实现。