Hadoop in Action 翻译 第一章
Hadoop介绍
内容简介:
1. 编写可扩展的,分布式的,海量数据处理的程序的基础
2. 介绍hadoop与MapREduce
3. 编写一个简单的MapReduce程序
今天,我们被数据所围绕,人们上传视频,手机拍照,给朋友发信息,更新facebook状态,论坛回帖,点击广告,等等.另外,机器本身也在不停的产生大量数据.甚至也许各位看官就在电脑旁读着电子书,当然,你的购买记录已经记录在书店的系统之中了.
海量数据的不停增长,现在已经给各大厂商带来了极大地挑战.他们需要在以兆记的数据中挖掘出有用的信息,比如哪些网页是大众喜闻乐见的,等等信息.Google是第一个公布使用MapReduce系统来处理他们的快速增长的数据的大型互联网企业。
由于各大厂商也遇到了同样的问题(scaling challenges),我们不可能指望每个遇到这种问题的厂商都自己去开发一套类似与Google MapReduce的产品,所以Hadoop框架迅速引起了大家的关注 .DC 认识到这是一个机会,进而开发了一套开源的mapReduce 系统,也就是我们所说的Hadoop.不久,Yahoo等厂商就迅速投入到这个项目中,支持这个项目.今天,Hadoop 已经成为了很多大型互联网公司的基础技术设施了,其中包括Yahoo Facebook LinkedIn Twitter.特别是很多传统行业也开始使用这个项目,比如传媒,通信行业等.
很快,编写可扩展的分布式数据处理程序将成为很多程序员的重要技能之一.曾经,我们这样定义一个优秀的程序员,他必须懂关系型数据库,会网络编程,安全编程.相似的,不久,分布式数据处理的能力也将成为程序员的重要技能之一了.本书就是知道你如何快速的将hadoop实践到你的数据处理中.
这一章主要介绍hdoop为何构建distributed system,及分布式系统,以及数据处理系统的.它将让你对mapreduce有一个宏观的认识.一个简单的word counting的例子.我们将讨论hadoop的历史,以及
Why “Hadoop in Action”?
实话实说,我第一次被Hadoop引起兴趣之前也饱受hadoop中的例子教程的打击。Hadoop官方文档非常全面,但是却不能够简单明了的解决我们学习中遇到的问题。而此书的目的就是解决这个问题。此书将引导你快速创建hadoop项目,在实践中告诉你什么是hadoop,而不是关注理论细节。
What is Hadoop?
hadoop 是一个帮助开发者构建处理大量数据并发应用的开源框架。分布式是一个很广的领域。而hadoop的主要特征包括:
可接入,易于接入。----Hadoop运行在一个大型集群上,或者运行在一些云服务上,客户端可以方便的接入到。
容错性。---
可扩展性。---
简单---
Hadoop 的可接入性与简洁性使其在分布式程序方面有很大的优势。甚至即便是大学中的学生也可以简单快速的构建自己的Hadoop集群。另外,它的容错性与扩展性使其很适合做Yahoo与Facebook等大型网站的后台服务。所以Hadoop在学术界和工业界都很受欢迎。
理解分布式系统与Hadoop
摩尔定律在过去很多年都正常发挥着作用。但是当大型系统遇到系统需要大规模扩展时,摩尔定律似乎就不再像以前那么准确的发挥作用了。很重要一点是程序很可能部署在很多低性能的或者廉价的机器之上。
了解一下目前流行的大型分布式系统,从目前的IO技术的价格成本方面考虑,一台高性能的服务器有4个I/O channel。每一个I/O channel有100MB/sec的处理能力。那么处理一个4TB的数据集,就会需要3个小时。使用Hadoop,这个数据集,将会被分割微很多小的数据块(一般来说是64MB),这些小块的数据块将会被独立的存放在Hadoop Distributed File System(HDFS)上。而HDFS是建立在许多廉价机器上的一个集群。即便是谦虚的说,服务器集群会提供更加强大的数据读取速度。而且廉价机器集群的成本要比一个高性能服务器的成本低得多。我们所说的廉价机器就是指的PC机。
以前都用hadoop 与传统体系的系统比较,来凸显hadoop的优势。现在,我们用hadoop与其他分布式系统相比教。SETI@home(在家搜寻外星智慧(地外文明---也就是我们常说的“外星人”)),是一个通过互联网利用家用个人计算机处理天文数据的分布式计算项目。该项目试图通过分析阿雷西博射电望远镜采集的无线电信号,搜寻能够证实外星智能生物存在的证据。该项目由美国加州大学伯克利分校的空间科学实验室主办。在SETI@home体系中,一个中央存储单独提同空间与服务器,其通过互联网,将分配好的数据分发给每个家用电脑,每个家用电脑经过计算,再将计算好的数据反馈给中央存储。
Hadoop 不同于seti@home之处在于Hadoop物理指向数据。seti@home将数据反复的传送与中央服务器与各个客户端之间。其中传输成本很大,但是如果是计算密集型的数据,那么这种方式是合适的,而hadoop处理的是数据密集型的数据。hadoop处理的数据本事都是非常巨型的。根本无法像SETI@home这种方式将数据在集群中自由的传输。Hadoop关注于移动代码而不是vice versa.对比图1.1。,我们看到数据与计算都在hadoop集群内部.客户端只是发送MapReduce程序去执行,并且这些程序常常很小.在hadoop集群中移动的是代码而不是无理数据本身数据.数据被分解并分布在集群之中.而且尽可能的每一片数据的处理都集中在一台相同的机器上,既数据数据都在本地处理.
这种传递代码,而不是传递数据的做法就是hadoop针对数据密集型程序所做的特殊设计.程序运行的代码都是短小精悍的而且易于传输的.每次都将要运行的代码传输到数据所在的机器.这样就可以不去动已经保存在机器上的数据了.
Now that you know how Hadoop fits into the design of distributed systems, let’s see
how it compares to data processing systems, which usually means SQL databases.
SQL 数据库 VS. Hadoop
Hadoop是一个数据处理的框架,对于高负荷的数据处理,什么使其优于传统的关系型数据库呢?
其中一个原因就是 SQL是用来处理结构化的数据.而hadoop 使用场景往往是非结构化数据,比如text文本数据.从这个观点出发,hadoop提供了more general paradigm than SQL.如果处理的是结构化数据,那么hadoop与SQL数据库的差别是微小的.理论上,SQL和Hadoop都可以处理,作为一种查询语言,也可以在hadoop之上实现一套SQL查询语言,并将其作为数据操作引擎.但是在具体实践中,SQL数据库基本上都已经有很多年的传统了.有一些老牌的数据库提供商,为很多历史悠久的软件提供服务.这些已有的数据库都无法解决hadoop所针对的那些问题.
(略)
理解Hadoop
你也许很喜欢像pipelines和消息队列这样的数据处理模型。这些模型再开发数据处理程序时发挥这很重要的作用。最有名的pipeline是Unix pipes。Pipelines可以复用处理单元;其可以简单的将现有的模块与新模块相链接。消息队列可以异步的处理消息单元,程序员可以控制生产者或者消费者,而其执行时间由系统控制。类似的,MapReduce同样是一个数据处理模型。而其最大的优点在于可以在多台电脑上延展你的数据处理。在此模型之下,数据处理单元称之为mapppers和reducers。其在内部将数据处理程序分解为mappers和reducers。一旦你使用MapReduce编写你的数据处理程序,将其扩展为一个成百上千台机器上的集群只不过是修改一些配置那么简单而已。简单快速的扩展性正是那么多程序选择MapReduce模型的原因。
1.5.1 Scaling a simple program manually
在正式进入MapReduce之前,我们通过一小段练习,来处理一个大型的数据集,并扩展这个程序。你将看到扩展这个程序的挑战,并且将欣赏MapReduce在扩展性方面给开发人员带来的好处。
这个练习就是计算在一个文档中出现每个单词出现的次数。在这个例子中,我们待处理的文档中只有一句话。
Do as I say, not as I do.
我们将调用这个小例子
define wordCount as Multiset;
for each document in documentSet {
T = tokenize(document);
for each token in T {
wordCount[token]++;
}
}
display(wordCount);
程序将遍历所有文档,在每个文档中,将是用tokenization程序一个一个等计算单词出现的次数。最终display方法将wordCount打印出来。这个程序将运行正常,知道你要处理的文件越来越大。
比如说,你要建立一个垃圾邮件过滤器,过滤所有的邮件,以便于统计数以百万记的垃圾邮件中每个词汇出现的频率。你将使用数台服务器遍历所有的文档。每台机器处理不同的文件。当所有的服务器完成这项工作,下一步就是将收集说有服务器上的处理结果。之前看到的伪码,将被部署到多台服务器上,我们将会吧wordCount定义为一个集合,用来存储多台服务器上的运算结果。
第一部分处理单元的代码为:
for each document in documentSubset {
T = tokenize(document);
for each token in T {
wordCount[token]++;
}
}
sendToSecondPhase(wordCount);
第二部分处理单元为:
define totalWordCount as Multiset;
for each wordCount received from firstPhase {
multisetAdd (totalWordCount, wordCount);
}
看上去,这并不难,但是一些细节问题将会阻碍它像我们想象中的运行。
首先,我们忽略了读取文件的性能。如果所有的文件存储在一个中央存储服务器上,那么这台服务器的总线带宽将成为一个传输瓶颈。更多的数据处理服务器将提升数据处理的能力,但是数据存储服务器并不能一直维持性能,因为它有限的带宽无法及时的将需要处理的数据发往各个数据处理服务器上去。所以我们需要先将这些文件分分别存到各个数据处理服务器上去。这样当各个数据处理服务器需要处理数据时,就不用再从中央存储服务器上获取文件了。特别要重申的是,对于数据密集型应用程序来说,将数据存储与数据处理放置在统一台服武器上,是非常重要的。
另外一个问题就是最终的结果集存储在内存中。当数据量超大时,请不要将数据结果集存放在服务器内存中,这样做很可能会超出内存数据存储的极限。比如wordCount中不仅仅只是存储英文单词,还包括所有可能存在的字母组合,所有其数据集的大小很难把握。
Ok,wordCount也许不太适合存储在内存中了;我们将不得不修改我们的程序,将其存储在硬盘中。这意味着我们将实现一个基于硬盘的hash table,这意味着我们将写大量的代码。此外,我们的第二部分处理单元(就是汇总所有处理结果的部分)只有一台服务器,这的确显得有点笨拙。特别是如果我们在第一部分处理单元中使用多台服务器用于处理数据,我们的第二部分处理单元(就是汇总所有处理结果的部分)必将成为一个瓶颈。此时我们理所应当的想法就是以分布式的形式,使用多台服务器处理这部分数据。为了在这部分数据处理中使用分布式,我们就需要将数据分割,以便与在多台服务器上独立计算。你需要将第一部分处理完的数据以某种形式分割,比如现在有26台服务器用于处理第二部分,那么你就可以按照首字母的顺序,将所有结果集分为26个部分,将其分布到26台服务器上进行第二部分的处理,这26台服务器中的每一台服务器都处理以某个大写字母开头的单词。不同与单机版的wordConunt,此时我们将有26个wordCount: wordCount-a, wordCount-b等等。此时,我们要对第一部分处理单元做一下调整。当第一部分数据处理时,将数据按照首字母分割一次。这样将其处理完毕后,每台处理第一部分数据的服务器都会将wordCount-a 发往处理A字母开头的单词的服务器上去。以此类推,每台处理第二部数据单元的服务器都会处理一个字母开头的单词。终于,这个分布式的计数器程序就可以完工了。为了使其工作在分布式集群上,我们需要增加或者修改一些处理流程:
1. 再多台服务器上存储并处理数据。
2. 在硬盘上存放数据的处理结果,而不是内存中。
3. 将第一部分的数据结果集在每台服务器上先分割好,以备于第二次数据处理时用。
4. 将第一部分处理好,并分割好的数据分发给第二部分数据处理单元的机器集群。
靠,我们只是想做一个简单的单词计数器,竟然要高的如此复杂,这还没有考虑容错问题呢。这也就是为什么我们需要hadoop这种框架的原因了。
Scaling the same program in MapReduce(待续)
MapReduce programs are executed in two main phases, called mapping and reducing.
Each phase is defined by a data processing function, and these functions are called
mapper and reducer, respectively. In the mapping phase, MapReduce takes the input
data and feeds each data element to the mapper. In the reducing phase, the reducer
processes all the outputs from the mapper and arrives at a final result.
In simple terms, the mapper is meant to filter and transform the input into something
that the reducer can aggregate over. You may see a striking similarity here with the two
phases we had to develop in scaling up word counting. The similarity is not accidental.
The MapReduce framework was designed after a lot of experience in writing scalable,
distributed programs. This two-phase design pattern was seen in scaling many programs,
and became the basis of the framework.
In scaling our distributed word counting program in the last section, we also had to
write the partitioning and shuffling functions. Partitioning and shuffling are common
design patterns that go along with mapping and reducing. Unlike mapping and
reducing, though, partitioning and shuffling are generic functionalities that are not too
dependent on the particular data processing application. The MapReduce framework
provides a default implementation
that works in most situations.