MapReduce
分布式计算思想
思想引入
首先, 来看三个问题:
-
假设有1T的文件, 文件中的每一行都是一个数字; 如何在一台48core, 64G内存的服务器上处理这个大文件, 将这个大文件排序呢?
-
假设有两个很大的文件(内存只能读入一小部分), 文件中的每一行都是一个url字符串, 共有10亿行. 如何在一台48core, 64G内存的服务器上处理这两个大文件, 将这两个大文件中相同的url找出呢?
-
在一座山上有三个山头, 每个山头都有红木, 橡木和樟木, 有三个工人分别负责在一个山头砍树, 砍好的树木由三辆分别运送红木, 橡木和樟木的运输车运送到位于其他地方的三家加工厂, 这三家加工厂分别加工红木, 橡木和樟木. 整个处理流程应该是怎样的?
1. 对于第一个问题, 这个1T的文件是无法完全读入内存中, 那么我们应该怎么做呢? 可以想到的是, 将这个大文件按行从上而下分割成一个个小文件分别读入服务器内存中处理, 服务器对每一个小文件进行排序, 最后再将每个内部有序的小文件进行归并排序, 从而产生一个有序文件.
整个过程的流程图如下:
虽然上述流程能够完成需求, 但是它存在一个问题----三次磁盘IO(第一次是切割文件时需要读写一次, 第二次是服务器排序时读写一下, 第三次是在归并排序时读写一次). 像这种磁盘IO是非常耗时的, 从而使得处理效率降低. 有什么地方可以改善吗?
答案是有的. 关键就在于第一次怎么切割, 第一次切割时, 去限定每个小文件的数值范围, 比如说第一个小文件的数值范围是0~100, 第二个是101~200, 以此类推. 这样当服务器对每个小文件内部排好序时, 只需将这些小文件拼接即可.
整个过程的流程图如下:
上述流程相较于第一种减少一次IO(归并排序的IO), 从而提高处理的效率.
2. 对于第二个问题, 还是要让整个过程只有两次磁盘IO. 首先要知道每一个字符串对应一个HashCode编码. 假设这两个文件都要拆成1000个小文件. 那么切割策略就有了: 先将每一个url的HashCode编码计算出来, 然后将这个值与1000取模, 每个" 模值 " 作为一个小文件的标识. 那么, 两个大文件中相同的url一定在模值相等的切割后的小文件中.
整个过程的流程图如下:
上述流程是一台服务器再处理, 假设现在有1000台服务器, 试想会是什么样情景呢?
整个过程的流程图如下: