PingCap interview
使用说明和详设在 usage&design.md
中
通过修改最大并发数量即可控制内存使用,若每个 map 任务的文件大小为128MB,则允许的最大并发数为8,考虑到每个线程的内部储存使用,允许的最大并发数应为 6~7(为了便于测试,代码中允许的最大并发数为3)
- 通过修改 GoDistributed 的 nReduce 参数即可更改
100GB url文件,使用1GB内存计算出出现次数top100的url和出现的次数。
注:本程序所有的分布式情况均使用多线程进行模拟
-
面向用户
-
文件输入要求 为多个文件且每个均不超过128MB(数值取自Hadoop2.0)加起来可以达到10GB
-
map/reduce
-
map 将每个URL扩展成为{key, value}的键值对,其中key为url本身,value为1表示出现一次。将处理的所有的键值对根据key进行排序并依据reducer的数量进行划分,产生中间文件
-
reduce 合并相邻的相同的URL,最终其value的值即为这个URL在所有的文件中出现的次数。因为在map阶段对key的集合进行了划分,所以不存在相同的key值分布在不同reducer上的情况。
-
-
-
master 节点
主线程,同时作为 rpc 线程的主机,负责任务调度和监控,同时。与 worker 节点所有的调用都是通过 rpc 服务进行的,避免了调用失败时阻塞主线程的情况。 -
RPC
作为 master 和 worker 的中间层,负责向双方传递消息,所有的 rpc 调用都是异步的。本质是 rpc.Dail 通过双方的 rpc 地址进行信息交换。 -
worker 节点
单独的线程,向 rpc 主机进行注册并汇报任务完成情况。对 worker 线程的调用也是异步的。
-
2.12
明确目标是计算10GB的数据中出现次数top100的URL,但是可用的内存只有1GB,显然需要使用外存,迅速想到之前接触过的mapreduce。在MIT 6.824的课程中曾经进行过word count的实现,且在mapreduce的论文中明确提到这样的技术可以进行URL count 复习了论文并实现了其中单独的 map/reduce 部分和归并函数 -
2.13
实现任务调度函数 schedule,建立 rpc 通信并完成 map/reduce 部分和多线程部分的单元测试,成功通过- 改进schedule的任务分配部分。取消了任务分配通道(chan)的缓存,通过 channel 类型两方都准备好才发生通信的特性完成任务分配
- 改进schedule的线程同步部分。通过统计成功完成的任务数量避免使用sync.WaitGroup(),简化程序结构
-
2.14
改动map部分以适应本次URL统计的需求。将每个URL作为统计的唯一键值,并生成测试数据,共八个文件,其中每个里面包含10000个随机生成的URL,为确保可以有重复的部分,统一使用3位(https://www.xxx.com
)。顺利通过单一worker的测试,生成的数据中出现最多的URL出现了16次,期望为4.55次 在进行分布式测试时发现在schedule中出现死循环,经过go race测试,发现在分配任务到每个worker时稳定出现线程阻塞情况,且每个线程均有相同情况- 没有成功debug
-
2.15
上午通过打log的方式推测其中call函数在包装 rpc.Dial 时出现问题,在同步调用时因为某些问题导致阻塞,使主线程处于挂起状态,但是在查阅文档后发现此处正常 下午继续尝试发现此处的阻塞产生于registerChan中没有数据导致所有的线程都在等待通道内容(即worker的rpc地址)。 通过调用检测发现此处产生了死锁: 产生于schedule(mapreduce/schedule.go)和forwardRegistrations(mapreduce/master.go)- schedule要求有机器地址,待任务完成后将机器重新注册到master处
- forwardRegistrations要求在master注册的可用机器数量大于0时才会分配机器的地址
- 解决方案:在schedule进行任务分配之前对所有worker线程在master处进行注册
===> 不仅要关注函数的运行时情况,还要关注初始化
-
2.16
完成所有代码部分并通过分布式的测试
反思: 在构建分布式情况的函数 Distributed 时,将过多的关注放在了 schedule 部分,忘记了在分配任务后开启 worker,导致在请求 worker 的 rpc地址时出现线程阻塞
完善文档 -
2.17
完成使用说明和详设的文档,开始写架构说明部分 -
2.18
完成全部文档,包括 readme 和 代码注释- 添加了 CI