3.5任务粒度
我们把map阶段细分为M片,把reduce阶段细分为R片,正如上面描述的那样,理想情况下,M和R都必须比worker的数量要大。使得每一台机器执行很多不同任务容易做到动态负载均衡,而且当一个worker出现故障的话恢复的速度也会提高:很多已经完成的map任务已经被传输到所有其他的工作机器上了。
对于M和R究竟有多大在我们的实现中具有实际的边界。因为master要做复杂度为O(M+R)调度决策,因此要保存O(M×R)个之前描述的状态在内存中(使用内存的常量系数很小然而对于每一个map任务和reduce任务的状态需要接近1个字节组成)。
此外,R是经常被用户限制的因为每一个reduce的输出都是在一个隔离的输出文件中完成。在实际中我们趋向于选择M使得每一个独立的任务都是16M在64M的输入数据(这样会使得之前描述的局部性优化最有有效),并且我们使得R是我们期望使用的worker机器的倍数。我们经常运行mapreduce在M=200,000, R=5,000, 在2000台机器集群上进行运算。
3.6备份任务
导致mapreduce操作的总时间延长的一个最常见的原因是一个“掉队的人”,也就是一台消耗了不正常时间去完成了计算中的map或者reduce任务的一台机器。掉队者出现的原因有很多,比如,一台具有坏硬盘的机器可能会经历频繁的错误校正使得读速度从30MB降低到1MB。集群调度系统可能已经在机器上调度了其他的任务,导致因为CPU,内存,磁盘,网络带宽等资源竞争而是的运行mapreduce任务的效率低下。我们经历的是一个常见问题是一个在机器初始化代码导致处理器缓存失效的bug:收到这样干扰的机器的运行速度会降低到原来的1/100。
我们有一种通用的机制缓和掉队者问题。当一个mapreduce操作接近结束,master调度会备份还在运行中的任务的执行。任务会被标记结束无论是原来的或者是备份的执行结束。我们协调了这个机制所以它一般使得使用的计算资源的增加很小的百分比。我们发现这很有效的减少了完成大规模mapreduce任务的时间。作为一个例子,排序程序在章节5.3中描述的消耗了44%的更多时间如果没有开启备份任务算法。
4.改进
计算基本函数只需要通过简单的写map和reduce函数来提供,这样也是最有效和最需要的,我们发现有用的扩展很少,在下面都会提到。
4.1划分函数
Mapreduce的使用者定义了他们期望的reduce输出文件的数量,数据被划分到任务通过划分函数对中间key运算。一个默认的划分函数是使用哈希(hash(key)mod R)。这个事实上会导致平衡性不好的划分。在一些情况下,通过key的其他函数划分数据会更有效。比如,我们希望在同一台主机的全部条目能写在同一个输出文件中。为了支持像这种情况,mapreduce库的使用者能提供一个特殊的划分函数,比如,使用“Hash(urlkey)MOD R”作为划分函数,这样能使得具有相同主机的URLs会输出在相同的输出文件中。
4.2顺序保证
我们保证在一个给定的划分函数中,中间的key/value对是按照key的升序处理的。这样的顺序保证了在每一个划分的输出文件有效很容易排序,这样对于支持输出文件格式需要根据key支持有效随机访问,或者输出的用户发现排序很方便。
4.3结合函数
在一些情况下,每一个map任务产生的太多的的中间key的重复,并且用户指定的Reduce函数是连续和关联的。一个很好的例子就是2.1中的单词计数例子,因为单词频率趋向于Zipf函数,每一个map任务将会产生成百上千的记录就像(the,1)这种形式,所有的这些计数都将通过网络传递到一个单独的reduce函数然后通过reduce函数加在一起来产生一个结果。
这个联合函数在运行在每一台执行map任务的机器上面。典型地相同的代码被用来实现联合函数以及reduce函数。联合函数和reduce函数唯一的区别是mapreduce库处理函数的输出结果的方式不同。Reduce函数的输出结果是写入到最终的输出文件而联合函数的结果是写入一个中间文件将被传递到reduce任务。
局部联合很大程度上加快了mapreduce操作的类,附录A包含了一个使用联合函数的例子。
4.4输入和输出的类型
Mapreduce库提供了对读取输出数据是不同格式的支持,比如,text模式输入将被当成每行是一个key/value对。Key是文件中的偏移而value是行的内容。另外一个常见的支持格式存储了通过key排序后的key/value对。每一个输入类型实现知道怎么把他自己分片成为有意义的取值范围然后作为分隔的map任务处理。用户能添加对新输入类型的支持通过提供一个简单的reader接口,尽管很多用于只使用预定义的输入类型中的很小一部分。
一个reader不需要提供从一个文件读取数据,例如,很简单定义从一个数据库读取记录,或者是从数据结构映射到内存。
在一种相似的类型中,我们通过提供不同类型支持一个输出类型的集合,并且用户代码很容易添加对新的输出类型的支持。
4.5副作用
在一个情况下,mapreduce的用户发现从map和reduce算子中提供辅助文件作为额外的输出文件是很方便的。我们依靠应用编写者去使得副作用原子化和幂等。典型的应用写一个临时文件并且原子性重命名这些生成的文件一次。
我们没有提供对于单个任务的原子化的2阶段多个输出文件提交。因此,任务产生多个输出文件并且存在跨文件约束必须是确定的,在实践中这个约束不是一个问题。
4.6跳过坏的记录
4.7局部运行
4.8状态信息
4.9计数器
由于时间问题暂时没有仔细看下去了,到时再整理一下吧