第一章 核心技术
在2002年,那时候World Wide Web相对还是比较新颖的,而且在用“谷歌”查询东西以前,Doug Cutting和Mike Cafarella想通过爬取网站,并为内容建立索引来建立一个Internet搜索引擎。为了这件事情他们启动了一个叫Nutch的工程,但是这个工程需要一个可伸缩的方法来存储内容的索引。在2002年组织存储数据的标准做法是用关系型数据库管理系统(RDBMS),它可以用一种称为SQL的语言进行访问。但是几乎所有的SQL和关系型存储都不适用于Internet的搜索引擎存储和检索。它们的成本相当高,但是又不那么可伸缩,又没有提供容错的需求,可能不能提供预期的性能。
在2003年到2004年,Google发布了两篇论文,一篇关于Google文件系统(Google File System),另一篇是关于在集群服务器上编程模型,称为MapReduce。Cutting和Cafarella将这些技术应用在了他们的项目中,实际上Hadoop就产生了。Hadoop不是字母的缩写,而是在某种程度上是,图标是一个可爱的小象。Yahoo!开始用Hadoop作为基础的搜索引擎,很快就传播到了其他的组织机构。现在Hadoop主要是大数据平台。关于Hadoop详情的描述有很多资源;这里我们找到了一个简要:
Hadoop由三个主要部分组成:
- Hadoop分布式文件系统(HDFS)
- MapReduce编程平台
- Hadoop生态系统,它是一系列工具的集合,可以用于除了MapReduce和HDFS做数据的存储和组织,并且能够管理运行Hadoop的机器。
这些机器被称为一个集群——一组服务器,基本上都是运行各种版本的Linux操作系统——一起工作完成任务。
Hadoop生态系统包含一些模块,这些模块可以帮助进行系统编程,管理配置集群,管理集群中的数据,管理集群的存储,任务分析等工作。本书的主要内容将描述生态系统的组件和相关的技术。
Hadoop分布式文件系统(HDFS)
许可证:Apache License, Version 2.0
活跃度:高
目的:高容量,容错,低成本存储大的数据集
官方地址:http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html
Hadoop集成:完全集成
Hadoop分布式文件系统在Hadoop集群中,在这里可以存储数据。建立数据密集型的应用,Hadoop的设计是运行在廉价的商用服务器上的。HDFS的优化是用于高性能,读密集型操作,并能在集群中进行错误复原。它不能避免错误,但是不太可能丢失数据,因为HDFS的错误对每一个数据库都做了多个备份。而且HDFS是一个一次写入,多次读取的文件系统:一旦一个文件被创建,那么文件系统的API就只允许你对这个文件进行添加,不允许覆盖。这样的结果就是,HDFS通常不适用于一般在线事务处理(OLTP)应用。HDFS的大多数都是用于对大文件的顺序读取。这些文件分为大块,一般为64MB或者更大,这些块都分布在服务器的节点上。
HDFS不是你在Linux,Mac OS X或者是一些Windows平台上看到的POSIX兼容的文件系统(看在*对POSIX的简要解释)。它不是由服务器上节点的操作系统内核进行管理的。HDFS中的块映射到主机中底层的文件系统中的文件,通常是Linux系统的ext3。HDFS没有假设主机中的底层磁盘由RAID做了保护,所以默认的是每个块都有三个拷贝,并放在集群的不同节点上。这就提供了数据丢失的保护,当节点或者磁盘出错并帮助访问数据,而不是通过网络来访问。
虽然解释超过了这本书的范围,HDFS中的文件元数据的是通过NameNode进行管理的,Hadoop相当于Linux/Unix超级块。
教程链接
通常你需要用像Hive或者Pig这样的工具与HDFS进行交互。也就是说,想要直接在HDFS上工作还是需要时间的。Yahoo!已经发布了一个非常棒的关于配置和浏览基本系统的指导。
示例代码
当你用Hadoop客户端的命令行接口(CLI)的时候,你用下面的代码片段拷贝一个本地的文件到HDFS,然后看下前十行:
[hadoop@client-host ~]$ hadoop fs -ls /data
Found 4 items
drwxr-xr-x - hadoop supergroup 0 2012-07-12 08:55 /data/faa
-rw-r--r-- 1 hadoop supergroup 100 2012-08-02 13:29 /data/sample.txt
drwxr-xr-x - hadoop supergroup 0 2012-08-09 19:19 /data/wc
drwxr-xr-x - hadoop supergroup 0 2012-09-11 11:14 /data/weblogs
[hadoop@client-host ~]$ hadoop fs -ls /data/weblogs/
[hadoop@client-host ~]$ hadoop fs -mkdir /data/weblogs/in
[hadoop@client-host ~]$ hadoop fs -copyFromLocal
weblogs_Aug_2008.ORIG /data/weblogs/in
[hadoop@client-host ~]$ hadoop fs -ls /data/weblogs/in
Found 1 items
-rw-r--r-- 1 hadoop supergroup 9000 2012-09-11 11:15
/data/weblogs/in/weblogs_Aug_2008.ORIG
[hadoop@client-host ~]$ hadoop fs -cat
/data/weblogs/in/weblogs_Aug_2008.ORIG \
| head
10.254.0.51 - - [29/Aug/2008:12:29:13 -0700] "GGGG / HTTP/1.1"
200 1456
10.254.0.52 - - [29/Aug/2008:12:29:13 -0700] "GET / HTTP/1.1"
200 1456
10.254.0.53 - - [29/Aug/2008:12:29:13 -0700] "GET /apache_pb.gif
HTTP/1.1" 200 2326
10.254.0.54 - - [29/Aug/2008:12:29:13 -0700] "GET /favicon.ico
HTTP/1.1" 404 209
10.254.0.55 - - [29/Aug/2008:12:29:16 -0700] "GET /favicon.ico
HTTP/1.1"
404 209
10.254.0.56 - - [29/Aug/2008:12:29:21 -0700] "GET /mapreduce
HTTP/1.1" 301 236
10.254.0.57 - - [29/Aug/2008:12:29:21 -0700] "GET /develop/
HTTP/1.1" 200 2657
10.254.0.58 - - [29/Aug/2008:12:29:21 -0700] "GET
/develop/images/gradient.jpg
HTTP/1.1" 200 16624
10.254.0.59 - - [29/Aug/2008:12:29:27 -0700] "GET /manual/
HTTP/1.1" 200 7559
10.254.0.62 - - [29/Aug/2008:12:29:27 -0700] "GET
/manual/style/css/manual.css
HTTP/1.1" 200 18674
MapReduce
许可证: Apache License, Version 2.0
活跃度: 高
目的: 处理大数据的编程范例
官方地址: https://hadoop.apache.org
Hadoop集成: 完全集成
MapReduce是第一个,也是最主要的在Hadoop上开发应用的编程框架。你需要用Java利用MapReduce的原生形式。你应该学习单词计数(WordCount),Hadoop的“Hello, World”。代码自带标准的分布式。这是单词计数问题:你有一个数据集,这个数据集包含一个大的文件集合,目的就是得到一个所有单词的列表,还有它们在数据集中出现的次数。
MapReduce工作的Java代码包括mapper和reduce两个部分。由Hadoop Software精心策划,每个mapper都给一打数据进行分析。假设它得到这么一个句子:“The dog ate the food.”。它会产生5个名字-值对或者map:“the”:1, “dog”:1, “ate”:1, “the”:1, and “food”:1。在名字-值对中的名字就是单词,值就是这个单词出现的次数。Hadoop接受了map的任务并得出结果,然后进行排序。对于每一个map,都要建立一个哈希值并赋给它,然后是reduce称为洗牌(shuffle)。Reducer过程在它的输入流中可以将map中每个单词做加和,并且产生一个排过序的单词列表。你可以认为mapper是将HDFS中的文件抽取到map中,然后reducer再将从map中输出的结果进行整合。下面的教程链接部分对此作了详细的说明。
当你知道很多困难的工作——将输入的数据集分割,分配mapper和reducer给节点,打乱从mapper到reducer的数据,并将最后的结果写到HDFS——是Hadoop自己全部管理的时候,你会感到欣慰的。程序员只需要写map和reduce函数就行了。Mapper和reducer一般来说都是用Java写的(比如在这部分引用的例子),写MapReduce代码对于新手来说是一件了不起的营生。在最后,开发更高级的结构做这些事情。Pig就是一个例子,它将在后续的内容中进行讨论。Hadoop流是另外的内容。
教程链接
关于用MapReduce工作的优秀教程有很多。一个很好的起步就是Apache官方文档,但是Yahoo!也已经方了一个指导模块。在MapR(一个商业软件公司建立Hadoop分布式)中有一个关于写MapReduce非常棒的演示。
代码示例
写一个MapReduce是相当复杂的,而且也超出了本书的范围。一个典型的应用就是通过一个简单的单词统计做起步。官方文档包含了创建这个应用的教程。
YARN
许可证: Apache License, Version 2.0
活跃度: 中
目的: 处理
官方地址: https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/YARN.html
Hadoop集成: 完全集成
当许多人考虑Hadoop的时候,他们只是考虑两个相关的技术。这两个技术是Hadoop分布式文件系统(HDFS),这里可以存储文件,另一个是MapReduce,这个可以对你的数据进行操作。虽然MapReduce对于某类任务是非常有效的,但是其他类型的任务可能就行不通了。这就断裂了生态系统,Hadoop外围的各种工具就生存尝试与HDFS进行通信。
在2012年5月,Hadoop发布2.0版本,它带了一种令人兴奋的数据交互方法。这个改变是YARN的出现带来的,YARN代表的是Yet Another Resource Negotiator。
YARN存在于数据与MapReduce之间,它允许利用很多Hadoop外围生存的工具,例如Spark和Giraph,目前是在Hadoop集群本地。理解YARN不能代替MapReduce是十分重要的;实际上YARN自己没有做任何事情。YARN所做的只是为如MapReduce,HBase,或者用户自定义的建立在Hadoop上的工具提供一个方便的,统一的方法。
教程链接
YARN仍然是一个在发展中的技术,对于初学者官方Apache是一个很不错的指导。
示例代码
坦诚地讲,用YARN写应用对于本书来讲还是很深的。你可以再“教程链接”部分寻找一个链接建立你的第一个YARN应用。
Spark
许可证: Apache License, Version 2.0
活跃度: 高
目的: 处理/存储
官方地址: http://spark.apache.org/
Hadoop集成: API兼容
在许多的Hadoop集群核心中,MapReduce都是主要的工作室。虽然对于非常大的批分析工作相当有效,但是Hadoop已经被证明对于例如需要迭代分析和数据共享的图分析的应用来讲还不是最优的。
Spark的设计是为了提供一个更加灵活的模型,这个模型支持在MapReduce中抖动的多道应用。它完成这目标是充分利用了内存的优势,这个优势就是无论在什么时候都减少数据从硬盘读写的次数。不像Pig和Hive,Spark不是一种让MapReduce更易用的工具。它是MapReduce的一个完全代替品,它有自己的工作执行引擎。
Spark操作有三个核心思想:
-
可恢复的分布式数据集(RDD)
RDDS包含你想要转换和分析的数据。它们可以从外部资源读取,例如一个文件或者一个数据库,或者可以通过转换创建。 -
转换(Transformation)
一个转换是修改一个已经存在的RDD来创建一个新的RDD。例如,一个过滤器将一个ERROR信息输出到日志文件就是一个转换 -
动作(Action)
一个动作分析一个RDD然后返回一个单独结果。例如,一个动作通过我们的ERROR过滤器对结果的id进行计数。
如果你想要用Spark做一些重要的工作。你最好用Scala,它是一种功能型的程序设计语言。Scala联合项目面向功能编程。因为Lisp是一个比较老的功能程序设计语言,Scala貌似可以称为“Lisp联手21世纪”。这不是说Scala只能跟Spark一起工作。Java和Python对这个项目也有很强大的支持,但是当添加了新的API或者特征的时候,它们首先是在Scala中出现的。
教程链接
Spark的快速开始可以在项目主页找到。
示例代码
我们可以通过从我们安装Spark的目录开始运行./bin/spark-shell打开Spark Shell。
在这个例子中,我们将对我们复查文件中的Dune进行计数。
// Read the csv file containing our reviews
scala> val reviews = spark.textFile("hdfs://reviews.csv")
testFile: spark.RDD[String] = spark.MappedRDD@3d7e837f
// This is a two-part operation:
// first we'll filter down to the two
// lines that contain Dune reviews
// then we'll count those lines
scala> val dune_reviews = reviews.filter(line =>
line.contains("Dune")).count()
res0: Long = 2