一、Map&Reduce起源
MapReduce最早由Google提出,论文出处《DEAN, J., AND GHEMAWAT, S. MapReduce: Simplified data processing on large clusters.》,有兴趣的话可以去看看原文,当然也有翻译。这篇文章和Google的《Bigtable: A Distributed Storage System for Structured Data 》是同期的,是Google对外介绍自身大规模数据处理架构的论文。
MapReduce受Lisp等函数式编程语言的Map 和 Reduce 语义启发,关于函数式编程语言,笔者了解的不多,关于其最主要的一点,是由程序运行时负责程序的调用、执行等,理解这一点很重要,因为由运行时负责调用是MR的核心,用户不需要去关心程序如何实现,它的规模多大,如何并行计算,多少个线程等等,用户只需要关心它们的语义,并按照语义去写Map函数和Reduce函数即可。
二、Map&Reduce
Map 也即映射,将一个或多个数据源映射为key-value样式
Reduce 也即归纳,将Mapper的Key-value进行计算,以得出结果(同为key-value样式)
总体而言非常好理解,但也因此容易引出个问题——Why?它与sql的select from where 有什么区别呢?Mapper也要筛选,Reducer也要计算。因为现在很多语言和数据库都引入了MR,这一问题变得尤为明显,本来它只是在大规模数据集群上计算,实在不理解还能用,“哦,框架就是这样”搪塞过去,现在不行了。
这个问题也困扰过我,现在我的理解是一点——交集。很多数据会符合一堆规则,如果单独的按照这些规则,一个一个挑出来,会造成重复计算,重复IO——很多时候符合条件A的数据也符合条件B,如果采用类似先计算选出选A,再选B的方式,则会有2次IO访问或是重复计算,浪费了算力(自然也省了内存),但当数据量大到一定的程度,节省下来的内存便进入长尾效应,而且对计算速度的拖累也更大,综合考虑下来,MR先使用Mapper无脑选候选数据,再使用Reducer计算更符合效率和成本。
三、Hadoop的Map Reduce。
关于DFS——Distributed File System.分布式文件系统,是Hadoop HDFS 的核心,也即基础设施,在面对大规模数据时,有这样2点重点,一是,省钱,二是,安全。对于这点Google提出的观点是,假设我买出错率很高的硬盘,1/1000,那么当我有3台这样的硬盘,它们同时出错的概率是多少呢?1/1000*1/1000*1/1000=1/1000000000,变得可接受了,而且廉价硬盘也带来了成本的下降,这样的文件系统就可以作为大数据的基础设施。
Hadoop(Hive)的MR是建立在HDFS之上的,原理也非常简单粗暴,读入文件,然后借助MR框架,去大规模并行计算。Now,MR理论上可以接受任何输入,但本着开箱即用的道理,绝大部分人还是会选择从文件中读取,然后进行计算,这样的话,瓶颈就会在IO上面,并行计算的算力也没被解放开来。
想要MR为你的计算实时服务,你就需要很多Wrapper从你的库中获取数据源,或者加速文件的读取,所以后面Hadoop萌生出那么多框架,也是有原因的。
同时提到这句话,笔者注意到的一点是,在Google BigTable 论文中提到的Big Table是支持MR的,在其论文中有这样一句话
Bigtable can be used with MapReduce [12], a framework for running large-scale parallel computations developed at Google. We have written a set of wrappers that allow a Bigtable to be used both as an input source
and as an output target for MapReduce jobs.
后续Hadoop的山寨版——Hbase,虽然也支持,不过貌似效率不高,更多的还是用Hive进行使用,而且在程序中,基本还是对HDFS的直接操作。对于Hbase而言,反而更像是绕了远路,HDFS上的HFile读取,然后到Hbase,再传到Mapper里面,性能怎么样更多的还是看你,或者Hbase的优化,因为这下连文件都看不到了。Google也不傻,既然提了这一说,那么BigTable底层实现和Hbase的区别,相比是很大的。
回顾完上面这些,不难发现,Hadoop,起码早期版本,就是一个空荡的平台,这也为后续一堆框架的提出埋下了伏笔。
四、MongoDB的MapReduce
提到MongoDB,这个后起之秀,就想起了一篇文章,《一个时代的终结——大数据已死》
Hadoop还面临这样的挑战:NoSQL数据库和对象存储提供商在解决Hadoop最初旨在帮助解决的部分存储和管理难题方面取得了进展。随着时间的推移,在Hadoop上支持业务连续性面临挑战,加上支持实时、地理空间及其他新兴的分析使用场合方面缺乏灵活性,这使得Hadoop面对海量数据时很难在批处理之外大有作为。
个人觉得文章写的还是不错的,每个新兴技术的出现都必将经历一波炒作,再到冷却,直至它作为广大技术栈中不起眼(基础)的一隅,凡事总要经历个过程,大数据已死是失去了热度,它已作为基础能力,不再适合被大书特书。
回到MR上面来,笔者目前的项目呢,也是烂大街的Hadoop,对于MR的使用可以说是反面教材了,对数据集的中间结果处理使用了大量的 temp文件。而且还使用的是最简单最低效的TextFormat,每次mr都有大量的parse,作为程序员脑中的基础概念,关于程序的性能主要就几点,一个是IO,一个是算力(Taraflops),减少IO和不必要的计算是时刻记住的重点,而这项目可以说2点禁忌全占了。而我如果想改,其实不光是改MR的逻辑,还要改HDFS里文件的存储方式,这样一来以新版和旧版为分界线,就需要一个Adapter来做老数据的读取……
那这样一来问题其实很明显,Hadoop本身就有纷繁复杂的技术栈, Hive,Spark,Hbase,Accumulo,Kylin,Storm ……要保证项目组的每一个人深刻理解这一堆技术栈,非但要调研成本,而且一旦换需求了,是不是还要对应改动呢?而且为了满足一些实时性的需求,还不得不从Hive MR到HBase,再入redis以提供大规模低时延调用。对于很多时候,只想要使用MR而已,又何苦这么麻烦呢。
在这种情况下,像MongoDB这样的库就提供了一个折中的办法,它不支持超大规模数据量的分析,这种情况下性能堪忧,但是对于大规模(SQL已经自闭)的程度还是OK的,通过MongoDB 的MR,我们仍然能借助MR思维去处理大规模数据,如果不是长期存储的类型,MongoDB给出的方案反倒更为经济。
五、其他语言实现的MapReduce
(一)、 Java
Java自1.8之后引入了Stream API,Map和Ruduce也作为同期被引入,与Hadoop的MR不同,它只能作为 Collection 接口下的方法,并不支持对每个Key,value进行计算,而只能得出一个结果。而它的重点在于,如果使用了 parallelStream() ,便能轻松地执行并行化计算。
List<Integer> source=new ArrayList<>(); source.add(1); source.add(2); Optional<Integer> sum=source.stream().map(new Function<Integer, Integer>() { @Override public Integer apply(Integer t) { return t+1; } }).reduce(new BinaryOperator<Integer>() { @Override public Integer apply(Integer t, Integer u) { return t+u; } }); System.out.println(sum.get());
(二)、Javascript
待续。