从M哥的一道面试题说起
问题
你有一个社区需要管理,现在要开发点赞和显示点赞数量的功能,社区的使用人数很多(日活超过100w),同时点赞的次数也很多(每天人均点赞100次).
已知点赞的消息存储在消息队列中,应该如何设计分布式统计点赞的功能?
先分析下问题
- 每天的点赞量超过1亿的量级,分布式设计是必须的,单核早爆炸了.
- 存储层的事情肯定是需要支持持久化存储,可以用mysql+缓存层
- 需要考虑容错问题和幂等问题
- 消息消费应该按照批次进行,单条消息处理耗费太高.
面试同学的给的答案
- 批量消费数据,消费完成后通过ack确认
- 程序是原子的,当出现计算异常时回滚已经造成影响的操作
- 程序设计为幂等,当出现网络问题重入时计算结果不受影响.
面试同学答案存在的问题
- ack确认可能导致当消息未被正常消费时不再启动重新计算
- 原子性程序成本非常高,同时需要对回滚操作也加上异常处理,事实上的事务是很难保证的
可能的解决方式
- 需要有 master 节点通过记录消费情况来调度worker
- 通过判断 worker 的心跳来考虑是否需要任务重发
- 单个 worker 程序完整地处理的所需要的工作时再执行对后端缓存/DB的写入,临时数据存在内存里或者本地的存储里.同时通知 master 这部分数据已经完成了处理.
所以核心是什么呢? 当可接受的数据量是单机的100倍甚至更多时,如何用 分片+调度 解决数据的处理问题
言归正传
理解了上面的问题对于理解mapreduce有很多帮助,今天我们主要关注 mapreduce 的分布式处理思想.只讨论理论上的问题,框架和使用不在考虑范围.
论文地址
英文版论文地址:static.googleusercontent.com/media/resea…
中译版论文:developer.aliyun.com/article/318…
核心问题:大数据量时如何进行数据处理
核心概念
- data 待计算的源数据,数据类型为<k,v>
- master master程序负责进行任务分配,当然,为了保证分配的合理性,功能会更复杂.
- worker
执行任务的程序,负责执行map方法或者reduce方法.
4.1 map方法
map(k1,v1) ->list(k2,v2)
4.2 combine方法
combine(list(k2,v2)) -> (k2,list(v2))
5. reduce方法
对map的结果进行处理
reduce(k2,list(v2)) ->list(v2)
流程
- 待处理的数据存储在磁盘上
- master分配map任务的worker,每个map任务去指定的数据位置取数据
- map函数的计算结果存放在内存或是本地的磁盘
- 通过combine过程对map的结果进行合并处理,相同key的被聚合
- 分配reduce程序对聚合后的mapRes进行reduce函数的处理
- 结果写入本地的磁盘
- 完成
举例
我们参照论文中的举例:统计文本中词语的出现次数为例子,看下一次完整的流程是怎么样的.
小结一下
我们今天暂时不去深究mapreduce的实现,只关注其中的对于大数据量的情况使用分片的逻辑进行处理的思路.