Hadoop-基础知识-全-

Hadoop 基础知识(全)

原文:Hadoop Essentials

协议:CC BY-NC-SA 4.0

零、前言

Hadoop 是一个非常吸引人和有趣的项目,各种组织和机构都对它表现出了极大的兴趣和贡献。Hadoop 已经走过了很长的路,从一个批处理系统变成了一个数据湖,并在各种 Hadoop 生态系统组件的帮助下,在低延迟下进行大容量流分析,特别是 Yarn。这一进展是实质性的,并使 Hadoop 成为一个强大的系统,可以设计为存储、转换、批处理、分析或流和实时处理系统。

Hadoop 项目作为一个数据湖可以分为多个阶段,如数据摄取、数据存储、数据访问、数据处理和数据管理。对于每个阶段,我们都有不同的子项目,它们是工具、实用程序或框架来帮助和加速这个过程。Hadoop 生态系统组件经过了测试、配置和验证,要自行构建类似的实用程序,需要花费大量的时间和精力。Hadoop 框架的核心是复杂的开发和优化。加速和简化这一过程的明智方法是利用不同的非常有用的 Hadoop 生态系统组件,这样我们就可以更加专注于应用流设计和与其他系统的集成。

随着 Hadoop 中许多有用的子项目和 Hadoop 生态系统中的其他工具的出现,出现的问题是何时以及如何有效地使用哪个工具。这本书旨在完成何时以及如何使用各种生态系统组件的拼图,并让您充分了解 Hadoop 生态系统实用程序以及应该使用它们的案例和场景。

这本书涵盖了什么

第 1 章大数据与 Hadoop 介绍,涵盖了大数据与 Hadoop 的概述,以及具有 Hadoop 优势和特点的不同用例模式。

第二章Hadoop 生态系统,探讨 Hadoop 项目开发的不同阶段或层次,以及每一层可以使用的一些组件。

第三章Hadoop 的支柱——HDFS、MapReduce 和 Yarn,是关于 Hadoop 的三个关键基础组件,分别是 HDFS、MapReduce 和 Yarn。

第 4 章数据访问组件–Hive 和 Pig 涵盖了数据访问组件 Hive 和 Pig,它们分别是 MapReduce 框架之上的类 SQL 和 Pig 拉丁过程语言的抽象层。

第五章存储组件–HBase,详细介绍了 NoSQL 组件数据库 HBA se。

第 6 章Hadoop 中的数据摄取–Sqoop 和 Flume ,涵盖了数据摄取库工具 SQOOP 和 Flume。

第 7 章流和实时分析–Storm 和 Spark,是关于建立在 Yarn 之上的流和实时框架 Storm 和 Spark。

这本书你需要什么

这本书的先决条件是很好地理解 Java 编程和分布式计算的基础知识,这对理解 Hadoop 及其生态系统组件非常有帮助和兴趣。

代码和语法已经在 Hadoop 2.4.1 和其他兼容的生态系统组件版本中进行了测试,但在较新的版本中可能会有所不同。

这本书是给谁的

如果你是一个对学习如何使用 Hadoop 框架解决实际问题感兴趣的系统或应用开发人员,那么这本书非常适合你。这本书也是为 Hadoop 专业人士准备的,他们希望找到解决他们在 Hadoop 项目中遇到的不同挑战的方法。它假定您熟悉分布式存储和分布式应用。

惯例

在这本书里,你会发现许多区分不同种类信息的文本样式。以下是这些风格的一些例子和对它们的意义的解释。

文本中的码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、伪 URL、用户输入和 Twitter 句柄如下所示:“我们可以通过使用include指令来包含其他上下文。”

代码块设置如下:

public static class MyPartitioner extends   org.apache.hadoop.mapreduce.Partitioner<Text,Text>

{
  @Override
  public int getPartition(Text key, Text value, int numPartitions)
  {
   int count =Integer.parseInt(line[1]);
   if(count<=3)
    return 0;
   else
    return 1;
  }
}

And in Driver class
job.setPartitionerClass(MyPartitioner.class);

任何命令行输入或输出都编写如下:

hadoop fs -put /home/shiva/Samplefile.txt  /user/shiva/dir3/

警告或重要提示会出现在这样的框中。

类型

提示和技巧是这样出现的。

读者反馈

我们随时欢迎读者的反馈。让我们知道你对这本书的看法——你喜欢或不喜欢什么。读者反馈对我们来说很重要,因为它有助于我们开发出你真正能从中获益的标题。

要给我们发送一般反馈,只需发送电子邮件<[feedback@packtpub.com](mailto:feedback@packtpub.com)>,并在您的邮件主题中提及书名。

如果你对某个主题有专业知识,并且对写作或投稿感兴趣,请参见我们位于www.packtpub.com/authors的作者指南。

客户支持

现在,您已经自豪地拥有了一本书,我们有许多东西可以帮助您从购买中获得最大收益。

下载示例代码

您可以从您在http://www.packtpub.com的账户下载您购买的所有 Packt Publishing 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问http://www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

勘误表

尽管我们尽了最大努力来确保我们内容的准确性,但错误还是会发生。如果你在我们的某本书里发现了错误——可能是文本或代码中的错误——如果你能向我们报告,我们将不胜感激。通过这样做,你可以让其他读者免受挫折,并帮助我们改进这本书的后续版本。如果您发现任何勘误表,请访问http://www.packtpub.com/submit-errata,选择您的书籍,点击勘误表提交表链接,并输入您的勘误表的详细信息。一旦您的勘误表得到验证,您的提交将被接受,勘误表将上传到我们的网站或添加到该标题勘误表部分下的任何现有勘误表列表中。

要查看之前提交的勘误表,请前往https://www.packtpub.com/books/content/support并在搜索栏中输入图书名称。所需信息将出现在勘误表部分。

盗版

互联网上版权材料的盗版是所有媒体的一个持续问题。在 Packt,我们非常重视版权和许可证的保护。如果您在互联网上遇到任何形式的我们作品的非法拷贝,请立即向我们提供位置地址或网站名称,以便我们寻求补救。

请通过<[copyright@packtpub.com](mailto:copyright@packtpub.com)>联系我们,获取疑似盗版资料的链接。

我们感谢您在保护我们的作者方面的帮助,以及我们为您带来有价值内容的能力。

问题

如果您对本书的任何方面有问题,可以在<[questions@packtpub.com](mailto:questions@packtpub.com)>联系我们,我们将尽最大努力解决问题。

一、大数据和 Hadoop 简介

你好大数据爱好者!到这个时候,我相信你一定听说了很多关于大数据的事情,因为大数据是热门的 IT 流行语,大数据有很多令人兴奋的地方。让我们试着去理解大数据的必要性。互联网上、机构中以及一些组织中有海量数据,这些数据有很多有意义的见解,可以使用数据科学技术进行分析,并涉及复杂的算法。数据科学技术需要大量的处理时间、中间数据和中央处理器能力,这可能需要几十个小时来处理千兆字节的数据,数据科学是在反复试验的基础上工作的,以检查算法是否能更好地处理数据来获得这样的见解。与任何其他分析或商业智能系统相比,大数据系统不仅可以更快、更高效地处理大数据的数据分析,还可以扩大研发分析的范围,并产生更有意义的见解。

由于传统系统的一些问题和局限性,大数据系统应运而生。传统系统适用于 【在线交易处理】(【OLTP】)和 【商业智能】 ( BI ),但考虑到成本、工作量和可管理性方面,它们不容易扩展。处理繁重的计算很困难,并且容易出现内存问题,或者非常慢,这在更大程度上阻碍了数据分析。传统系统在数据科学分析方面存在广泛的不足,使得大数据系统强大而有趣。大数据使用案例的一些示例包括预测分析、欺诈分析、机器学习、识别模式、数据分析、半结构化和非结构化数据处理和分析。

大数据的 V

通常,大数据范畴内的问题是由通常被称为大数据 V 的术语定义的。通常有三个 V,即音量、速度和变化,如下图所示:

V's of big data

根据 国际数据公司 ( IDC )的第五次年度调查,仅 2011 年就创造和复制了 1.8 兆字节(1.8 万亿千兆字节)的信息,高于 2009 年的 800 千兆字节,预计到 2020 年,这一数字将超过 35 兆字节,每两年翻一番以上。大数据系统旨在通过容错架构存储这些数据量,甚至更大的数据量,并且由于它分布和复制在多个节点上,底层节点可以是普通的计算系统,也不需要是高性能系统,这大大降低了成本。

大数据中每万亿字节存储的成本比其他系统中的成本低得多,这使得组织在更大程度上感兴趣,即使数据增长了多次,也很容易扩展,并且无需太多维护工作就可以添加节点。

速度

处理和分析我们前面讨论的数据量是大数据越来越受欢迎并取得巨大发展的关键兴趣领域之一。并不是所有要处理的数据最初都必须在数量上更大,但是当我们处理和执行一些复杂的算法时,数据会大量增长。为了处理大多数算法,我们将需要中间或临时数据,对于大数据,这些数据可能是以 GB 或 TB 为单位的,因此在处理时,我们将需要大量数据,并且处理速度也必须更快。大数据系统可以更快地处理海量数据上的巨大复杂算法,因为它利用了跨分布式环境的并行处理,同时并行执行多个进程,作业可以更快地完成。

例如,雅虎在 2009 年创造了一项世界纪录,使用 Apache Hadoop 在 16.25 小时内对一个千兆字节进行排序,在 62 秒内对一个千兆字节进行排序。MapR 已经在 55 秒内实现了万亿字节的数据排序,这充分说明了处理能力,尤其是在分析中,我们需要使用大量中间数据来更快地执行大量时间和内存密集型算法。

品种

传统系统面临的另一大挑战是处理不同种类的半结构化数据或非结构化数据,如电子邮件、音频和视频分析、图像分析、社交媒体、基因、地理空间、3D 数据等。大数据不仅可以帮助存储,还可以使用算法更快、更有效地利用和处理这些数据。半结构化和非结构化数据的处理非常复杂,大数据可以像其他系统一样使用最少或不需要预处理的数据,可以节省大量工作,并有助于最大限度地减少数据丢失。

了解大数据

实际上,大数据是一个术语,指的是我们在 V 问题方面由于数据的指数级增长而面临的挑战。挑战可细分为以下几个阶段:

  • 捕获
  • 储存;储备
  • 搜索
  • 共享
  • 分析学
  • 形象化

大数据系统指的是能够处理和分析数据的技术,我们将它称为容量、速度和各种数据问题。能够解决大数据问题的技术应该使用以下体系结构策略:

  • 分布式计算系统
  • 大规模并行处理
  • NoSQL(不仅仅是 SQL)
  • 分析数据库

结构如下:

Understanding big data

大数据系统使用分布式计算和并行处理来处理大数据问题。除了分布式计算和 MPP,还有其他可以解决大数据问题的体系结构,即 NoSQL 和高级 SQL,它们都是基于数据库环境的系统。

NoSQL

由于无模式设计,NoSQL 数据库是一种广泛适用的技术,其纵向和横向扩展的能力相当简单,而且工作量也小得多。SQL 和 RDBMS 已经统治了三十多年,它在处理环境的限制范围内表现良好,除此之外,RDBMS 系统性能下降,成本增加,可管理性降低,我们可以说 NoSQL 在这些场景中比 RDBMS 有优势。

值得一提的重要一点是,NoSQLs 不支持所有 ACID 属性,并且具有高度可伸缩性、可用性和容错性。NoSQL 通常提供一致性或可用性(处理节点的可用性),这取决于架构和设计。

NoSQL 数据库的类型

由于 NoSQL 数据库是非关系型的,它们有不同的可能架构和设计。根据数据的存储方式,NoSQL 数据库大致有四种类型:

  1. 键值存储:这些数据库是为在键值存储中存储数据而设计的。键可以是自定义的,可以是合成的,也可以是自动生成的,值可以是复杂的对象,如 XML、JSON 或 BLOB。数据的关键字被编入索引,以便更快地访问数据并改进对值的检索。一些流行的键值类型数据库是 DynamoDB、Azure 表存储(ATS)、Riak 和 BerkeleyDB。
  2. 列存储:这些数据库是为作为一组列族存储数据而设计的。读/写操作是使用列而不是行来完成的。优点之一是压缩范围大,可以有效节省空间,避免对列的内存扫描。由于列的设计,并不是所有的文件都需要被扫描,并且每个列文件都可以被压缩,尤其是当一个列有许多空值和重复值时。列存储高度可扩展且具有极高性能架构的数据库。一些流行的列存储类型数据库是 HBase、BigTable、Cassandra、Vertica 和 Hypertable。
  3. 文档数据库:这些数据库是设计用于存储、检索和管理面向文档的信息。文档数据库扩展了键值存储的思想,在键值存储中,值或文档使用某种结构存储,并以 XML、YAML 或 JSON 等格式编码,或者以二进制形式编码,如 BSON、PDF、微软办公文档(微软 Word、Excel)等。以像 XML 或 JSON 这样的编码格式存储的优点是,我们可以在数据的文档中使用关键字进行搜索,这在即席查询和半结构化数据中非常有用。一些流行的文档类型数据库是 MongoDB 和 CouchDB。
  4. 图形数据库:这些数据库是为数据设计的,这些数据的关系被很好地表示为树或图形,并且具有元素,通常具有相互连接的节点和边。关系数据库在执行基于图的查询时不太受欢迎,因为它们需要大量复杂的连接,因此管理互连变得很麻烦。图论算法在预测、用户跟踪、点击流分析、计算最短路径等方面非常有用,由于算法本身比较复杂,因此用图数据库处理这些问题会更加有效。一些流行的图形类型数据库是 Neo4J 和 Polyglot。

分析数据库

分析数据库是一种为存储、管理和使用大数据而构建的数据库。分析数据库是由供应商管理的数据库管理系统,针对处理高级分析进行了优化,包括对万亿字节数据的高度复杂查询以及复杂的统计处理、数据挖掘和自然语言处理。分析数据库的例子有 Vertica(由惠普收购)、Aster Data(由 Teradata 收购)、Greenplum(由 EMC 收购)等等。

谁在创造大数据?

数据呈指数级增长,并且来自持续一致地发布数据的多个来源。在某些领域,我们必须分析由机器、传感器、质量、设备、数据点等处理的数据。创建大数据的一些来源列表如下:

  • 监测传感器:气候或海浪监测传感器产生的数据一致且大小良好,将有超过数百万个传感器捕捉数据。
  • 发布到社交媒体网站:社交媒体网站,如脸书、推特和其他网站,有大量的千兆字节数据。
  • 网上发布的数字图片和视频:YouTube、网飞等网站处理大量数字视频和数据,数据量可达千兆字节。
  • 网上购物的交易记录:易贝、亚马逊、Flipkart 等电子商务网站一次处理数千笔交易。
  • 服务器/应用日志:应用生成持续增长的日志数据,对这些数据的分析变得困难。
  • CDR(通话数据记录):漫游数据和手机 GPS 信号,不一而足。
  • 科学、基因组学、生物地球化学、生物学和其他复杂和/或跨学科的科学研究。

大数据用例

我们来看看信用卡发卡行(MapR 演示的用例)。

一位信用卡发卡行客户希望改进现有的推荐系统,该系统比较落后,如果推荐速度更快,可能会有巨大的潜在利润。

现有系统是 企业数据仓库 ( EDW ),成本非常高,生成推荐的速度也比较慢,进而影响潜在利润。由于 Hadoop 更便宜更快,它将比现有系统产生巨大的利润。

通常,信用卡客户会有如下数据:

  • 客户购买历史记录(大)
  • 商家名称
  • 商家特别优惠

让我们分析一下现有 EDW 平台与大数据解决方案的总体比较。推荐系统采用 Mahout(可扩展机器学习库 API)和 Solr/Lucene 设计。推荐基于作为搜索索引实现的共现矩阵。

基准测试的时间改进从 20 小时缩短到仅 3 小时,少了令人难以置信的 6 倍,如下图所示:

Big data use cases

在下图的 web 层中,我们可以看到改进从 8 小时缩短到 3 分钟:

Big data use cases

因此,最终,我们可以说时间减少,收入增加,Hadoop 提供了一个经济高效的解决方案,因此利润增加,如下图所示:

Big data use cases

大数据用例模式

有很多技术场景,有些模式相似。用架构模式映射场景是一个好主意。一旦理解了这些模式,它们就成为解决方案的基本构件。我们将在下一节讨论五种类型的模式。

该解决方案并不总是优化的,它可能取决于域数据、数据类型或一些其他因素。这些例子是为了可视化问题,它们可以帮助找到解决方案。

大数据作为一种存储模式

大数据系统可以作为存储模式,也可以作为数据仓库,来自多个来源的数据,即使是不同类型的数据,都可以存储起来,以后可以利用。使用场景和用例如下:

  • 使用场景:
    • 大量数据不断生成
    • 加载到目标系统之前需要预处理
  • 用例:
    • 用于后续清理的机器数据捕获可以合并到多个或单个大文件中,并可以加载到 Hadoop 中进行计算
    • 应该捕获跨多个来源的非结构化数据,以便随后对新兴模式进行分析
    • 在 Hadoop 中加载的数据应该经过处理和过滤,根据数据的不同,我们可以将存储作为数据仓库、Hadoop 或任何 NoSQL 系统。

存储模式如下图所示:

Big data as a storage pattern

大数据作为一种数据转换模式

大数据系统可以设计为执行转换作为数据加载和清理活动,由于并行性,许多转换可以比传统系统完成得更快。转换是数据提取-转换-加载和清理阶段的一个阶段。使用场景和用例如下:

  • 使用场景
    • 需要预处理的大量原始数据
    • 数据类型包括结构化数据和非结构化数据
  • 用例
    • 利用大数据的 ETL(提取-转换-加载)工具的发展,例如 Pentaho、Talend 等。此外,在 Hadoop 中,ELT(提取-加载-转换)也是趋势,因为在 Hadoop 中加载会更快,清理可以运行并行流程来清理和转换输入,这将会更快

数据转换模式如下图所示:

Big data as a data transformation pattern

用于数据分析模式的大数据

数据分析在大数据系统中更受关注,在大数据系统中,大量数据可以被分析以生成关于数据的统计报告和见解,这对业务和模式理解非常有用。使用场景和用例如下:

  • 使用场景
    • 改善模式检测的响应时间
    • 非结构化数据的数据分析
  • 用例
    • 机器数据分析的快速周转(例如,地震数据分析)
    • 跨结构化和非结构化数据的模式检测(例如,欺诈分析)

实时模式下的大数据

集成和一些流库的大数据系统和系统能够处理大规模实时数据处理。大型复杂需求的实时处理具有许多挑战,如性能、可伸缩性、可用性、资源管理、低延迟等。一些流技术,如 Storm 和 Spark 流可以与 Yarn 集成。使用场景和用例如下:

  • 使用场景
    • 实时管理基于不断变化的数据采取的措施
  • 用例
    • 基于制造设备实时的自动化过程控制
    • 基于业务系统 企业资源规划 ( 企业资源规划事件的工厂运营实时变化

下图显示了实时模式中的数据:

Big data for data in a real-time pattern

用于低延迟缓存模式的大数据

大数据系统可以作为的特例进行调优,这是一个低延迟的系统,读取高得多,更新低,可以更快地获取数据并存储在内存中,可以进一步提高性能并避免开销。使用场景和用例如下:

  • 使用场景
    • 读取与写入的比率要高得多
    • 读取需要非常低的延迟和有保证的响应
    • 基于位置的分布式数据缓存
  • 用例
    • 订购有希望的解决方案
    • 基于云的身份和单点登录
    • 移动设备上的低延迟实时个性化服务

低延迟缓存模式显示在以下模式中:

Big data for a low latency caching pattern

下图显示了根据层和框架广泛使用的一些技术堆栈:

Big data for a low latency caching pattern

Hadoop

在大数据中,应用最广泛的系统是 Hadoop。Hadoop 是大数据的开源实现,在业界被广泛接受,Hadoop 的基准测试令人印象深刻,在某些情况下是其他系统无法比拟的。Hadoop 在工业中用于大规模、大规模并行和分布式数据处理。Hadoop 具有很高的容错性,并且可以根据我们需要配置任意多的级别,以使系统具有容错性,这将直接影响数据的存储次数。

正如我们已经谈到的大数据系统,该架构围绕两个主要组件:分布式计算和并行处理。在 Hadoop 中,分布式计算由 HDFS 处理,并行处理由 MapReduce 处理。简而言之,我们可以说 Hadoop 是 HDFS 和 MapReduce 的结合,如下图所示:

Hadoop

我们将在接下来的章节中详细介绍上述两个主题。

Hadoop 历史

Hadoop 始于一个名为 Nutch 的项目,这是一个基于开源爬虫的搜索,在分布式系统上处理。在 2003-2004 年,谷歌发布了谷歌地图减少和全球资源定位系统论文。MapReduce 是在 Nutch 上改编的。Doug Cutting 和 Mike Cafarella 是 Hadoop 的创作者。当道格·卡特加入雅虎时,一个类似于 Nutch 的新项目被创建,我们称之为 Hadoop,Nutch 仍然是一个独立的子项目。然后,有了不同的版本,其他独立的子项目开始与 Hadoop 集成,我们称之为 Hadoop 生态系统。

下图和描述描述了在 Hadoop 中实现的时间表和里程碑的历史:

Hadoop history

描述

  • 2002.8:Nutch 项目开工
  • 2003.2 :第一个 MapReduce 库是在谷歌写的
  • 2003.10 :谷歌文件系统论文发表
  • 2004.12 :谷歌 MapReduce 论文发表
  • 2005.7 : Doug Cutting 报道 Nutch 现在使用新的 MapReduce 实现
  • 2006.2 : Hadoop 代码从 Nutch 转移到了一个新的 Lucene 子项目中
  • 2006.11 :谷歌 Bigtable 论文发表
  • 2007.2 :第一个 HBase 代码从 Mike Cafarella 掉了
  • 2007.4 :雅虎!在 1000 节点集群上运行 Hadoop
  • 2008.1 : Hadoop 做了一个 Apache 顶级项目
  • 2008.7 : Hadoop 打破了 Terabyte 数据排序基准
  • 2008.11 : Hadoop 0.19 发布
  • 2011.12 : Hadoop 1.0 发布
  • 2012.10:Hadoop 2.0 alpha 发布
  • 2013.10 : Hadoop 2.2.0 发布
  • 2014.10 : Hadoop 2.6.0 发布

Hadoop 的优势

Hadoop 有很多优点,其中一些如下:

  • 低成本——在商品硬件上运行: Hadoop 可以在性能一般的商品硬件上运行,不需要高性能的系统,可以帮助控制成本,实现可扩展性和性能。从集群中添加或删除节点很简单,就像我们需要时一样。在 Hadoop 中,每 TB 的存储和处理成本更低。
  • 存储灵活性 : Hadoop 可以在分布式环境中以原始格式存储数据。Hadoop 可以比大多数现有技术更好地处理非结构化数据和半结构化数据。Hadoop 为处理数据提供了充分的灵活性,我们不会有任何数据丢失。
  • 开源社区: Hadoop 是开源的,得到了众多贡献者的支持,全球开发者网络不断壮大。许多组织,如雅虎、脸书、霍顿工程和其他组织,都对 Hadoop 和其他相关子项目的进展做出了巨大贡献。
  • 容错 : Hadoop 具有大规模可伸缩性和容错性。就数据可用性而言,Hadoop 是可靠的,即使某些节点宕机,Hadoop 也可以恢复数据。Hadoop 架构假设节点可以关闭,系统应该能够处理数据。
  • 复杂数据分析:随着大数据的出现,数据科学也有了突飞猛进的发展,我们有了复杂且计算密集的算法来进行数据分析。Hadoop 可以为非常大规模的数据处理这种可扩展的算法,并且可以更快地处理算法。

Hadoop 的用途

使用 Hadoop 的一些用例示例如下:

  • 搜索/文本挖掘
  • 日志处理
  • 推荐系统
  • 商业智能/数据仓库
  • 视频和图像分析
  • 归档
  • 图形创建和分析
  • 模式识别
  • 风险评估
  • 情绪分析

Hadoop 生态系统

一个 Hadoop 集群可以有千个节点,人工管理复杂且困难,因此有一些组件辅助整个 Hadoop 系统的配置、维护和管理。在本书中,我们将基于第 2 章Hadoop 生态系统中的以下组件进行讨论。

|

|

实用程序/工具名称

|
| --- | --- |
| 分布式文件系统 | Apache HDFS |
| 分布式程序设计 | Apache MapReduce |
| Apache Hive |
| ApachePIG |
| ApacheSpark |
| NoSQL 数据库 | 阿帕契巴塞 |
| 数据摄取 | ApacheFlume |
| Apache Sqoop |
| ApacheStorm |
| 服务编程 | Apache 动物园管理员 |
| 行程安排 | Apache Oozie |
| 机器学习 | Apache·马胡特 |
| 系统部署 | Apache 人 Ambari |

上述所有组件都有助于管理 Hadoop 任务和作业。

Apache Hadoop

开源的 Hadoop 由 Apache 软件基金会维护。 Apache Hadoop 的官方网站是http://hadoop.apache.org/,这里详细描述了包和其他细节。当前的 Apache Hadoop 项目(2.6 版)包括以下模块:

  • Hadoop 通用:支持其他 Hadoop 模块的通用实用程序
  • Hadoop 分布式文件系统(HDFS) :一个分布式文件系统,提供对应用数据的高吞吐量访问
  • Hadoop Yarn:作业调度和集群资源管理的框架
  • Hadoop MapReduce :一个基于 Yarn 的系统,用于大数据集的并行处理

Apache Hadoop 可以以以下三种模式部署:

  • 独立:用于进行简单的分析或调试。
  • 伪分布式:帮助在单个节点上模拟多节点安装。在伪分布式模式下,每个组件进程都在单独的 JVM 中运行。您可以在单个服务器上模拟它,而不是在不同的服务器上安装 Hadoop。
  • 分布式:集群有几十个或者几百个或者几千个节点的多个工作节点。

在 Hadoop 生态系统中,除了 Hadoop 之外,还有许多独立的 Apache 项目的实用程序组件,如 Hive、Pig、HBase、Sqoop、Flume、Zookeper、Mahout 等,它们必须单独配置。我们必须小心子项目与 Hadoop 版本的兼容性,因为并非所有版本都是相互兼容的。

Apache Hadoop 是一个开源项目,它有很多好处,因为源代码可以更新,也有一些贡献是通过一些改进完成的。作为开源项目的一个缺点是,公司通常为他们的产品提供支持,而不是为开源项目提供支持。客户更喜欢支持和改编供应商支持的 Hadoop 发行版。

让我们看看一些可用的 Hadoop 发行版。

Hadoop 发行版

Hadoop 发行版由管理发行版的公司提供支持,一些发行版也有许可成本。Cloudera、Hortonworks、Amazon、MapR 和 Pivotal 等公司在市场上都有各自的 Hadoop 发行版,为 Hadoop 提供所需的子包和项目,这些子包和项目兼容并提供商业支持。这大大减少了工作量,不仅是在操作方面,而且在部署、监控以及工具和实用程序方面,以便于更快地开发产品或项目。

为了管理 Hadoop 集群,Hadoop 发行版为 Hadoop 集群的部署、管理和监控提供了一些图形网络用户界面工具,可用于设置、管理和监控复杂的集群,从而减少了大量的工作和时间。

一些可用的 Hadoop 发行版如下:

  • Cloudera:根据 The Forrester Wave:大数据 Hadoop Solutions,Q1 2014 ,这是使用最广泛的 Hadoop 发行版,拥有最大的客户群因为它提供了很好的支持,并且拥有一些很好的实用组件,比如 Cloudera Manager,可以创建、管理和维护集群,管理作业处理,Impala 是由具备实时处理能力的 Cloudera 开发和贡献的。
  • Hortonworks : Hortonworks 的战略是通过开源社区推动所有创新,并创建一个合作伙伴生态系统,加速企业对 Hadoop 的采用。它使用开源 Hadoop 项目,是 Apache Hadoop 中 Hadoop 增强的主要贡献者。Ambari 是由 Hortonworks 开发并贡献给 Apache 的。Hortonworks 为入门提供了一个非常好的、易于使用的沙盒。Hortonworks 做出了一些改变,使 Apache Hadoop 在微软视窗平台上运行,包括视窗服务器和微软 Azure。
  • MapR:Hadoop 的 MapR 发行版使用了与普通开源 Hadoop 及其竞争对手不同的概念,特别是支持网络文件系统(NFS)而不是 HDFS,以获得更好的性能和易用性。在 NFS,可以使用本机 Unix 命令来代替 Hadoop 命令。MapR 具有高可用性功能,例如快照、镜像或状态故障转移。
  • Amazon Elastic MapReduce(EMR):AWS 的 Elastic MapReduce (EMR)利用其全面的云服务,如用于计算的 Amazon EC2、用于存储的 Amazon S3 以及其他服务,为希望在云中实施 Hadoop 的客户提供非常强大的 Hadoop 解决方案。EMR 非常适合用于不常见的大数据处理。它可能会帮你省很多钱。

Hadoop 的支柱

Hadoop 被设计为高度可扩展、分布式、大规模并行处理、容错和灵活,设计的关键方面是 HDFS、MapReduce 和 Yarn。HDFS 和 MapReduce 可以以更快的速度执行非常大规模的批处理。由于各种组织和机构的贡献,Hadoop 架构经历了很多改进,其中之一就是 Yarn。Yarn 克服了 Hadoop 的一些限制,允许 Hadoop 轻松地与不同的应用和环境集成,尤其是在流和实时分析方面。我们将要讨论的一个这样的例子是 Storm 和 Spark,它们在流和实时分析方面非常有名,都可以通过 Yarn 与 Hadoop 集成。

我们将在第 3 章Hadoop 的支柱——HDFS、MapReduce 和 Yarn中更详细地介绍 HDFS、MapReduce 和 Yarn 的概念。

数据访问组件

MapReduce 是一个非常强大的框架,但是掌握和优化一个 MapReduce 作业有着巨大的学习曲线。为了在 MapReduce 范式中分析数据,我们的大量时间将花费在编码上。在大数据中,用户来自不同的背景,如编程、脚本、EDW、数据库管理员、分析等等,对于这样的用户,在 MapReduce 之上有抽象层。Hive 和 Pig 就是这样两层,Hive 有类似 SQL 查询的接口,Pig 有 Pig 拉丁程序语言接口。分析这些层上的数据变得容易得多。

我们将在第 4 章数据访问组件-Hive 和 PIG中更详细地介绍 Hive 和 PIG 的概念。

数据存储组件

HBase 是一个基于列商店的 NoSQL 数据库解决方案。HBase 的数据模型与谷歌的 BigTable 框架非常相似。HBase 可以高效地处理大量数据(通常是数百万或数十亿行)中的随机和实时访问。HBase 的重要优势在于,它支持对更大的表进行更新,并且查找速度更快。HBase 数据存储支持线性和模块化扩展。HBase 将数据存储为多维地图,并且是分布式的。HBase 操作都是以并行方式运行的 MapReduce 任务。

我们将在第 5 章存储组件—HBase 中更详细地介绍 HBase 的概念。

Hadoop 中的数据摄取

在 Hadoop 中,存储从来都不是问题,但是管理数据是驱动力,不同的系统可以围绕它设计不同的解决方案,因此管理数据变得极其关键。一个更好管理的系统在可伸缩性、可重用性甚至性能方面都有很大帮助。在 Hadoop 生态系统中,我们有两个广泛使用的工具:Sqoop 和 Flume,它们都可以帮助管理数据,并且可以高效地导入和导出数据,性能良好。Sqoop 通常用于与 RDBMS 系统的数据集成,Flume 通常在流式日志数据方面表现更好。

我们将在第 6 章Hadoop 中的数据摄取—Sqoop 和 Flume 中更详细地介绍 Sqoop 和 Flume 的概念。

流式传输和实时分析

Storm 和 Spark 是两个令人着迷的新组件,它们可以在 Yarn 网上运行,并在处理流和实时分析方面具有一些惊人的能力。这两种方法都用于我们有大量连续流数据并且必须在实时或接近实时的情况下进行处理的场景。我们前面讨论的流量分析器的例子是 Storm 和 Spark 用例的一个很好的例子。

我们将在第 7 章流和实时分析—Storm 和 Spark中更详细地介绍 Storm 和 Spark 的概念。

总结

在本章中,我们谈到了大数据及其用例模式。我们探讨了一下 Hadoop 的历史,最后谈到了 Hadoop 的优势和用途。

Hadoop 系统的监控和管理非常复杂,我们有独立的子项目框架、工具和实用程序,它们与 Hadoop 集成在一起,有助于更好地管理任务,这被称为 Hadoop 生态系统,我们将在后续章节中讨论。

二、Hadoop 生态系统

既然我们已经讨论并了解了大数据和 Hadoop,我们就可以继续了解 Hadoop 生态系统了。一个 Hadoop 集群可能有数百或数千个难以手动设计、配置和管理的节点。因此,需要工具和实用程序来轻松有效地管理系统和数据。除了 Hadoop,我们还有独立的子项目,由一些组织和贡献者贡献,并且主要由 Apache 管理。子项目与 Hadoop 集成得非常好,可以帮助我们更加专注于设计和开发,而不是维护和监控,还可以帮助开发和数据管理。

在了解不同的工具和技术之前,让我们先了解一个用例,以及它与传统系统的区别。

传统系统

传统系统适合 OLTP(在线事务处理)和一些基本的数据分析和 BI 用例。在这个范围内,传统系统在性能和管理方面是最好的。下图显示了传统系统的高级概述:

Traditional systems

BIA 的传统系统

典型传统系统的步骤如下:

  1. 数据驻留在数据库中
  2. 提取转换加载过程
  3. 数据被移入数据仓库
  4. 商业智能应用可以有一些商业智能报告
  5. 数据分析应用也可以使用数据

当数据增长时,传统系统无法处理甚至存储数据;即使他们这样做了,也要付出非常高的成本和努力,因为体系结构的局限性、可伸缩性和资源限制的问题、横向扩展的能力或困难。

数据库趋势

数据库技术已经发展了一段时间。我们有关系数据库、企业数据仓库,现在出现了基于 Hadoop 和 NoSQL 的数据库。Hadoop 和基于 NoSQL 的数据库现在是用于解决大数据问题的首选技术,一些传统系统正在逐步转向 Hadoop 和 NoSQL,以及它们现有的系统。一些系统有不同的技术来处理数据,例如,Hadoop 和 RDBMS,Hadoop 和 EDW,NoSQL 和 EDW,NoSQL 和 Hadoop。下图描述了弗雷斯特研究公司的数据库趋势:

Database trend

数据库趋势

该图描绘了设计趋势和在特定十年中可用和适用的技术。

20 世纪 90 年代是关系数据库管理系统时代,它是为 OLTP 处理而设计的,数据处理没有那么复杂。

数据仓库的出现和适应是在 2000 年,用于 OLAP 处理和商业智能。

从 2010 年开始,大数据系统,尤其是 Hadoop,被许多组织用来解决大数据问题。

所有这些技术实际上可以共存于一个解决方案中,因为每种技术都有其优缺点,因为不是所有的问题都可以通过任何一种技术来解决。

Hadoop 用例

Hadoop 可以帮助解决我们在第 1 章大数据和 Hadoop 简介中讨论的大数据问题。基于数据速度(批处理和实时)和数据多样性(结构化、半结构化和非结构化),我们在不同的领域和行业有不同的用例集。所有这些用例都是大数据用例,Hadoop 可以有效地帮助解决它们。下图描述了一些用例:

The Hadoop use cases

大数据分析的潜在使用案例

Hadoop 的基础数据流

Hadoop 系统的一个基本数据流可以分为四个阶段:

  1. 捕获大数据:来源可以是结构化、半结构化和非结构化的大量列表,一些流式实时数据源、传感器、设备、机器捕获的数据以及许多其他来源。对于数据捕获和存储,我们在 Hadoop 生态系统中有不同的数据集成器,如 Flume、Sqoop、Storm 等,具体取决于数据的类型。
  2. 流程和结构:我们将使用基于 MapReduce 的框架或者其他一些能够在 Hadoop 生态系统中执行分布式编程的框架,对数据进行清理、过滤和转换。目前可用的框架有 MapReduce、Hive、Pig、Spark 等。
  3. 分发结果:处理后的数据可以被 BI 和分析系统或大数据分析系统用于执行分析或可视化。
  4. 反馈和保留:分析后的数据可以反馈给 Hadoop,用于改进和审核。

下图显示了在 Hadoop 平台中捕获并处理的数据,以及在商业交易和交互系统以及商业智能和分析系统中使用的结果:

Hadoop's basic data flow

Hadoop 基本数据流

Hadoop 集成

Hadoop 架构旨在轻松与其他系统集成。集成非常重要,因为虽然我们可以在 Hadoop 中高效地处理数据,但我们也应该能够将结果发送到另一个系统,以将数据移动到另一个级别。数据必须与其他系统集成,以实现互操作性和灵活性。

下图描述了与不同系统集成的 Hadoop 系统,以及一些实现的工具,以供参考:

Hadoop integration

Hadoop 与其他系统的集成

通常与 Hadoop 集成的系统有:

  • 数据集成工具,如,Sqoop,Flume 等
  • NoSQL 工具,如卡珊德拉、MongoDB、Couchbase 等
  • ETL 工具,如 Pentaho、Informatica、Talend 等
  • 可视化工具,如 Tableau、Sas、R 等

Hadoop 生态系统

Hadoop 生态系统由许多子项目组成,我们可以根据需要在 Hadoop 集群中配置这些项目。由于 Hadoop 是一个开源软件,并且已经变得流行,我们看到了不同组织支持 Hadoop 的许多贡献和改进。所有实用程序都绝对有用,有助于高效管理 Hadoop 系统。为了简单起见,我们将通过分类来理解不同的工具。

下图描述了 Hadoop 生态系统中的层以及该层中的工具和实用程序:

The Hadoop ecosystem

Hadoop 生态系统

分布式文件系统

在 Hadoop 中,我们知道数据存储在分布式计算环境中,因此文件分散在集群中。我们应该有一个高效的文件系统来管理 Hadoop 中的文件。Hadoop 中使用的文件系统是 HDFS,详细描述为 Hadoop 分布式文件系统。

HDFS

HDFS 是极可扩展和容错。它被设计成在分布式环境中甚至在商用硬件中有效地处理并行处理。HDFS 在 Hadoop 中有守护进程,负责管理数据。流程为NameNodeDataNodeBackupNodeCheckpoint NameNode

我们将在下一章很少讨论 hdfs 。

分布式编程

为了利用分布式存储文件系统的能力,Hadoop 执行分布式编程,可以进行大规模并行编程。分布式编程是任何大数据系统的核心,因此极其关键。以下是可用于分布式编程的不同框架:

  • MapReduce
  • 储备
  • PIG
  • Spark

Hadoop 中用于分布式编程的基本层是 MapReduce。让我们介绍一下 MapReduce:

  • Hadoop MapReduce:MapReduce 是 Hadoop 系统分布式编程的核心。MapReduce 是一个框架模型,设计为分布式环境下的并行处理。Hadoop MapReduce 的灵感来自谷歌 MapReduce 白皮书。Hadoop MapReduce 是一个可扩展的大规模并行处理框架,可以处理巨大的数据,设计为即使在商品硬件中也能运行。在 Hadoop 2 之前。 x ,MapReduce 是唯一可以执行的处理框架,然后一些实用程序扩展并创建了一个包装器,可以轻松编程以加快开发速度。我们将在第三章Hadoop 的支柱——HDFS、MapReduce 和 T7 中详细讨论 Hadoop MapReduce。
  • Apache Hive : Hive 为 Hadoop 提供了一个数据仓库基础架构系统,它在 MapReduce 之上创建了一个类似 SQL 的包装器接口,名为 HiveQL,。Hive 可用于对 Hadoop 数据运行一些特别的查询以及基本的聚合和汇总处理。HiveQL 不符合 SQL92。Hive 是由脸书开发的,并为 Apache 做出了贡献。Hive 是在 MapReduce 之上设计的,这意味着 HiveQL 查询将运行 MapReduce 作业来处理查询。我们甚至可以通过使用 【用户定义功能】 ( UDF )来扩展 HiveQL。
  • Apache Pig : Pig 提供了一个用 Pig 拉丁语编写的类似脚本的包装器,用类似脚本的语法处理数据。Pig 由雅虎开发,并为 Apache 做出了贡献。Pig 还将 Pig 拉丁脚本代码翻译成 MapReduce 并执行作业。Pig 通常用于分析半结构化和大型数据集。
  • Apache Spark : Spark 为 Hadoop 的 MapReduce 提供了强大的替代方案。Apache Spark 是一个并行数据处理框架,在内存上可以运行比 Hadoop MapReduce 快 100 倍的程序,在磁盘上可以快 10 倍。Spark 用于实时流处理和数据分析。

NoSQL 数据库

我们已经讨论过 NoSQL 是新兴和被采用的体系之一。在 Hadoop 生态系统中,我们有一个名为 HBase 的 NoSQL 数据库。HBase 是提供非常灵活的设计和低延迟的大容量同时读写的关键组件之一,因此被广泛采用。

Apache HBase

HBase 的灵感来源于谷歌的《大桌子》。HBase 是一个排序图,具有稀疏性、一致性、分布性和多维性。HBase 是一个面向 NoSQL、面向列的数据库和键/值存储,它在 HDFS 之上工作。HBase 提供了更快的查找速度,还可以大规模地大量插入/更新随机访问请求。HBase 模式非常灵活,实际上是可变的,可以在运行时添加或删除列。HBase 支持低延迟和高度一致的读写操作。适用于高速计数器聚合。

许多组织或公司使用 HBase,如雅虎、Adobe、脸书、推特、Stumbleupon、NGData、Infolinks、趋势科技等。

数据摄取

大数据中的数据管理是一个重要而关键的方面。我们必须导入和导出大规模数据来进行处理,这在生产环境中变得难以管理。在 Hadoop 中,我们处理不同的源集,如批处理、流、实时,以及数据格式复杂的源,因为有些源也是半结构化和非结构化的。管理这样的数据是非常困难的,因此我们有一些数据管理的工具,比如 Flume、Sqoop 和 Storm,它们被提到如下:

  • Apache Flume:ApacheFlume 是一个广泛使用的工具,用于高效地收集、聚合和移动来自许多不同来源的大量日志数据到一个集中的数据存储中。Flume 是一个分布式、可靠、可用的系统。如果一个源是流的,例如日志文件,它会表现很好。
  • Apache Sqoop : Sqoop 可以用来管理 Hadoop 和关系数据库、企业数据仓库、NoSQL 系统之间的数据。Sqoop 有不同的连接器,具有各自的数据存储,使用这些连接器,Sqoop 可以在 MapReduce 中导入和导出数据,并且可以以并行模式导入和导出数据。Sqoop 也是容错的。
  • Apache Storm:Apache Storm 为流媒体数据提供实时、可扩展、分布式的解决方案。Storm 支持数据驱动和自动化活动。Apache Storm 可以与任何编程语言一起使用,它保证了数据流的处理不会丢失数据。Storm 与数据类型无关,它处理任何数据类型的数据流。

服务编程

在分布式环境中编程很复杂,必须小心,否则会变得效率低下。为了在 Hadoop 中开发合适的分布式应用,我们有一些服务编程工具,它们提供了处理分发和资源管理方面的实用程序。我们将讨论的工具如下:

  • Apache Yarn
  • Apache 动物园管理员

ApacheYarn

另一个资源谈判者 ( Yarn)是在 Hadoop 2.x 版本的主要发布中的一场革命。Yarn 提供资源管理,应该被用作一个公共平台,用于在 Hadoop 集群中集成不同的工具和实用程序并管理它们。Yarn 是一个资源管理器,它是通过分离 MapReduce 的处理引擎和资源管理功能而创建的。它还为处理 MapReduce 之外的框架提供了平台,如 Storm、Spark 等。Yarn 内置支持多租户共享集群资源。Yarn 负责管理和监控工作负载,并管理 Hadoop 的高可用性功能。

Yarn 具有改进的功能,因此也可以针对流和实时分析进行调整,这在某些场景中是一个巨大的优势和需求。Yarn 也向后兼容现有的 MapReduce 应用。

由 Yarn 驱动的一些应用如下:

  • Apache Hadoop MapReduce
  • ApacheSpark
  • ApacheStorm
  • Apache Tez
  • Apache S4

Apache 动物园管理员

ZooKeeper 是一个分布式、开源的分布式应用协调服务。ZooKeeper 公开了一组简单的原语,分布式应用可以使用这些原语进行同步、配置、维护、分组和命名资源,以实现协调、高可用性和同步。ZooKeeper 在 Java 中运行,并且有 Java 和 c 的绑定。

HBase、Solr、Kata、Neo4j 等等,都是一些使用 Zookeeper 来协调活动的工具。

调度

Hadoop 系统可以有多个作业,这些作业必须被调度多次。Hadoop 作业的调度很复杂,很难创建、管理和监控。我们可以使用像 ozie 这样的系统来高效地协调和监控 Hadoop 作业,如下所述:

  • Apache Ouzie:Ouzie 是一个工作流和协调服务处理系统,允许用户管理多个作业以及用 MapReduce、Pig 和 Hive 编写的作业链,以及 java 程序和 shell sripts,并且可以将它们相互链接。Oozie 是一个可扩展、可扩展和数据感知的服务。Oozie 可以用来设置工作流的开始和结束规则,它还可以检测任务的完成情况。

数据分析和机器学习

在 Hadoop 中,对于一般的大数据,分析是关键的兴趣领域,因为 Hadoop 是处理复杂程序和算法以改进流程和业务的强大工具。数据分析可以识别深刻的见解,并有助于优化流程,在竞争中保持领先地位。由于 Hadoop 强大的处理特性,机器学习一直备受关注,并且在算法和技术方面的大量开发已经适用于 Hadoop。机器学习技术也用于预测分析。竞争组织需要数据分析和机器学习来在竞争中保持领先地位,一些研究人员,特别是生命科学领域的研究人员,需要处理基因和病历模式,以产生医学领域非常必要的重要和有用的见解和细节。机器人领域的研究人员也需要这样做,以便为执行和优化任务的机器提供智能。RHadoop 是一种与 Hadoop 集成的数据分析统计语言。Mahout 是一个在 Hadoop 中使用的开源机器学习 API。

  • Apache Mahout : Mahout 是一个可扩展的机器学习 API,有很多已经实现的机器学习库。Mahout 是一个孤立的项目,可以作为一个纯粹的机器学习库,但是当它与 Hadoop 集成时,Mahout 的力量会增强。Mahout 中常用的一些算法如下:
    • 建议
    • 使聚集
    • 分类

系统管理

部署、配置、管理和监控 Hadoop 集群需要专业的脚本知识,并且通常需要大量的人工工作和时间,但这是重复的。对于在 Hadoop 中执行这样的活动,我们可以使用 Ambari 等工具。

Apache Ambari

应用开发人员和系统集成商可以使用 Ambari 来管理 Hadoop 集群中的大多数管理活动。Ambari 是 Hadoop 生态系统中的一个开源框架,可用于安装、配置、部署、管理和监控 Hadoop 集群。Ambari 的主要动机是隐藏 Hadoop 集群管理的复杂性,并提供一个非常简单直观的网络用户界面。Ambari 的一个关键特性是它提供了 RESTful APIs,可以用来与其他外部工具集成,以实现更好的管理。

总结

在本章中,我们探讨了不同的层,以及在 Hadoop 生态系统中可以执行层功能的一些组件及其用法。

我们在非常高的层次上讨论了 Hadoop 系统,我们将在第 3 章Hadoop 的支柱——HDFS、MapReduce 和 Yarn中深入讨论 Hadoop 架构。

三、Hadoop 的支柱——HDFS、MapReduce 和 Yarn

我们在最后两章讨论了大数据、Hadoop 和 Hadoop 生态系统。现在,让我们讨论更多关于 Hadoop 架构的技术方面。Hadoop 架构极其灵活、可扩展和容错。Hadoop 成功的关键是它的架构允许数据按原样加载并以分布式方式存储,没有数据丢失,也不需要预处理。

我们知道 Hadoop 是分布式计算,是一个并行处理环境。Hadoop 架构可以分为两部分:存储和处理。Hadoop 中的存储由 Hadoop 分布式文件系统(HDFS)处理,处理由T7】MapReduce 处理,如下图所示:

Pillars of Hadoop – HDFS, MapReduce, and YARN

在本章中,我们将介绍 HDFS 概念、体系结构、一些关键特性、读写过程是如何发生的,以及一些示例。MapReduce 是 Hadoop 的核心,我们将涵盖架构、序列化数据类型、MapReduce 步骤或流程、各种文件格式以及编写 MapReduce 程序的示例。在这之后,我们将来到在 Hadoop 中最有前途的 Yarn,许多应用已经采用了 Yarn,这提升了 Hadoop 的能力。

HDFS

HDFS 是 Hadoop 中的默认存储文件系统,它是分布式的,设计相当简单,并且具有极高的可扩展性、灵活性和高容错能力。HDFS 架构具有主从模式,因此可以更好地管理和利用从节点。HDFS 甚至可以在商用硬件上运行,并且该体系结构接受一些节点可以关闭,并且仍然需要恢复和处理数据。HDFS 具有自愈过程和推测执行,这使得系统具有容错性,并且可以灵活地添加/移除节点,增加了可扩展性和可靠性。HDFS 被设计成最适合 MapReduce 编程。HDFS 的一个关键假设是移动计算比移动数据便宜。

HDFS 的特色

HDFS 的重要特征如下:

  • 可扩展性 : HDFS 可扩展到千兆字节甚至更多。HDFS 足够灵活,可以添加或删除节点,这可以实现可扩展性。
  • 可靠性和容错 : HDFS 将数据复制到一个可配置的参数中,这使得获得高可靠性的灵活性和增加系统的容错性,因为数据将存储在多个节点中,即使少数节点停机,也可以从其他可用节点访问数据。
  • 数据一致性 : HDFS 有 WORM ( 写一次,读多次)模型,简化了数据一致性,给出了高吞吐量。
  • 硬件故障恢复 : HDFS 假设集群中的一些节点可能会出现故障,并且具有良好的故障恢复流程,这使得 HDFS 即使在商用硬件中也能运行。HDFS 有故障转移流程,可以恢复数据和处理硬件故障恢复。
  • 可移植性 : HDFS 在不同的硬件和软件上都是可移植的。
  • 计算更接近数据 : HDFS 将计算过程移向数据,而不是将数据拉出来进行计算,这要快得多,因为数据是分布式的,非常适合 MapReduce 过程。

HDFS 建筑

HDFS 是由守护进程管理的,守护进程如下:

  • 名称节点:主进程
  • 数据节点:从进程
  • 检查点名称节点或辅助名称节点:检查点进程
  • 备份节点:备份名称节点

HDFS 架构如下图所示:

HDFS architecture

姓氏

NameNode 是 HDFS 的主进程守护服务器,负责协调 Hadoop 中所有与存储相关的操作,包括 HDFS 的读写操作。名称节点管理文件系统名称空间。名称节点保存所有文件块之上的元数据,并且其中数据块的所有节点都存在于集群中。名称节点不存储任何数据。名称节点缓存数据并将元数据存储在内存中,以便更快地访问,因此它需要一个具有高内存的系统,否则名称节点会成为集群处理的瓶颈。

名称节点在 HDFS 是一个非常关键的过程,并且是单点故障,但是 HDFS 可以配置为 HDFS 高可用性,这允许两个名称节点,其中一个在某个时间点只能处于活动状态,另一个将处于待机状态。备用名称节点将获得更新和数据节点状态,这使得备用名称节点可以在名称节点的活动节点出现故障时接管和恢复。

名称节点维护以下两个元数据文件:

  • Fsimage 文件:保存整个文件系统名称空间,包括块到文件和文件系统属性的映射
  • 编辑日志文件:这个保存文件系统元数据发生的每一个变化

当 NameNode 启动时,它从磁盘读取FsImageEditLog文件,将EditLog中的所有事务合并到FsImage中,并将这个新版本刷新到磁盘上的新FsImage中。然后,它可以截断旧的EditLog,因为它的事务已经应用于持久的FsImage

数据节点

数据节点保存 HDFS 的实际数据,还负责创建、删除和复制数据块,由名称节点分配。数据节点向名称节点发送消息,这些消息被称为周期间隔内的心跳。如果数据节点未能发送心跳消息,则名称节点会将其标记为死节点。如果数据节点中的文件数据小于复制因子,则名称节点会将文件数据复制到其他数据节点。

DataNode

图片来源:http://yoyoclouds . files . WordPress . com/2011/12/Hadoop _ arch . png

检查点名称节点或辅助名称节点

检查点名称节点,早期称为辅助名称节点,是一个经常合并FsImageEditLog文件的数据检查点的节点,在任何名称节点出现故障时可用于名称节点。检查点名称节点收集并存储最新的检查点。存储后,它合并元数据中的更改,使其可用于名称节点。检查点名称节点通常必须是一个单独的节点,并且它需要与名称节点类似的配置机器,因为内存需求与名称节点相同。

备份节点

BackupNode 与 Checkpoint NameNode 类似,但它将FsImage的更新副本保存在 RAM 内存中,并始终与 NameNode 同步。备份节点的内存需求与命名节点相同。在高可用性方面,备份节点可以配置为热备用节点,动物园管理员协调将备份节点作为故障转移名称节点。

HDFS 的数据存储

在 HDFS,文件被分成块,存储在多个数据节点中,它们的元数据存储在名称节点中。为了理解 HDFS 是如何工作的,我们需要了解一些参数以及为什么使用它。参数如下:

  • 区块:文件分为多个区块。在 HDFS,块是可配置的参数,我们可以在这里设置值,文件将按块大小划分:在 2.2.0 之前的版本中,默认块大小为 64 MB,在 Hadoop 2.2.0 之后的版本中,默认块大小为 128 MB。数据块大小较高,可以最大限度地减少磁盘寻道时间的成本(速度较慢),利用传输速率(可能较高),并减少文件在名称节点中的元数据大小。
  • 复制:之前分割的每个文件块都存储在多个数据节点中,我们可以配置复制因子的数量。默认值为3。复制因素是实现容错的关键。复制因子的数量越多,系统的容错性就越高,并且会占用文件保存的大量时间,还会增加 NameNode 中的元数据。我们要平衡复制因素,不能太高也不能太低。

读取管道

HDFS 读取过程如下图所示:

Read pipeline

HDFS 读取过程包括以下六个步骤:

  1. 使用 Hadoop 客户端应用编程接口的分布式文件系统对象的客户端调用open(),启动读取请求。
  2. 分布式文件系统名称节点连接。名称节点标识要读取的文件的块位置以及块所在的数据节点命名节点然后按照距离客户端最近的数据节点的顺序发送数据节点列表
  3. 分布式文件系统然后创建 FSDataInputStream 对象,该对象反过来包装一个 DFSInputStream ,该 DFSInputStream 可以连接到所选的数据节点,并获取块,然后返回到客户端。客户端通过调用 FSDataInputStreamread()发起转账。
  4. FSDataInputStream 反复调用read()方法获取块数据。
  5. 当到达数据块的末尾时, DFSInputStream 关闭来自数据节点的连接,并为下一个数据块识别最佳数据节点。
  6. 当客户端读取完毕后,会在 FSDataInputStream 上调用close()关闭连接。

写流水线

HDFS 写流水线流程总结如下图:

Write pipeline

HDFS 写流水线流程描述如下七个步骤:

  1. 客户端使用 Hadoop 客户端应用编程接口的分布式文件系统对象,调用create(),启动写请求。
  2. 分布式文件系统名称节点连接。名称节点启动新文件创建,并在元数据中创建新记录,并启动类型为 FSDataOutputStream 的输出流,该输出流包装 DFSOutputStream 并将其返回给客户端。在启动文件创建之前,名称节点检查文件是否已经存在,客户端是否有权限创建新文件,如果任何条件为真,则向客户端抛出一个 IOException。
  3. 客户端使用 FSDataOutputStream 对象写入数据,并调用write()方法。 FSDataOutputStream 对象是 DFSOutputStream,处理与数据节点和名称节点的通信。
  4. DFSOutputStream 将文件分割成块,并用名称节点进行协调,以识别数据节点和副本数据节点。复制因子的数量将是标识的数据节点的数量。数据将分组发送到一个数据节点,该数据节点将相同的分组发送到第二个数据节点,第二个数据节点将发送到第三个,以此类推,直到确定数据节点的数量。
  5. 当所有数据包被接收和写入时,数据节点向发送方数据节点向客户端发送确认数据包。DFSOutputStream 在内部维护一个队列,以检查数据包是否被数据节点成功写入。如果没有收到确认或者数据节点在写入时失败,DFSOutputStream 也会进行处理。
  6. 如果所有数据包都已成功写入,客户端将关闭流。
  7. 如果该过程完成,则分布式文件系统对象通知名称节点该状态。

HDFS 有一些重要的概念,使架构容错和高度可用。

机架感知

HDFS 是容错的,这可以通过跨节点配置机架感知来增强。在大型 Hadoop 集群系统中,数据节点将跨多个机架,可在 HDFS 进行配置,以识别数据节点的机架信息。在最简单的形式中,可以通过使用一个脚本使 HDFS 知道机架,该脚本可以为节点的 IP 地址返回机架地址。要设置试管架映射脚本,请在conf/hadoop-site.xml中指定键topology.script.file.name,它必须是可执行脚本或程序,应提供运行命令以返回试管架标识。

Hadoop 中的机架标识是分层的,看起来像路径名。默认情况下,每个节点的机架标识为/default-rack。您可以将节点的机架号设置为任意路径,例如/foo/bar-rack。更靠左的路径元素在树的上方。因此,大型安装的合理结构可能是/top-switch-name/rack-name。Hadoop 机架标识将用于查找副本放置的远近节点。

机架意识在 HDFS 的优势

机架感知可用于在整个机架出现故障时防止数据丢失,并在读取文件时识别存在数据块的最近节点。为了实现高效的机架感知,一个节点不能有同一个数据块的两个副本,在一个机架中,一个数据块最多可以存在于两个节点中。用于数据块复制的机架数量应始终少于数据块副本的总数。

考虑以下情况:

  • 写入块:创建新块时,第一个副本放在本地节点上,第二个副本放在不同的机架上,第三个副本放在本地机架的不同节点上
  • 读取数据块:对于读取请求,与正常读取过程一样,NameNode 按照距离客户端较近的数据节点的顺序发送数据节点列表,因此优先选择同一机架的数据节点

为了验证数据块是否损坏,HDFS 进行了块扫描。每个数据节点都会检查其中存在的数据块,并使用在数据块创建过程中生成的存储校验和进行验证。在 HDFS 客户端读取数据块并且数据节点收到结果通知后,也会验证校验和。Block Scanner 计划运行三周,也可以进行配置。

如果发现数据块损坏,将通知名称节点,名称节点会将数据节点中的数据块标记为损坏,并启动数据块的复制,一旦创建了一个良好的拷贝并通过校验和验证,该数据节点中的数据块将被删除。

HDFS 联邦

我们已经讨论过名称节点与数据节点紧密耦合,是 Hadoop 1 中的 SPOF T2(T3)单点故障 T4。 x 。让我们试着理解 HDFS 1.0 的局限性来理解 HDFS 联邦的必要性。

HDFS 1.0 的局限性

以下是一些限制:

  • 文件数量的限制:尽管 HDFS 可以有成百上千个节点,但是由于 NameNode 将元数据保存在内存中,因此可以存储的文件数量会受到限制,这取决于分配给 NameNode 的映射堆内存。这种限制是由单个名称节点引起的。
  • 单一命名空间:由于单一命名空间,NameNode 无法委派任何工作负载,可能成为瓶颈。
  • SPOF : NameNode 是单点故障,因为它很关键,NameNode 可能会有太多的工作负载。
  • 不能运行非 MapReduce 应用 : HDFS 只设计运行 MapReduce 进程的应用或者基于 MapReduce 框架的应用。

名称节点只有一个名称空间,与数据节点紧密耦合,因为所有的请求都必须与名称节点协调才能获得块的位置,因此它可能成为瓶颈。名称节点必须高度可用,否则请求将无法得到服务。HDFS 联盟是一项功能,它使 Hadoop 能够拥有独立的多个命名空间,克服了我们讨论的限制。让我们看看下面的图片:

Limitations of HDFS 1.0

通过多个独立的名称空间层次结构,名称节点的责任在多个名称空间之间共享,这些名称空间是联合的,但共享集群的数据节点。由于名称节点的联合,一些请求可以在名称节点之间获得负载平衡。联合名称节点在多租户架构中工作,以提供隔离。

HDFS 联邦的利益

读取和写入过程由于多个名称节点而更快,避免了单个名称节点过程中的瓶颈。

水平可伸缩性是由 HDFS 联邦实现的,它有一个巨大的优势,即它是一个高度可用的进程,也可以充当负载平衡器。

HDFS 港口

在 Hadoop 生态系统中,组件有不同的端口,通信通过各自的端口进行。通常,端口号会很难记住。

默认的 HDFS web UI 端口汇总于的 Hortonworks 文档中。

|

服务

|

服务器

|

使用的默认端口

|

草案

|

描述

|

需要最终用户访问吗?

|

配置参数

|
| --- | --- | --- | --- | --- | --- | --- |
| WebUI 名称节点 | 主节点(名称节点和任何备份名称节点) | Fifty thousand and seventy | 超文本传送协议(Hyper Text Transport Protocol 的缩写) | 查看 HDFS 的当前状态,探索文件系统 | 是(通常是管理员、开发/支持团队) | dfs.http.address |
| Fifty thousand four hundred and seventy | https | 安全 http 服务 | dfs.https.address |
| 名称节点元数据服务 | 主节点(名称节点和任何备份名称节点) | 8020/9000 | 工业程序控制( industrial process control 的缩写) | 文件系统元数据操作 | 是(所有直接需要与 HDFS 互动的客户) | 嵌入在由 fs.default.name 指定的 URI 中 |
| 数据节点 | 所有从节点 | Fifty thousand and seventy-five | 超文本传送协议(Hyper Text Transport Protocol 的缩写) | 访问状态、日志等。 | 是(通常是管理员、开发/支持团队) | dfs.datanode.http.address |
| Fifty thousand four hundred and seventy-five | https | 安全 http 服务 | dfs.datanode.https.address |
| Fifty thousand and ten |   | 数据传送 |   | dfs.datanode.address |
| Fifty thousand and twenty | 工业程序控制( industrial process control 的缩写) | 元数据操作 | 不 | dfs.datanode.ipc.address |
| 检查站名称节点或者辅助名称节点 | 辅助名称节点和任何备份辅助名称节点 | Fifty thousand and ninety | 超文本传送协议(Hyper Text Transport Protocol 的缩写) | 名称节点元数据的检查点 | 不 | dfs.secondary.http.address |

HDFS 命令道

Hadoop 命令行环境类似于 Linux。Hadoop 文件系统(fs)提供各种外壳命令来执行文件操作,例如复制文件、查看文件内容、更改文件所有权、更改权限、创建目录等。

Hadoop fs shell 命令的语法如下:

hadoop fs <args>

  1. 在 HDFS 的给定路径上创建一个目录:

    • 用法:

      hadoop fs -mkdir <paths>
      
      
    • 示例:

      hadoop fs -mkdir /user/shiva/dir1 /user/shiva/dir2
      
      
  2. 列出目录的内容:

    • 用法:

      hadoop fs -ls <args>
      
      
    • 示例:

      hadoop fs -ls /user/shiva
      
      
  3. 在 HDFS 存档和获取文件:

    • 用法(放):

      hadoop fs -put <localsrc> ... <HDFS_dest_Path>
      
      
    • 示例:

      hadoop fs -put /home/shiva/Samplefile.txt  /user/shiva/dir3/
      
      
    • 用法(获取):

      hadoop fs -get <hdfs_src> <localdst>
      
      
    • 示例:

      hadoop fs -get /user/shiva/dir3/Samplefile.txt /home/
      
      
  4. 参见文件内容:

    • 用法:

      hadoop fs -cat <path[filename]>
      
      
    • 示例:

      hadoop fs -cat /user/shiva/dir1/abc.txt
      
      
  5. 将文件从源复制到目标:

    • 用法:

      hadoop fs -cp <source> <dest>
      
      
    • 示例:

      hadoop fs -cp /user/shiva/dir1/abc.txt /user/shiva/dir2
      
      
  6. 将文件从/复制到本地文件系统到 HDFS:

    • copyFromLocal 的用法:

      hadoop fs -copyFromLocal <localsrc> URI
      
      
    • 示例:

      hadoop fs -copyFromLocal /home/shiva/abc.txt  /user/shiva/abc.txt
      
      
    • copyToLocal 的用法

      hadoop fs -copyToLocal [-ignorecrc] [-crc] URI <localdst>
      
      
  7. 将文件从源移动到目标:

    • 用法:

      hadoop fs -mv <src> <dest>
      
      
    • 示例:

      hadoop fs -mv /user/shiva/dir1/abc.txt /user/shiva/dir2
      
      
  8. 删除 HDFS 的文件或目录:

    • 用法:

      hadoop fs -rm <arg>
      
      
    • 示例:

      hadoop fs -rm /user/shiva/dir1/abc.txt
      
      
    • 删除递归版本的用法:

      hadoop fs -rmr <arg>
      
      
    • 示例:

      hadoop fs -rmr /user/shiva/
      
      
  9. 显示文件的最后几行:

    • 用法:

      hadoop fs -tail <path[filename]>
      
      
    • 示例:

      hadoop fs -tail /user/shiva/dir1/abc.txt
      
      

MapReduce

MapReduce 是一个大规模并行处理框架,可以处理分布式环境中更快、可扩展和容错的数据。与 HDFS 类似,Hadoop MapReduce 甚至可以在商用硬件中执行,并假设节点随时可能出现故障,但仍能处理作业。MapReduce 可以并行处理大量数据,方法是将一个任务分成独立的子任务。MapReduce 也有主从架构。

输入和输出,甚至是 MapReduce 作业中的中间输出,都是以<KeyValue >对的形式。键和值必须是可序列化的,并且不使用 Java 序列化包,但是必须有一个接口,该接口必须实现,并且可以有效地序列化,因为数据处理必须从一个节点移动到另一个节点。键必须是实现可写可比接口的类,这是对键进行排序所必需的,值必须是实现可写接口的类。

MapReduce 架构

MapReduce 架构有以下两个守护进程:

  • 作业跟踪器:主流程
  • 任务跟踪器:从进程

工作跟踪者

JobTracker 是主协调器守护进程,负责协调和完成 Hadoop 中的一个 MapReduce 作业。JobTracker 的主要功能是资源管理、跟踪资源可用性和任务流程周期。作业跟踪器识别任务跟踪器来执行某些任务,并监控任务的进度和状态。JobTracker 是 MapReduce 进程的单点故障。

任务跟踪器

任务跟踪器是执行作业跟踪器分配的任务的从守护进程。任务跟踪器定期向作业跟踪器发送心跳消息,以通知空闲插槽,并将任务的状态发送给作业跟踪器,并检查是否有任何任务必须执行。

序列化数据类型

MapReduce 中的序列化极其重要,因为数据和中间数据必须在非常大的规模上从一个 TaskTracker 移动到另一个 task tracker。Java 序列化没有优化,因为即使对于较小的值,对象序列化程序也会有较大的大小,这可能是 Hadoop 性能的瓶颈,因为 Hadoop 处理需要大量数据传输。因此,Hadoop 不使用 Java 序列化包,而是使用可写接口。

对于序列化,Hadoop 使用以下两个接口:

  • 可写接口(对于值)
  • 可写可比较接口(用于按键)

可写界面

可写接口用于序列化和反序列化的值。实现可写接口的类有ArrayWritableBooleanWritableByteWritableDoubleWritableFloatWritableIntWritableLongWritableMapWritableNullWritableObjectWritableShortWritableTupleWritableVIntWritableVLongWritable

我们可以创建自己的自定义可写类,可以在 MapReduce 中使用。为了创建类,我们必须实现可写类,并实现以下两种方法:

  • void write (DataOutput out):这将序列化对象
  • void readFields (DataInput in):读取输入流并将其转换为对象

可写可比界面

WritableComparable 用于键,它是从可写接口继承而来的,实现了一个可比较的接口来提供值对象的比较。一些实现是BooleanWritableBytesWritableByteWritableDoubleWritableFloatWritableIntWritableLongWritableNullWritableShortWritableTextVIntWritableVLongWritable

我们可以创建自己的自定义可写可比较类,可以在 MapReduce 中使用。为了创建一个类,我们必须实现 WritableComparable 类,并实现以下三种方法:

  • void write (DataPutput out):这将序列化对象
  • void readFields (DataInput in):读取输入流并将其转换为对象
  • Int compareTo (Object obj):比较排序关键字所需的值

MapReduce 示例

MapReduce 最初很难理解,所以我们将尝试用一个简单的例子来理解它。假设我们有一个文件,其中包含一些单词,并且该文件在 HDFS 被划分为多个块,我们必须计算一个单词在该文件中出现的次数。我们将逐步使用 MapReduce 功能来实现这个结果。整个过程如下图所示:

The MapReduce example

类型

下载示例代码

您可以从您在http://www.packtpub.com的账户下载您购买的所有 Packt Publishing 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问http://www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

以下为上图描述:

  1. Each block will be processed. Each line in the block will be sent as an input to the process. This process is called as Mapper.

    映射器解析该行,获取一个单词并为每个单词设置<<word>, 1>。在本例中,一行苹果橙芒果的 Mapper 输出将是<苹果、1 >、<橙子、1 >和<芒果、1 >。所有地图工具的关键字为单词,数值为 1。

  2. The next phase is where the output of Mapper, which has the same key will be consolidated. So key with Apple, Orange, Mango, and others will be consolidated, and values will be appended as a list, in this case

    <Apple, List<1, 1, 1, 1>>, <Grapes, List<1>>, <Mango, List<1, 1>>, and so on

    Mappers 生成的关键字将被比较和排序。这一步叫做洗牌和排序。密钥和值列表将被发送到密钥排序序列中的下一步。

  3. 下一阶段将获得<key, List<>>作为输入,并将只计算列表中 1 的数量,并将计数值设置为输出。这个步骤被称为减速器,例如,某些步骤的输出如下:

    • <Apple, List<1, 1, 1, 1>> will be <Apple, 4>
    • <Grapes, List<1>> will be < Grapes, 1>
    • <Mango, List<1, 1>> will be <Mango, 2>
  4. 减速器输出将合并到一个文件中,并作为最终输出保存在 HDFS。

MapReduce 过程

MapReduce 框架有多个步骤和流程或任务。对于程序员来说,MapReduce 抽象了其中的大部分,在许多情况下,只需要关心两个过程;映射和简化为了协调这个过程,必须编写一个驱动类程序。在驱动程序类中,我们可以从输入、映射器类、减少器类、输出和执行映射减少作业所需的其他参数中设置运行映射减少作业的各种参数。

MapReduce 作业复杂,涉及多个步骤;有些步骤是由 Hadoop 以默认行为执行的,如果需要可以被覆盖。以下是在 MapReduce 中按顺序执行的强制步骤:

  1. 制图人
  2. 无序播放和排序
  3. 还原剂

下图解释了上述过程:

The MapReduce process

图片来源:来自雅虎的 Hadoop 教程!

文件夹

在 MapReduce 中,并行性将由 Mapper 实现,其中 Mapper 功能将出现在 TaskTracker 中,TaskTracker 将处理一个 Mapper。映射器代码应该有一个逻辑,它可以独立于其他块数据。映射器逻辑应该利用算法中所有可能的并行步骤。映射器的输入是在映射器进程必须运行的特定输入格式类型和文件的驱动程序中设置的。Mapper 的输出将是一个地图<key, value>keyvalue在 Mapper 输出中设置的地图不保存在 HDFS,但是在操作系统空间路径中创建了一个中间文件,并且该文件被读取,并且进行洗牌和排序。

洗牌和排序

Shuffle 和 sort 是 MapReduce 中 Mapper 和 Reduce 之间的中间步骤,由 Hadoop 处理,如果需要可以覆盖。无序播放过程通过对映射器输出的键值进行分组来聚合所有映射器输出,该值将被追加到值列表中。因此,Shuffle 输出格式将是一个地图<key, List<list of values>>。映射器输出的关键字将被合并和排序。映射器输出将使用排序键序列发送到减速器,默认为HashPartitioner,这将以排序序列的减速器数量序列的循环方式发送映射器结果。

减速器

在 MapReduce 中,Reducer 是聚合器进程,其中经过洗牌和排序后的数据被发送到 Reducer,在这里我们有<key, List<list of values >>,Reducer 将在值列表中进行处理。每把钥匙都可以送到不同的减速器。Reduce 可以设置该值,该值将合并到 MapReduce 作业的最终输出中,该值将作为最终输出保存在 HDFS。

投机性执行

正如我们所讨论的,MapReduce 作业被分解为多个 Mapper 和 Reduce 进程,以及一些中间任务,这样一个作业可以产生数百或数千个任务,而一些任务或节点可能需要很长时间才能完成一个任务。Hadoop 监控并检测任务何时运行速度慢于预期,如果该节点有执行任务速度慢的历史,那么它会在另一个节点启动相同的任务作为备份,这被称为任务的推测执行。Hadoop 不会试图修复或诊断节点或进程,因为进程不会给出错误,但它很慢,并且由于硬件降级、软件错误配置、网络拥塞等原因,可能会出现缓慢。对于推测性执行,作业跟踪器在所有任务启动后监控任务,并识别执行缓慢的任务,监控其他正在运行的任务。一旦执行缓慢的任务被标记,作业跟踪器在不同的节点启动任务,并获取先完成的任务的结果,杀死其他任务并记录情况。如果一个节点始终落后,那么作业跟踪器对该节点的偏好就会降低。

可以启用或禁用推测执行,默认情况下,它是打开的,因为它是一个有用的过程。推测性执行必须监视每个任务,在某些情况下会影响性能和资源。在任务(尤其是缩减器)由于特定缩减器上的数据偏斜而可能获得数百万个值的作业中,不建议进行推测执行,因为这将比其他任务花费更长的时间,并且启动另一个任务也无济于事。另一种情况可能是一个 Sqoop 流程,其中一个任务导入数据,如果它花费的时间超过通常的时间,它可以在另一个节点启动相同的任务,并将导入相同的数据,这将导致重复的记录。

文件格式

文件格式控制 MapReduce 程序中的输入输出。一些文件格式可以被认为是数据结构。Hadoop 提供了一些实现的文件格式,我们也可以编写自己的自定义文件格式。我们将在下一节中看到它们。

输入格式

映射器过程步骤提供了并行性,为了更快地处理,映射器必须进行优化设计。为了独立执行数据,映射器的输入数据被分成称为输入分割的块。InputSplit 可以被认为是输入数据的一部分,在这里数据可以被独立处理。映射器对输入的数据进行处理。MapReduce 作业的输入必须被定义为实现 InputFormat 接口的类,有时需要 RecordReader 在拆分之间读取数据,以从输入数据文件中识别独立的数据块。

Hadoop 已经有了不同类型的 InputFormat,用于解释各种类型的输入数据和从输入文件中读取数据。InputFormat 将输入文件拆分为输入到地图任务的片段。实现的输入格式类的例子如下:

  • TextInputFormat 用于逐行读取文本文件
  • SequenceFileInputFormat 用于读取二进制文件格式
  • DBInputFormat 子类是一个可以用来从 SQL 数据库中读取数据的类
  • CombineFileInputFormat 是 FileInputFormat 类的抽象子类,可用于将多个文件合并为一个拆分

我们可以通过实现输入格式接口或扩展任何实现输入格式的类来创建自己的自定义输入格式类。扩展类是首选,因为编写的许多函数都是可重用的,这有助于代码的可维护性和可重用性。该类必须重写以下两个函数:

  • public RecordReader createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException
  • protected boolean isSplitable(JobContext context, Path file)

录音机

InputFormat 拆分数据,但是拆分并不总是整齐地结束在一行的末尾。记录读取器可以允许数据,即使该行跨越了分割的末尾,否则可能会丢失可能已经跨越了输入分割边界的记录。

下图解释了 RecordReader 的概念,其中块大小为 128 MB,拆分大小为 50 MB:

RecordReader

我们可以看到不同块之间存在数据分割的重叠。分割 1 和 2 可以从块 1 读取,但是对于分割 3,记录读取器必须从 101 兆字节本地读取到 128 兆字节,从 129 兆字节到 150 兆字节必须从块 2 远程读取,合并的数据将作为输入发送到映射器。

输出格式

OutputFormat 实现类负责写一个 MapReduce 作业的输出和结果,它给出了你想要如何高效地写记录以优化结果的控制,并且可以用来写数据的格式以便与其他系统互操作。默认的输出格式是文本输出格式(我们将它用作我们的字数示例的输出),它是由行分隔和制表符分隔的键值对。TextOutputFormat 可以在许多用例中使用,但不能以优化或有效的方式使用,因为它会浪费空间,并会使输出大小变大,从而提高资源利用率。因此,我们可以重用 Hadoop 提供的一些输出格式,甚至可以编写自定义的输出格式。

一些广泛使用的输出格式如下:

  1. 所有输出格式的文件输出格式(实现接口输出格式)基类

    • MapFileOutputFormat

    • SequenceFileOutputFormat

      SequenceFileAsBinaryOutputFormat

    • 文本输出格式

    • MultipleOutputFormat

      multiplatextoutputformat

      多重序列输出格式

  2. SequenceOutputFormat 可用于对象的二进制表示,它会将其压缩并作为输出写入。OutputFormats 使用 RecordWriter 的实现来实际写入数据。

记录作者

RecordWriter 接口提供了更多的控制,可以按照我们想要的方式写入数据。RecordWriter 将输入作为键值对,可以转换要写入的数据的格式。

RecordWriter 是一个抽象类,它有两个要实现的方法,如下所示:

abstract void write(K key, V value) Writes a key/value pair.
abstract void close(TaskAttemptContext context) Close this RecordWriter to future operations.

默认的记录写入程序是行记录写入程序。

编写 MapReduce 程序

一个 MapReduce 作业类将有以下三个强制类或任务:

  • Mapper :在 Mapper 类中,编写实际的独立步骤,并行化运行在独立的子任务中
  • Reducer :在 Reducer 类中,进行映射器输出的聚合,并将输出写入 HDFS
  • 驱动程序:在驱动程序类中,我们可以从输入、映射器类、缩减器类、输出以及 MapReduce 作业执行所需的其他参数中设置运行 MapReduce 作业的各种参数

我们已经看到了一个简单的字数示例的逻辑来说明 MapReduce 是如何工作的。现在,我们将看到如何在 Java MapReduce 程序中对其进行编码。

映射器代码

映射器类必须扩展

org.apache.hadoop.mapreduce.Mapper<KEYIN,VALUEIN,KEYOUT,VALUEOUT>.

以下是映射器类代码的片段:

// And override 
public void map(Object key, Text value, Context context) throws IOException, InterruptedException
public static class WordCountMapper extends Mapper<Object, Text, Text, IntWritable> {

    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
      StringTokenizer token = new StringTokenizer(value.toString());
      while (token.hasMoreTokens()) {
        word.set(token.nextToken());
        context.write(word, one);
      }
    }
  }

在映射函数中,输入值(苹果、橘子、芒果)必须被标记化,标记化的单词将被写成映射键,值为 1。请注意,值 1 是可写的。

减速器代码

减速器类必须扩展

org.apache.hadoop.mapreduce.Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT>.

以下是单词 WordCountReducer 的代码:

 // and override reduce function
protected void reduce(KEYIN key, Iterable<VALUEIN> values,
org.apache.hadoop.mapreduce.Reducer.Context context) 
throws IOException, InterruptedException
public static class WordCountReducer
       extends Reducer<Text,IntWritable,Text,IntWritable> {
    private IntWritable count = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values,
                       Context context
                       ) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {
        sum += val.get();
      }
      count.set(sum);
      context.write(key, count);
    }
  }

Reducer 输入将是<word, List<1,1,…>>对于字数来说 Reducer 必须对值列表求和并写入值。减速器输出将作为关键字,值作为计数。

驱动程序代码

MapReduce 中的驱动代码大部分是参数刚刚变化的锅炉板代码,可能需要设置一些辅助类,如下图所示:

public static void main(String[] args) throws Exception {
  Configuration conf = new Configuration();
  Job job = Job.getInstance(conf, "word count");
  job.setJarByClass(WordCount.class);
  job.setMapperClass(WordCountMapper.class);
  job.setReducerClass(WordCountReducer.class);
  job.setOutputKeyClass(Text.class);
  job.setOutputValueClass(IntWritable.class);
  FileInputFormat.addInputPath(job, new Path(args[0]));
  FileOutputFormat.setOutputPath(job, new Path(args[1]));
  System.exit(job.waitForCompletion(true) ? 0 : 1);
}

驱动程序代码必须创建Configuration对象的实例,该实例用于获取Job类的实例。在Job类中,我们可以设置以下内容:

  • MapperClass
  • 减速器
  • OutputKeyClass
  • OutputValueClass
  • 输入格式
  • 输出格式
  • JarByClass

字数统计的整个程序如下:

import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordCount {

  public static class WordCountMapper
       extends Mapper<Object, Text, Text, IntWritable>{

    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
      StringTokenizer token = new StringTokenizer(value.toString());
      while (token.hasMoreTokens()) {
        word.set(token.nextToken());
        context.write(word, one);
      }
    }
  }

  public static class WordCountReducer extends Reducer<Text,IntWritable,Text,IntWritable> {
    private IntWritable count = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {
        sum += val.get();
      }
      count.set(sum);
      context.write(key, count);
    }
  }

  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    Job job = Job.getInstance(conf, "word count");
    job.setJarByClass(WordCount.class);
    job.setMapperClass(WordCountMapper.class);
    job.setReducerClass(WordCountReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    FileInputFormat.addInputPath(job, new Path(args[0]));
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}

编译WordCount.java并创建一个罐子。

运行应用:

$ bin/hadoop jar wc.jar WordCount /input /user/shiva/wordcount/output

输出:

$ bin/hdfs dfs -cat /user/shiva/wordcount/output/part-r-00000

辅助步骤

除了和映射器、混洗和排序以及缩减器,在 MapReduce 中还有其他可以设置的辅助步骤,或者可以覆盖默认实现来处理 MapReduce 作业。以下是我们将讨论的一些过程:

  • 组合器
  • 瓜分者ˌ分割者

下图中讨论了上述几点:

Auxiliary steps

合并

组合器是节点本地减速器。组合器用于减少 Mapper 设置的键值数量,我们可以减少为洗牌而发送的数据数量。许多程序将 Reducer 作为组合器类,如果需要,可以有不同于 Reducer 的实现。组合器是使用job.setCombinerClass(CombinerClassName)为作业指定的。

组合器应该具有与映射器的输出类型相同的输入/输出键和值类型。组合器只能用于可交换的(a.b = b.a)和可关联的{a. (b.c) = (a.b).c}函数。

在 WordCount 示例中,我们可以使用一个组合器,它可以与 Reducer 类相同,并将提高作业的性能。

组合器不会总是由作业跟踪器处理。如果映射器中的数据溢出,那么组合器肯定会被调用。

分区

分割器负责将特定的键值对发送到特定的减压器。HashPartitioner是默认的 Partitioner,它根据 reduce 的数量(如果指定的话)对记录的键进行散列,以循环方式确定记录属于哪个分区,或者分区的数量等于作业的 reduce 任务的数量。有时需要分区来控制映射器中的键值对移动到特定的缩减器。分区对我们要运行的作业的整体性能有直接的影响。

自定义分割器

假设我们想根据标记出现的次数对字数的输出进行排序。假设我们的工作将由两个减速器处理,如下所示:

减速器的设置数量:我们可以通过job.setNumReduceTasks(#NoOfReducucer)来指定。

如果我们在不使用任何用户定义的分区器的情况下运行作业,我们将获得如下输出:

|

数数

|

单词

|

数数

|

单词

|
| --- | --- | --- | --- |
| one | 这 | Two | a |
| three | 是 | four | 因为 |
| six | 如同 | five | 关于 |
| 减速器 1 | 减速器 2 |

这是部分排序,是HashPartitioner的默认行为。如果我们使用正确的分区函数,我们可以将小于或等于 3 的计数发送给一个减速器,而将更高的计数发送给另一个减速器,我们必须将setNumReduceTasks设置为2。我们将得到发生次数的总顺序。

输出如下所示:

|

数数

|

单词

|

数数

|

单词

|
| --- | --- | --- | --- |
| one | 这 | four | 因为 |
| Two | A | five | 如同 |
| three | 是 | six | 关于 |
| 减速器 1 | 减速器 2 |

我们来看看如何才能编写一个自定义的Partitioner类,如下图所示:

public static class MyPartitioner extends   org.apache.hadoop.mapreduce.Partitioner<Text,Text>

{
  @Override
  public int getPartition(Text key, Text value, int numPartitions)
  {
   int count =Integer.parseInt(line[1]);
   if(count<=3)
    return 0;
   else
    return 1;
  }
}

And in Driver class
job.setPartitionerClass(MyPartitioner.class);

Yarn

Yarn 是又一个资源协商者,下一代计算和集群管理技术。Yarn 提供了一个在 Hadoop 中构建/运行多个分布式应用的平台。2012 年在 Hadoop 2.0 版本中发布了 Yarn,标志着 Hadoop 架构的重大改变。Yarn 花了大约 5 年时间在一个开放的社区发展。

我们讨论了作业跟踪器是 MapReduce 的单点故障,考虑到 Hadoop 被设计为即使在商品服务器上也能运行,作业跟踪器很有可能会失败。JobTracker 有两个重要的功能:资源管理,以及作业调度和监控。

Yarn 委托和分割责任到单独的守护程序,并实现更好的性能和容错。由于 Yarn,Hadoop 只能作为批处理工作,现在可以被设计成处理交互式和实时处理系统。这是一个巨大的优势,因为许多系统、机器、传感器和其他来源会不断产生大量的数据流,而 Yarn 可以处理这些数据,如下图所示:

YARN

图片来源:http://hortonworks.com/wp-content/uploads/2013/05/yarn.png

Yarn 架构

与 MapReduce 1 相比,YARN 架构具有极高的可扩展性、容错性和更快的数据处理速度。 x 。Yarn 侧重于集群中资源的高可用性和利用率。Yarn 架构有以下三个组成部分:

  • 资源管理器 ( RM )
  • 节点管理器 ( NM )
  • 应用大师 ( AM )

下图说明了 Yarn 的结构:

YARN architecture

图片来源:http://Hadoop . Apache . org/docs/current/Hadoop-SHARE/Hadoop-SHARE-site/SHARE . html

资源管理器

在 Yarn 中,ResourceManager 是负责系统中应用间资源管理的主进程管理器。ResourceManager 有一个调度器,它只将资源分配给应用,以及 ResourceManager 从提供内存、磁盘、CPU、网络等信息的容器中获得的资源可用性。

节点管理器

在 Yarn 中,节点管理器存在于所有节点中,负责容器、认证、监控资源使用情况,并将信息报告给资源管理器。与任务跟踪器类似,节点管理器向资源管理器发送心跳。

ApplicationMaster

ApplicationMaster 存在于每个应用中,负责管理运行在 Yarn 内的应用的每个实例。ApplicationMaster 与 ResourceManager 协调资源的协商,并与 NodeManager 协调监控容器的执行和资源消耗,如 CPU、内存的资源分配等。

由 Yarn 驱动的应用

在下面是一些应用,它们已经调整了 Yarn 来利用其功能并实现高可用性:

  • Apache·吉拉夫:图形处理
  • Apache 哈马:高级分析
  • Apache Hadoop MapReduce :批处理
  • Apache Tez :Hive 顶部的交互/批处理
  • Apache S4 :流处理
  • Apache Samza :流处理
  • ApacheStorm:流处理
  • Apache Spark :实时迭代处理
  • 霍亚:Hbase on SHARE

总结

在这一章中,我们详细讨论了 HDFS、MapReduce 和 Yarn。

HDFS 具有高度的可扩展性、容错性、可靠性和可移植性,甚至可以在商用硬件上工作。HDFS 体系结构有四个守护进程,分别是名称节点、数据节点、检查点名称节点和备份节点。HDFS 面临许多复杂的设计挑战,这些挑战由不同的技术管理,如复制、心跳、数据块概念、机架感知和数据块扫描程序,HDFS 联邦使 HDFS 具有高可用性和容错性。

Hadoop MapReduce 还具有高度的可扩展性、容错性,甚至可以在商用硬件中工作。MapReduce 架构在节点中有一个主任务跟踪器和多个工作任务跟踪器进程。MapReduce 作业分为多步进程,包括映射器、洗牌器、排序器、缩减器以及辅助合并器和分割器。MapReduce 作业需要大量的数据传输,为此 Hadoop 使用了可写和可写的可比接口。MapReduce 文件格式具有输入格式接口、记录读取器、输出格式和记录写入器,以提高处理速度和效率。

Yarn 是一个分布式资源管理器,用于在 Hadoop 之上管理和运行不同的应用,并为 MapReduce 框架提供了急需的增强,这可以使 Hadoop 更加可用、可扩展和可集成。Yarn 架构有以下组件:资源管理器、节点管理器和应用主控器。许多应用都建立在 are 之上,这使得 Hadoop 更加稳定,并且可以与其他应用集成。

在下一章中,我们将介绍 Hadoop 生态系统中使用的数据访问组件技术,如 Hive 和 Pig,因为它有助于简化编程模型,并使其更快、更易维护。

四、数据访问组件——Hive 和 PIG

Hadoop 通常可以容纳万亿字节或千兆字节的数据进行处理;因此,数据访问在任何项目或产品中都是一个极其重要的方面,尤其是在 Hadoop 中。当我们处理大数据来处理数据时,我们将不得不执行一些临时处理来获得对数据和设计策略的见解。Hadoop 的基本处理层是 MapReduce,正如我们前面讨论的,它是一个大规模并行处理框架,具有可伸缩性、速度快、适应性强和容错性。

我们将详细了解 MapReduce 编程的一些限制和一些编程抽象层,如 Hive 和 Pig,它们可以使用用户友好的语言执行 MapReduce,以实现更快的开发和管理。当涉及到轻松地做一些特别的分析和一些不太复杂的分析时,Hive 和 PIG 是相当有用和方便的。

在 Hadoop 上需要一个数据处理工具

MapReduce 是对大数据进行处理的关键,但是理解、设计、编码和优化都很复杂。MapReduce 的学习曲线很高,需要掌握良好的编程技巧。通常大数据用户来自编程、数据库管理员、脚本、分析师、数据科学、数据管理人员等不同背景,并非所有用户都能适应 MapReduce 的编程模式。因此,我们对 Hadoop 的数据访问组件有不同的抽象。

数据访问组件对开发人员非常有用,因为他们可能不需要详细学习 MapReduce 编程,并且仍然可以在界面中利用 MapReduce 框架,在该界面中,他们可以更加舒适,并有助于更快的开发和更好的代码管理。抽象可以帮助快速地对数据进行临时处理,并专注于业务逻辑。

Hadoop 生态系统中广泛使用的两个数据访问组件是:

  • PIG
  • 储备

让我们通过一些例子来详细讨论其中的每一个。

PIG

Pig 是一个在 MapReduce 之上有 Pig 拉丁语言抽象包装的组件。PIG 是雅虎开发的!大约在 2006 年,作为一个开源项目被贡献给了 Apache。Pig Latin 是一种数据流语言,对于过程语言开发人员或用户来说更合适。Pig 可以帮助管理流中的数据,这对于数据流过程、ETL(提取转换加载)或 ELT(提取加载转换)过程特别数据分析是理想的。

Pig 可以以更简单的方式用于结构化和半结构化数据分析。Pig 的开发基于一种理念,即 pig 可以吃任何东西,住在任何地方,可以被用户轻松控制和修改,快速处理数据很重要。

PIG 数据类型

Pig 有原始数据类型的集合,也有复杂的数据类型。Pig 关系运算符的输入和输出使用以下数据类型指定:

  • 原语 : int、long、float、double、chararray 和 bytearray

  • Map: Map is an associative array data type that stores a chararray key and its associated value. The data type of a value in a map can be a complex type. If the type of the value cannot be determined, Pig defaults to the bytearray data type. The key and value association is specified as the # symbol. The key values within a map have to be unique.

    语法:[key#value, key1#value1…]

  • Tuple: A tuple data type is a collection of data values. They are of fixed length and ordered. Tuple is similar to a record in a SQL table, without restrictions on the column types. Each data value is called a field. Ordering of values offers the capability to randomly access a value within a tuple.

    语法:(value1, value2, value3…)

  • Bag: A bag data type is a container for tuples and other bags. They are unordered, that is, a tuple or a bag within a bag cannot be accessed randomly. There are no constraints on the structure of the tuples contained in a bag. Duplicate tuples or bags are allowed within a bag.

    语法:{(tuple1), (tuple2)…}

Pig 允许嵌套复杂的数据结构,您可以将元组嵌套在元组、包和映射中。PIG 拉丁语语句处理关系,可以认为是:

  • 关系(类似于数据库表)是一个包
  • 包是元组的集合
  • 元组(类似于数据库行)是一组有序的字段
  • 字段是一段数据

PIG 的建筑

Pig 数据流架构是分层的,用于将 Pig 拉丁语语句转换为 MapReduce 步骤。编译和执行 Pig 脚本有三个主要阶段,如下所示:

  • 逻辑计划
  • 物理计划
  • MapReduce 计划

逻辑计划

在逻辑计划中,对 Pig 语句进行语法错误解析,并验证输入文件和输入数据结构。然后准备一个逻辑计划,一个操作符作为节点的 DAG(有向无环图),以及作为边的数据流。基于内置规则的优化发生在这个阶段。逻辑计划与操作员一一对应。

物理计划

在这一阶段,每个操作者被转换成执行的物理形式。对于 MapReduce 平台,除了少数,大多数操作人员都与物理计划有一一对应关系。除了逻辑运算符,还有一些物理运算符。它们如下:

  • 局部重排
  • 全局重排
  • 包装

GROUPCOGROUPJOIN这样的逻辑运算符被翻译成一系列的LRGRP运算符。LR操作符对应于混洗准备阶段,在该阶段,基于密钥进行分区。GR对应于地图和减少任务之间的实际洗牌。P操作符是减少侧的分割操作符。

地图缩减计划

Pig 编译的最后阶段是将物理计划编译成实际的 MapReduce 作业。只要物理计划中存在LRGRP序列,就需要减少任务。编译器也会尽可能寻找机会放入 Combiners。上图中物理计划的 MapReduce 计划有两个 MapReduce 作业,一个对应于逻辑计划中的JOIN,另一个对应于GROUP。对应于GROUP操作符的 MapReduce 任务也有一个组合器。必须注意的是GROUP操作发生在地图任务中。

PIG 模式

用户可以通过两种模式运行 Pig:

  • 本地模式:通过访问一台机器,所有文件都使用本地主机和文件系统安装和运行。
  • MapReduce 模式:这是默认模式,需要访问 Hadoop 集群。

在 Pig 中有三种执行模式:

  • 交互模式或咕哝模式
  • 批处理模式或脚本模式
  • 嵌入模式:以 Python 或 JavaScript 等宿主语言嵌入 Pig 命令并运行程序

这些执行模式既可以在本地模式下执行,也可以在地图缩减模式下执行。

咕噜贝

咕噜是 PIG 的交互外壳。可用于交互输入 PIG 拉丁,为用户提供与 HDFS 交互的外壳。

对于本地模式:

使用-x标志指定本地模式:

$ pig –x local

对于 MapReduce 模式:

HADOOP_CONF_DIR置于PIG_CLASSPATH上,将小 PIG 指向远程集群。

类型

HADOOP_CONF_DIR是包含hadoop-site.xmlhdfs-site.xmlmapred-site.xml文件的目录。

示例:$ export PIG_CLASSPATH=<path_to_hadoop_conf_dir>

这里给出的是:

$ pig
grunt>

输入数据

我们将使用movies_data.csv文件作为探索 PIG 的数据集。输入文件包含以下字段和示例数据:

|

身份证明

|

名字

|

|

评级

|

持续时间(秒)

|
| --- | --- | --- | --- | --- |
| Forty thousand one hundred and forty-six | 奥斯卡的绿洲:耍鸡高手枪蜥蜴:爱情的渴望力量 | Two thousand and eleven |   | One thousand six hundred and one |
| Forty thousand one hundred and forty-seven | 变形金刚:救援机器人:第一季:恐龙机器人的回归 | Two thousand and eleven |   | One thousand three hundred and twenty-four |
| Forty thousand one hundred and forty-eight | 浮游生物入侵:温克尔行动、鳕鱼行动、硬壳行动 | Two thousand and twelve |   | One thousand two hundred and sixty-two |
| Forty thousand one hundred and forty-nine | 变形金刚:救援机器人:第一季:深度麻烦 | Two thousand and eleven |   | One thousand three hundred and twenty-four |
| Forty thousand one hundred and fifty | 预告片:揭开面 Yarn | Two thousand and twelve | Three point six | sixty-nine |
| Forty thousand one hundred and fifty-one | 预告片:痛苦 | Two thousand and twelve | Three point six | fifty-two |
| Forty thousand one hundred and fifty-two | 托德和《纯粹邪恶之书》 | Two thousand and ten | Three point nine |   |
| Forty thousand one hundred and fifty-three | 预告片:纸牌屋 | Two thousand and twelve | Three point seven | One hundred and forty-eight |

加载数据

对于在 Pig 中加载数据的,我们使用LOAD命令并将其映射到关系的别名(如本例中的电影),该别名可以从文件系统或 HDFS 读取数据,并将其加载到 Pig 中进行处理。Pig 中有不同的存储处理程序,通过提及USING和存储处理程序功能来处理不同类型的记录;一些常用的存储处理函数是:

  • PigStorage 用于带有可指定分隔符的结构化文本文件,是默认的存储处理程序
  • 用于处理来自糖化血红蛋白表的数据的糖化血红蛋白存储
  • BinStorage,用于二进制和机器可读格式
  • JSONStorage,用于处理 JSON 数据和应该指定的模式
  • 用于 UTF-8 的非结构化数据的文本加载器

如果我们没有默认提到任何处理程序,默认使用 PigStorage,PigStorage 和 TextStorage 支持压缩文件gzipbzip

示例:

grunt> movies = LOAD '/user/biadmin/shiva/movies_data.csv' USING PigStorage(',') as (id,name,year,rating,duration);

我们可以使用模式为字段分配类型:

A = LOAD 'data' AS (name, age, gpa); // name, age, gpa default to bytearrays
A = LOAD 'data' AS (name:chararray, age:int, gpa:float); // name is now a String (chararray), age is integer and gpa is float

垃圾场

转储命令对于交互式查看关系中存储的值并将输出写入控制台非常有用。转储不会保存数据:

示例:

grunt> DUMP movies;
INFO  [JobControl] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
INFO  [main] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
(1,The Nightmare Before Christmas,1993,3.9,4568)
(2,The Mummy,1932,3.5,4388)
(3,Orphans of the Storm,1921,3.2,9062)
(4,The Object of Beauty,1991,2.8,6150)
(5,Night Tide,1963,2.8,5126)
(6,One Magic Christmas,1985,3.8,5333)
(7,Muriel's Wedding,1994,3.5,6323)

店铺

存储命令用于写入或继续数据。Pig 只有在遇到DUMPSTORE时才开始作业。我们也可以在STORE中使用LOAD中提到的处理器。

示例:

grunt> STORE movies INTO '/temp' USING PigStorage(','); //This will write contents of movies to HDFS in /temp location

FOREACH 生成

FOREACH操作用于在关系的每个记录中应用列级表达式。甚至允许关系中的某些列是相当强大的,我们可以在FOREACH中使用 UDF 作为表达。

示例:

grunt> movie_duration = FOREACH movies GENERATE name, (double)(duration/60);

过滤器

Filter 是用来获取符合表达式条件的行。

示例:

grunt> movies_greater_than_four = FILTER movies BY (float)rating>4.0;
grunt> DUMP movies_greater_than_four;

我们可以对过滤器和布尔运算符(与、或、非)使用多个条件:

grunt> movies_greater_than_four_and_2012 = FILTER movies BY (float)rating>4.0 AND year > 2012;
grunt> DUMP movies_greater_than_four_and_2012;
INFO  [JobControl] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
WARN  [main] org.apache.pig.data.SchemaTupleBackend     - SchemaTupleBackend has already been initialized
INFO  [main] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
(22148,House of Cards: Season 1,2013,4.4,)
(22403,House of Cards,2013,4.4,)
(37138,Orange Is the New Black: Season 1,2013,4.5,)
(37141,Orange Is the New Black,2013,4.5,)
(37174,The Following: Season 1,2013,4.1,)
(37239,The Following,2013,4.1,)
(37318,The Carrie Diaries,2013,4.3,)
(37320,The Carrie Diaries: Season 1,2013,4.3,)
(37589,Safe Haven,2013,4.2,6936)

分组依据

Group By命令用于用键创建记录组。Group By关系用于处理分组数据的聚合函数。

分组依据的语法如下:

alias = GROUP alias { ALL | BY expression} [, alias ALL | BY expression …] [PARALLEL n];

例如:

  • Group By(员工在销售团队的起始年)

    grunt> grouped_by_year = group movies by year;
    
    
  • 或者Group By多个字段:

    B = GROUP A BY (age, employeesince);
    
    

极限

Limit命令限制了一个关系中输出元组的数量,但是元组返回可以在命令的不同执行中改变。对于特定的元组,我们必须使用ORDERLIMIT,这将返回元组的有序集。

示例:

grunt> movies_limit_10 = LIMIT movies 10;
grunt> DUMP movies_limit_10;
INFO  [JobControl] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
INFO  [JobControl] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
WARN  [main] org.apache.pig.data.SchemaTupleBackend     - SchemaTupleBackend has already been initialized
INFO  [main] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
(1,The Nightmare Before Christmas,1993,3.9,4568)
(2,The Mummy,1932,3.5,4388)
(3,Orphans of the Storm,1921,3.2,9062)
(4,The Object of Beauty,1991,2.8,6150)
(5,Night Tide,1963,2.8,5126)
(6,One Magic Christmas,1985,3.8,5333)
(7,Muriel's Wedding,1994,3.5,6323)
(8,Mother's Boys,1994,3.4,5733)
(9,Nosferatu: Original Version,1929,3.5,5651)
(10,Nick of Time,1995,3.4,5333)

聚合

Pig 提供了一堆聚合功能,比如:

  • AVG
  • 数数
  • 计数 _ 星
  • 总和
  • 马克斯(男子名ˌ等于 Maximilian)

示例:

grunt> count_by_year = FOREACH grouped_by_year GENERATE group, COUNT(movies);
grunt> DUMP count_by_year;
INFO  [JobControl] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
INFO  [main] org.apache.hadoop.mapreduce.lib.input.FileInputFormat     - Total input paths to process : 1
(1913,3)
(1914,20)
.
.
 (2009,4451)
(2010,5107)
(2011,5511)
(2012,4339)
(2013,981)
(2014,1)

合群

Cogroup是群的概括。它不是基于一个键收集一个输入的记录,而是基于一个键收集 n 个输入的记录。结果是一个记录,每个输入都有一个键和一个包。每个包包含该输入中具有给定值的所有记录:

$ cat > owners.csv
adam,cat
adam,dog
alex,fish
alice,cat
steve,dog

$ cat > pets.csv
nemo,fish
fido,dog
rex,dog
paws,cat
wiskers,cat

grunt> owners = LOAD 'owners.csv'
>>     USING PigStorage(',')
>>     AS (owner:chararray,animal:chararray);

grunt> pets = LOAD 'pets.csv'
>>     USING PigStorage(',')
>>     AS (name:chararray,animal:chararray);

grunt> grouped = COGROUP owners BY animal, pets by animal;
grunt> DUMP grouped;

这将根据动物栏对每个表格进行分组。对于每种动物,它将从两个表中创建一个匹配行的包。对于这个例子,我们得到如下表所示的结果:

|

|

业主

|

宠物

|
| --- | --- | --- |
| 猫 | {(亚当,猫),(爱丽丝,猫)} | 小猫咪小猫咪小猫咪 |
| 狗 | {(亚当,狗),(史蒂夫,狗)} | {(菲多,狗),(雷克斯,狗)} |
| 鱼 | {(亚历克斯,鱼)} | {(尼莫,鱼)} |

描述

DESCRIBE命令给出了一个关系的模式,如下所示:

grunt> Describe grouped;
grouped: {group: chararray,owners: {(owner: chararray,animal: chararray)},pets: {(name: chararray,animal: chararray)}}

解释

关系上的EXPLAIN命令显示了 Pig 脚本将如何执行。它显示了关系的逻辑计划、物理计划和 MapReduce 计划。我们可以使用EXPLAIN命令来研究已经进入计划的优化。此命令可用于进一步优化脚本:

grunt> explain grouped;
#-----------------------------------------------
# New Logical Plan:
#-----------------------------------------------
grouped: (Name: LOStore Schema: group#107:chararray,owners#108:bag{#118:tuple(owner#94:chararray,animal#95:chararray)},pets#110:bag{#119:tuple(name#96:chararray,animal#97:chararray)})
|
|---grouped: (Name: LOCogroup Schema: group#107:chararray,owners#108:bag{#118:tuple(owner#94:chararray,animal#95:chararray)},pets#110:bag{#119:tuple(name#96:chararray,animal#97:chararray)})
 |   |
 |   animal:(Name: Project Type: chararray Uid: 95 Input: 0 Column: 1)
 |   |
 |   animal:(Name: Project Type: chararray Uid: 97 Input: 1 Column: 1)
 |
 |---owners: (Name: LOForEach Schema: owner#94:chararray,animal#95:chararray)
 |   |   |
 |   |   (Name: LOGenerate[false,false] Schema: owner#94:chararray,animal#95:chararray)ColumnPrune:InputUids=[95, 94]ColumnPrune:OutputUids=[95, 94]
 |   |   |   |
 |   |   |   (Name: Cast Type: chararray Uid: 94)
 |   |   |   |
 |   |   |   |---owner:(Name: Project Type: bytearray Uid: 94 Input: 0 Column: (*))
 |   |   |   |
 |   |   |   (Name: Cast Type: chararray Uid: 95)
 |   |   |   |
 |   |   |   |---animal:(Name: Project Type: bytearray Uid: 95 Input: 1 Column: (*))
 |   |   |
 |   |   |---(Name: LOInnerLoad[0] Schema: owner#94:bytearray)
 |   |   |
 |   |   |---(Name: LOInnerLoad[1] Schema: animal#95:bytearray)
 |   |
 |   |---owners: (Name: LOLoad Schema: owner#94:bytearray,animal#95:bytearray)RequiredFields:null
 |
 |---pets: (Name: LOForEach Schema: name#96:chararray,animal#97:chararray)
 |   |
 |   (Name: LOGenerate[false,false] Schema: name#96:chararray,animal#97:chararray)ColumnPrune:InputUids=[96, 97]ColumnPrune:OutputUids=[96, 97]
 |   |   |
 |   |   (Name: Cast Type: chararray Uid: 96)
 |   |   |
 |   |   |---name:(Name: Project Type: bytearray Uid: 96 Input: 0 Column: (*))
 |   |   |
 |   |   (Name: Cast Type: chararray Uid: 97)
 |   |   |
 |   |   |---animal:(Name: Project Type: bytearray Uid: 97 Input: 1 Column: (*))
 |   |
 |   |---(Name: LOInnerLoad[0] Schema: name#96:bytearray)
 |   |
 |   |---(Name: LOInnerLoad[1] Schema: animal#97:bytearray)
 |
 |---pets: (Name: LOLoad Schema: name#96:bytearray,animal#97:bytearray)RequiredFields:null

#-----------------------------------------------
# Physical Plan:
#-----------------------------------------------
grouped: Store(fakefile:org.apache.pig.builtin.PigStorage) - scope-76
|
|---grouped: Package[tuple]{chararray} - scope-71
 |
 |---grouped: Global Rearrange[tuple] - scope-70
 |
 |---grouped: Local Rearrange[tuple]{chararray}(false) - scope-72
 |   |   |
 |   |   Project[chararray][1] - scope-73
 |   |
 |   |---owners: New For Each(false,false)[bag] - scope-61
 |       |   |
 |       |   Cast[chararray] - scope-56
 |       |   |
 |       |   |---Project[bytearray][0] - scope-55
 |       |   |
 |       |   Cast[chararray] - scope-59
 |       |   |
 |       |   |---Project[bytearray][1] - scope-58
 |       |
 |       |---owners: Load(file:///home/opt/pig/bin/owners.csv:PigStorage(',')) - scope-54
 |
 |---grouped: Local Rearrange[tuple]{chararray}(false) - scope-74
 |   |
 |   Project[chararray][1] - scope-75
 |
 |---pets: New For Each(false,false)[bag] - scope-69
 |   |
 |   Cast[chararray] - scope-64
 |   |
 |   |---Project[bytearray][0] - scope-63
 |   |
 |   Cast[chararray] - scope-67
 |   |
 |   |---Project[bytearray][1] - scope-66
 |
 |---pets: Load(file:///home/opt/pig/bin/pets.csv:PigStorage(',')) - scope-62

#--------------------------------------------------
# Map Reduce Plan
#--------------------------------------------------
MapReduce node scope-79
Map Plan
Union[tuple] - scope-80
|
|---grouped: Local Rearrange[tuple]{chararray}(false) - scope-72
|   |   |
|   |   Project[chararray][1] - scope-73
|   |
|   |---owners: New For Each(false,false)[bag] - scope-61
|       |   |
|       |   Cast[chararray] - scope-56
|       |   |
|       |   |---Project[bytearray][0] - scope-55
|       |   |
|       |   Cast[chararray] - scope-59
|       |   |
|       |   |---Project[bytearray][1] - scope-58
|       |
|       |---owners: Load(file:///home/opt/pig/bin/owners.csv:PigStorage(',')) - scope-54
|
|---grouped: Local Rearrange[tuple]{chararray}(false) - scope-74
 |   |
 |   Project[chararray][1] - scope-75
 |
 |---pets: New For Each(false,false)[bag] - scope-69
 |   |
 |   Cast[chararray] - scope-64
 |   |
 |   |---Project[bytearray][0] - scope-63
 |   |
 |   Cast[chararray] - scope-67
 |   |
 |   |---Project[bytearray][1] - scope-66
 |
 |---pets: Load(file:///home/opt/pig/bin/pets.csv:PigStorage(',')) - scope-62--------
Reduce Plan
grouped: Store(fakefile:org.apache.pig.builtin.PigStorage) - scope-76
|
|---grouped: Package[tuple]{chararray} - scope-71--------
Global sort: false
----------------

说明

ILLUSTRATE命令也许是最重要的发展援助。关系上的ILLUSTRATE对数据进行采样,并对其应用查询。这可以在调试过程中节省大量时间。样本明显小于数据,使得代码、测试和调试周期非常快。在许多情况下,JOINFILTER操作员可能不会对数据样本产生任何输出。在这种情况下,ILLUSTRATE制造通过这些运算符的记录,并将它们插入样本数据集中:

grunt> illustrate grouped;
-----------------------------------------------------------
| owners     | owner:chararray     | animal:chararray     |
-----------------------------------------------------------
|            | steve               | dog                  |
|            | adam                | dog                  |
-----------------------------------------------------------
--------------------------------------------------------
| pets     | name:chararray     | animal:chararray     |
--------------------------------------------------------
|          | fido               | dog                  |
|          | rex                | dog                  |
--------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| grouped     | group:chararray     | owners:bag{:tuple(owner:chararray,animal:chararray)}                 | pets:bag{:tuple(name:chararray,animal:chararray)}                 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|             | dog                 | {(steve, dog), (adam, dog)}                                          | {(fido, dog), (rex, dog)}                                         |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Pig 广泛用于数据流和 ETL,因此像 Pig 拉丁语言这样的脚本有助于轻松设计流。

鼠标

Hive 用类似 SQL 的包装器在 Hadoop 中提供了一个数据仓库环境,并且还翻译 MapReduce 作业中的 SQL 命令进行处理。Hive 中的 SQL 命令被称为 HiveQL,不支持 SQL 92 方言,不应该假设支持所有的关键字,因为整体思路是隐藏 MapReduce 编程的复杂性,对数据进行分析。

Hive 还可以充当与其他系统的分析接口,因为大多数系统与 Hive 集成良好。Hive 不能用于处理事务,因为它不提供行级更新和实时查询。

Hive 建筑

Hive 架构有不同的组件,例如:

  • 驱动程序:驱动程序管理 HiveQL 语句在 Hive 中移动时的生命周期,还维护会话统计的会话句柄。
  • Metastore : Metastore 存储系统目录和关于表、列、分区等的元数据。
  • 查询编译器:它把 HiveQL 编译成一个优化的地图/缩减任务的 DAG。
  • 执行引擎:以适当的依赖顺序执行编译器产生的任务。执行引擎与底层 Hadoop 实例交互。
  • HiveServer2 :提供节俭接口和 JDBC/ODBC 服务器,提供 Hive 与其他应用集成的方式,支持多客户端并发和身份验证。
  • 客户端组件,如命令行界面、网络用户界面和驱动程序。驱动程序是由供应商提供的 JDBC/ODBC 驱动程序和其他合适的驱动程序。

HiveQL 的流程描述如下:

  • HiveQL 语句可以从命令行界面、网络用户界面或使用诸如节俭、ODBC 或 JDBC 等接口的外部客户端提交。
  • 驱动程序首先将查询传递给编译器,在编译器中,它使用存储在 Metastore 中的元数据,通过典型的解析、类型检查和语义分析阶段。
  • 编译器生成一个逻辑计划,然后通过一个简单的基于规则的优化器进行优化。最后,以 MapReduce 任务和 HDFS 任务的 DAG 的形式生成优化计划。然后,执行引擎通过使用 Hadoop 按照依赖关系的顺序执行这些任务。

让我们检查元存储、查询编译器和执行引擎的更多细节。

Metastore

Metastore 存储关于表、分区、模式、列、类型等的所有细节。它充当 Hive 的系统目录。可以从不同编程语言的客户端调用,详情可以使用节俭查询。Metastore 对于 Hive 非常关键,没有它就无法检索结构设计细节,也无法访问数据。因此,Metastore 会定期备份。

Metastore 可能会成为 Hive 中的瓶颈,因此建议使用本地 JDBC 数据库(如 MySQL)来隔离 JVM 进程。Hive 确保作业的映射器和缩减器不会直接访问 Metastore 相反,它通过一个 xml 计划传递,该计划由编译器生成,并包含运行时所需的信息。

查询编译器

查询编译器使用 Metastore 存储的元数据处理 HiveQL 语句,生成执行计划。查询编译器执行以下步骤:

  • 解析:查询编译器解析语句。
  • 类型检查和语义分析:在这个阶段,编译器使用元数据来检查语句的表达式和语义中的类型兼容性。在检查被验证并且没有发现错误之后,编译器为语句构建一个逻辑计划。
  • 优化:编译器优化逻辑计划,并创建一个 DAG,将一个链的结果传递给下一个链,并尝试通过对逻辑步骤应用不同的规则(如果可能)来优化计划。

执行引擎

执行引擎执行优化后的计划。它一步一步地执行计划,为计划中的每一个任务考虑要完成的从属任务。任务的结果存储在一个临时位置,在最后一步,数据被移动到所需的位置。

数据类型和模式

Hive 支持TINYINTSMALLINTINTBIGINTFLOATDOUBLEDECIMAL等所有原始数值数据类型。除了这些原语数据类型,Hive 还支持字符串类型,如CHARVARCHARSTRING数据类型。与 SQL 一样,存在TIMESTAMPDATE等时间指标数据类型。也有BOOLEANBINARY杂类。

许多复杂的数据类型也可用。复杂类型可以由其他基本类型或复杂类型组成。可用的复杂类型有:

  • STRUCT: These are groupings of data elements similar to a C-struct. The dot notation is used to dereference elements within a struct. A field within column C defined as a STRUCT {x INT, y STRING} can be accessed as A.x or A.y.

    语法:STRUCT<field_name : data_type>

  • MAP: These are key value data types. Providing the key within square braces can help access a value. A value of a map column M that maps from key x to value y can be accessed by M[x].There is no restriction on the type stored by the value, though the key needs to be of a primitive type.

    语法:MAP<primitive_type, data_type>

  • ARRAY: These are lists that can be randomly accessed through their position. The syntax to access an array element is the same as a map. But what goes into the square braces is a zero-based index of the element.

    语法:ARRAY<data_type>

  • UNION: There is a union type available in Hive. It can hold an element of one of the data types specified in the union.

    语法:UNIONTYPE<data_type1, data_type2…>

安装蜂箱

Hive 可以通过下载并解包一个 tarball 来安装,也可以下载源代码,使用 Maven(0.13 及更高版本)或 Ant(0.12 及更低版本)来构建 Hive。

Hive 安装过程有以下要求:

  • Java 1.7(首选)或 Java 1.6
  • Hadoop 2。 x (首选)或 1。 x 。Hive 版本高达 0.13,但它也支持 0.20。 x 或 0.23。 x
  • Hive 通常用于 Linux 和 Windows 环境中的生产

首先,从一个 Apache 下载镜像下载最新稳定的 Hive 版本(请参见 Hive Releases)。

接下来,你需要打开油球。这将导致创建一个名为 hive-x.y.z 的子目录(其中 x.y.z 是发行号):

$ tar -xzvf hive-x.y.z.tar.gz

设置环境变量HIVE_HOME指向安装目录:

 $ cd hive-x.y.z
 $ export HIVE_HOME={{pwd}}

最后,将$HIVE_HOME/bin添加到您的Path中:

 $ export PATH=$HIVE_HOME/bin:$PATH

启动 Hive 外壳

对于使用 Hive shell,我们应该遵循以下步骤:

  1. 用户必须先创建/tmp/user/hive/warehouse,并在 HDFS 将其设置为chmod g+w,然后才能在 Hive 中创建表格。执行该设置的命令如下:

     $HADOOP_HOME/bin$ ./hadoop dfs -mkdir /tmp
     $HADOOP_HOME/bin$ ./hadoop dfs -mkdir /user/hive/warehouse
     $HADOOP_HOME/bin$ ./hadoop dfs -chmod g+w /tmp
     $HADOOP_HOME/bin$ ./hadoop dfs -chmod g+w /user/hive/warehouse
    
    
  2. 要从外壳使用 Hive 命令行界面(cli),请使用以下脚本:

     $HIVE_HOME/bin$ ./hive
    
    

HiveQL

HiveQL 拥有广泛的 Hive 内置运算符,Hive 内置函数,Hive 内置聚合函数,UDF 和 UDAF 为用户自定义函数。

数据定义语言操作

让我们从 DDL 操作命令开始,这些命令是:

  • Create database:使用Create database命令在 Hive 中创建数据库。示例:

    hive> Create database shiva;
    OK
    Time taken: 0.764 seconds
    
    
  • Show database:使用Show database命令列出 Hive 中所有现有的数据库。示例:

    hive> show databases;
    
    OK
    default
    shiva
    Time taken: 4.458 seconds, Fetched: 2 row(s)
    
    
  • Use database:使用Use database命令为会话选择一个数据库。示例:

    hive> use shiva;
    
    
  • Create table:使用Create table创建一个 Hive 表。在 create table 命令中,我们可以指定一个表是托管表还是外部表,如果它需要分区、分时段和 Hive 表中的其他重要功能的话。一个简单的“创建表格”选项的例子是:

    hive> Create table person (name STRING , add STRING);
    
    

Create table命令有许多选项,我们将在接下来给出的创建表格部分中看到。前面的命令是 Hive 中最简单的表格创建形式。

Create命令针对具体情况有很多选项,其要求是:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format] [STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]

  • 创建表:这个命令用给定的表名和下面解释的选项创建一个表:

    • 如果不存在:如果同名的表或视图已经存在,该命令用于跳过错误。
    • EXTERNAL 关键字:正如我们前面讨论的,这个命令允许我们创建一个表,我们必须为此提供一个 LOCATION。
    • ROW FORMAT :我们可以在创建表的时候使用自定义 SerDe 或者原生 SerDe。如果未指定行格式或指定了行格式分隔,则使用本机 SerDe。您可以使用 DECLARED 子句读取分隔文件。
    • STORED AS :如果数据需要以纯文本文件的形式存储,我们可以使用 TEXTFILE。如果数据需要压缩,请使用存储为序列文件。
    • PARTITIONED BY :可以使用 PARTITIONED BY 子句创建分区表。
    • CLUSTERED BY :此外,可以使用列对表或分区进行分桶,并且可以通过 SORT BY 列在该桶内对数据进行排序。这可以提高某些类型查询的性能。
    • TBLPROPERTIES :该子句允许您使用自己的元数据键/值对来标记表定义。
  • 显示表格:Show tables命令用于列出数据库中的所有表格:

    hive>Show tables;
    OK
    person
    Time taken: 0.057 seconds, Fetched: 1 row(s)
    
    hive>Show tables '.*n';-- List all the table end that end with s.
    
    OK
    person
    Time taken: 0.057 seconds, Fetched: 1 row(s)
    
    
  • 描述表:使用describe table命令获取关于表和列的有用信息。

    hive> describe person;
    OK
    name                    string                  None
    add                     string                  None
    Time taken: 0.181 seconds, Fetched: 2 row(s)
    
    
  • 更改表:使用Alter table命令更改表元数据,添加分区或桶。

    hive> Alter table person ADD COLUMNS (PNO  INT);
    OK
    Time taken: 0.334 seconds
    
    
  • 删除表:使用drop table命令从 Hive 元数据中删除表;如果表是 Hive 管理的,那么这个命令也将删除数据,如果它是外部的,那么只有 Hive 元数据被删除。

    hive>drop table person;
    
    

DML(数据操作语言)操作

现在,让我们看看 DML 的操作命令:

加载数据:Hive 中的文件可以从本地加载,也可以从 HDFS 加载;默认情况下,Hive 将在 HDFS 显示。

我们使用的输入数据是简单的个人数据,有Nameaddpno;这个数据的例子是这样的:

|

名字

|

增加

|

进行性核性眼肌麻痹

|
| --- | --- | --- |
| 艾尔文·琼纳 | 尼斯大道 678-8957 号 | one |
| 贾斯帕·罗伯逊 | 公元前 8336 年。 | Two |
| 迪尔德丽·富尔顿 | 页:1。街上 | three |
| 希拉里·克雷格 | AP #198-3439 id 关闭。 | four |
| 布雷泽·卡尔 | 普鲁斯路 283-9985 号 | five |

请看下面的命令:

hive>LOAD DATA INPATH 'hdfs://localhost:9000/user/hive/shiva/PersonData.csv' OVERWRITE INTO TABLE person;

Loading data to table shiva.person
OK
Time taken: 0.721 seconds

前面的命令将数据从 HDFS 文件/目录加载到表中,从 HDFS 加载数据的过程将导致文件/目录的移动。

对于本地数据加载,请使用以下代码:

hive>LOAD DATA LOCAL INPATH './examples/shiva/file1.txt' OVERWRITE INTO TABLE person;

我们还可以用 PARTITION 加载数据:

hive>LOAD DATA LOCAL INPATH './examples/ shiva /file2.txt'
 OVERWRITE INTO TABLE person PARTITION (date='26-02-2014');

SQL 操作

在 Hive 中查询数据可以按照以下部分进行:

选择 : SELECT是 SQL 中的投影运算符。用于此功能的子句有:

  • SELECT扫描由FROM子句指定的表格

  • WHERE给出过滤什么的条件

  • GROUP BY给出列列表,然后指定如何聚合记录

  • CLUSTER BYDISTRIBUTE BYSORT BY指定排序顺序和算法

  • LIMIT指定要检索的记录数量:

    SELECT [ALL | DISTINCT] select_expr, select_expr,
    FROM table_reference
    [WHERE where_condition]
    [GROUP BY col_list]
    [HAVING having_condition]
    [CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list]]
    [LIMIT number];
    
    

示例:

hive>select * from person where name = 'Alvin Joyner';

Total MapReduce jobs = 1
Launching Job 1 out of 1
Number of reduce tasks is set to 0 since there's no reduce operator
Starting Job = job_201503051113_2664, Tracking URL = http://machine76.bigdatadomain.com:50030/jobdetails.jsp?jobid=job_201503051113_2664
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 0
2015-03-24 14:52:54,541 Stage-1 map = 0%,  reduce = 0%
2015-03-24 14:52:58,570 Stage-1 map = 100%,  reduce = 0%, Cumulative CPU 2.57 sec
2015-03-24 14:52:59,579 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 2.57 sec
MapReduce Total cumulative CPU time: 2 seconds 570 msec
Ended Job = job_201503051113_2664
MapReduce Jobs Launched:
Job 0: Map: 1   Cumulative CPU: 2.57 sec   HDFS Read: 4502 HDFS Write: 0 SUCCESS
Total MapReduce CPU Time Spent: 2 seconds 570 msec
OK
Time taken: 12.53 seconds

连接

HiveQL 支持以下类型的连接:

  • 加入
  • 左外连接
  • 右外连接
  • 完全外部连接

HiveQL 中只支持equi join;无法执行非相等条件连接。HiveQL 中的默认连接选项是等价连接,而 SQL 中的默认连接是内部连接;《也在场》中的一个句法差异是,我们不得不提到左OUTER JOINRIGHT OUTER JOIN,而在SQL LEFT JOINRIGHT JOIN的作品中。

HiveQL 被转换成 MapReduce 作业,因此我们必须在设计查询时牢记 MapReduce 范例。根据解析器和优化计划,连接作为 Mapside 连接或减少侧连接执行,因此经验法则是尽早连接较小的表,以避免大量数据传输或处理,并在最后连接较大的表。这背后的原因是,在关节的每个 MapReduce 阶段,最后一个表都是通过减速器精简的;而其他的被缓冲。

示例:

Hive> SELECT a.val1, a.val2, b.val, c.val
 > FROM a
 > JOIN b ON (a.key = b.key)
 > LEFT OUTER JOIN c ON (a.key = c.key);

如 Hive wiki 中所述,不支持以下条件:

  • 联合后跟一个映射连接
  • 横向视图,后跟地图连接
  • 减少接收器(分组依据/连接/排序依据/群集依据/分发依据),然后是映射连接
  • 地图连接后跟联合
  • 映射连接后跟连接
  • MapJoin 后跟 MapJoin

聚合

HiveQL 支持聚合,也允许同时进行多个聚合。可能的聚合器有:

  • count(*)count(expr)count(DISTINCT expr[, expr_.])
  • sum(col)sum(DISTINCT col)
  • avg(col)avg(DISTINCT col)
  • min(col)
  • max(col)

示例:

hive> SELECT a, sum(b) FROM t1
 > GROUP BY a;

Hive 还支持Group By的地图端聚合,以提高性能,但需要更多内存。如果我们将hive.map.aggr设置为真(默认值为假),那么 Hive 将直接在地图任务中进行一级聚合。

hive> set hive.map.aggr=true;
hive> SELECT COUNT(*) FROM table2;

内置功能

Hive 有许多内置功能,其一些广泛使用的功能有:

  • concat(string A, string B,...)
  • substr(string A, int start)
  • round(double a)
  • upper(string A), lower(string A)
  • trim(string A)
  • to_date(string timestamp)
  • year(string date), month(string date), day(string date)

自定义 UDF(用户定义函数)

我们可以创建自己的自定义 UDF 函数,并在 Hive 查询中使用它。Hive 为用户定义的函数提供了一个接口,在这里可以用 Java 编写和部署自定义函数,这些函数可以在 HiveQL 中作为函数使用。定制 UDF 要执行的步骤如下:

  1. 创建一个新的 Java 类,用一个或多个名为 evaluate:

    import org.apache.hadoop.hive.ql.exec.UDF;
    import org.apache.hadoop.io.Text;
    public class LowerUDF extends UDF
    {
      public Text evaluate(final Text s)
      {
        if (s == null) { return null; }
        return new Text(s.toString().toLowerCase());
      }
    }
    

    的方法扩展 UDF

  2. 现在,编译函数,制作 jar。

  3. Deploy jars for user-defined functions:

    hive> add jar my_jar.jar;
    
    

    在类路径中添加了my_jar.jar

  4. 一旦 Hive 开始在类路径中使用您的 jars,最后一步就是注册您的函数:

    create temporary function my_lowerUDF as 'Lower';
    
    
  5. 现在,你可以开始使用它了。

    hive> select my_lowerUDF(title), sum(freq) from titles group by my_lowerUDF(title);
    
    

管理表格–外部与托管

Hive 可以灵活地只管理元数据或元数据以及数据。在 Hive 中,两种类型的数据管理是:

  • 托管:元数据连同数据将由 Hive 管理。
  • 外部:Hive 只存储和管理元数据。

如果我们想让 Hive 管理表的生命周期,就应该使用 Hive 中的托管表,如果是临时表,就应该使用数据。

使用外部表格的优势是:

  • 我们可以使用一个自定义的位置,如 HBase、Cassandra 等。
  • 数据可以由另一个系统处理,可以避免锁定,同时处理和提高性能
  • 在 DROP 表命令中,只有元数据将被删除,数据不会被删除。

ser

使用 Hadoop 的重要好处之一是它可以灵活地存储,并提供接口来处理半结构化和非结构化数据。Hive 也可以用于处理这些数据;Hive 这样做是因为它复杂的数据类型和 SerDe 属性。SerDe 是一个 serializer 和 Serializer 接口,可以允许对 Java 对象中的字符串或二进制数据进行编组和解组,Hive 可以使用这些数据在表中进行读写。Hive 有一些内置的 SerDe 库,比如 Avro、ORC、RegEx、节俭、Parquet 和 CSV 它还有一个像亚马逊提供的 JSON SerDe 那样的第三方 SerDe。

我们也可以写我们的自定义 SerDe。为了编写定制的 SerDe 类,我们必须重写一些方法:

  • public void initialize (Configuration conf, Properties tbl) throws SerDeException:方法initialize()只调用一次,我们可以从表属性中获取和设置一些常用的信息,比如列类型和名称。
  • public Writable serialize (Object obj, ObjectInspector oi) throws SerDeException:serialize()方法要有序列化的逻辑,取一个代表一行数据的 Java 对象,生成一个可序列化的可写接口对象。
  • public Class<? extends Writable> getSerializedClass ():getSerializedClass()返回序列化对象的返回类型类。
  • public Object deserialize (Writable blob) throws SerDeException:deserialize()应该有反序列化逻辑。
  • public ObjectInspector getObjectInspector () throws SerDeException:ObjectInspectors是用于描述和检查复杂类型层次结构的 Hive 对象。
  • public SerDeStats getSerDeStats():它们覆盖支持一些统计。

让我们看一下实现自定义服务的代码:

public class CustomSerDe implements SerDe {

 private StructTypeInfo rowTypeInfo;
 private ObjectInspector rowOI;
 private List<String> colNames;
 Object[] outputFields;
 Text outputRowText;
 private List<Object> row = new ArrayList<Object>();

 @Override
 public void initialize(Configuration conf, Properties tbl)throws SerDeException {
   // Get a list of the table's column names.
   String colNamesStr = tbl.getProperty(Constants.LIST_COLUMNS);
   colNames = Arrays.asList(colNamesStr.split(","));

   // Get a list of TypeInfos for the columns. This list lines up with
   // the list of column names.
   String colTypesStr = tbl.getProperty(Constants.LIST_COLUMN_TYPES);
   List<TypeInfo> colTypes = TypeInfoUtils.getTypeInfosFromTypeString(colTypesStr);
   rowTypeInfo = (StructTypeInfo) TypeInfoFactory.getStructTypeInfo(colNames, colTypes);
   rowOI = TypeInfoUtils.getStandardJavaObjectInspectorFromTypeInfo(rowTypeInfo);
 }

 @Override
 public Object deserialize(Writable blob) throws SerDeException {
   row.clear();
   // Implement the logic of Deserialization
   return row;
 }

 @Override
 public ObjectInspector getObjectInspector() throws SerDeException {
   return rowOI;
 }

 @Override
 public SerDeStats getSerDeStats() {
   return null;
 }

 @Override
 public Class<? extends Writable> getSerializedClass() {
   return Text.class;
 }

 @Override
 public Writable serialize(Object obj, ObjectInspector oi)
     throws SerDeException {
   // Implement Logic of Serialization
   return outputRowText;
 }
}

我们必须创建类的 jar 文件,并将其放入 Hive 服务器中。然后,我们可以在创建表时使用 SerDe,如下面的代码所示:

CREATE EXTERNAL TABLE IF NOT EXISTS my_table (field1 string, field2 int, field3 string, field4 double)
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2\. CustomSerDe' LOCATION '/path-to/my_table/';

分区

Hive 支持数据分区,可用于水平分布数据。以为例,如果我们有一个大型事务表,该表频繁地查询一年或一系列月,那么我们可以在创建表时用PARTITIONED BY (year INT, month INT)对该表进行分区。

Hive 通过创建子目录作为分区字段的结构来管理数据,例如:

/DB/Table/Year/Month/.

/db/table/2014/11/.

/db/table/2014/12/.

/db/table/2015/1/.

/db/table/2015/2/.

分区适用于托管表和外部表,建议用于非常大的表,这样可以限制要处理的文件,并为提高性能提供巨大优势。

分区应该小心进行,因为它可能有以下缺点:

  • 如果没有正确选择分区列,那么它可能会不均匀地划分数据,查询执行将不会得到优化。
  • 如果分区层次级别变高,则递归扫描目录将比完全数据扫描更昂贵。

颠簸

我们刚刚讨论了分区可以不均匀分布数据的事实,但是通常不太可能得到均匀分布。但是,我们可以使用 bucket 来实现几乎均匀的分布式数据处理。Bucketing 将一个数据值放入一个存储桶中,因此同一存储桶中可以有相同的值记录,并且一个存储桶可以有多组值。Bucketing 提供了对多个文件的控制,因为我们在使用create table时必须提到 buckets 的数量而使用CLUSTERED BY (month) INTO #noofBuckets BUCKETS

为了数据的均匀分布,我们应该设置hive.enforce.bucketing = true。桶是辅助地图端连接的理想选择,因为桶中存在相同的值数据,合并排序将更快、更有效。它可以使用分区,也可以不使用分区。

总结

在本章中,我们探讨了 MapReduce 编程的两个包装器——Pig 和 Hive。

MapReduce 非常强大,但却是一条非常复杂的高学习曲线。困难的部分是管理 MapReduce 程序以及开发和优化所花费的时间。为了在 MapReduce 中更容易和更快地开发,我们有抽象层,例如 Pig,它是 MapReduce 之上的 Pig 拉丁语过程语言的包装器,以及 HiveQL 包装器,它是一个类似于 SQL 的 HiveQl 包装器。

数据流程模型中使用了 Pig,因为它使用 DAG 模型将 Pig 拉丁语言转换为 MapReduce 作业。Pig 在三个计划中进行转换,即从逻辑到物理到 MapReduce,其中每个计划翻译语句并产生一个优化的执行计划。Pig 还有交互分析数据的咕噜模式。Pig 有非常有用的命令来过滤、分组、聚合、共组等等,它还支持用户定义的函数。

Hive 被那些在类似 SQL 的开发中更舒服的用户使用,因为它有 HiveQL。配置单元体系结构包含驱动程序、元存储、查询编译器、执行引擎和 HiveServer。HiveQL 有一个详尽的内置函数和命令列表来分析数据。Hive 有许多内置函数,也支持用户定义的函数。

在下一章中,我们将介绍 Hadoop 中最重要的组件之一。它是非关系分布式数据库,具有高吞吐量和高性能;我们称之为 HBase。

五、存储组件——HBase

Hadoop 生态系统中最重要的组件之一是 HBase,它非常高效地利用 HDFS,能够以更好的性能规模存储、管理和处理数据。NoSQL 正在崛起,人们非常关注大数据问题解决领域的不同实施和解决方案。HBase 是一个 NoSQL 数据库,可以处理 HDFS 以上的数据,以获得非常好的性能,同时具有优化、可扩展性和可管理性。在 Hadoop 中,HDFS 非常适合作为 WORM(一次写入多次读取)范例的存储,在这种范例中,数据不会更新。在许多情况下,需求可能是更新、特别分析或随机读取。在 HDFS,处理这些需求的效率不是很高,因为更新文件中的记录是不可能的;HDFS 必须删除和重写整个文件,这是资源、内存和输入/输出密集型的。但是,在海量随机读写中,HBase 可以以接近最佳的性能高效地管理此类处理。

在这一章中,我们将介绍 HBase 的需求和必要性及其功能、体系结构和设计。我们还将深入研究数据模型和模式设计、HBase 的组件、读写管道以及一些示例。

糖化血红蛋白酶概述

HBase 是基于谷歌白皮书大表:结构化数据的分布式存储系统设计的,定义为稀疏、分布式、持久的多维排序图。HBase 是一个面向列和分区的数据库,但存储在数据的键值对中。我知道这很令人困惑和棘手,所以让我们再详细看看这些术语。

  • 稀疏 : HBase 呈柱状,分区定向。通常,一条记录可能有许多列,其中许多列可能有空数据,或者这些值可能重复。HBase 可以高效、有效地节省稀疏数据中的空间。
  • 分布式:数据存储在多个节点中,分散在集群中。
  • 持久:数据写入并保存在集群中。
  • 多维:一行可以有多个版本或者时间戳的值。
  • 映射:键值对链接数据结构存储数据。
  • 已排序:结构中的键以已排序的顺序存储,以实现更快的读写优化。

HBase 数据模型,正如我们将看到的,非常灵活,可以针对许多大数据用例进行调整。与每种技术一样,HBase 在某些用例中表现非常好,但在其他用例中可能不被建议。以下是糖化血红蛋白酶表现良好的情况:

  • 需要大规模实时随机读/写
  • 变量模式:可以在运行时添加或删除列
  • 数据集的许多列是稀疏的
  • 需要基于密钥的检索和自动分片
  • 对一致性的需求大于可用性
  • 为了获得更好的性能,必须对数据或表进行反规范化

糖化血红蛋白酶的优势

HBase 有很多好处,在很多用例中都是很好的解决方案。让我们来看看糖化血红蛋白的一些优点:

  • 高容量请求中随机且一致的读/写访问
  • 自动故障转移和可靠性
  • 灵活的基于列的多维地图结构
  • 变量模式:可以动态添加和删除列
  • 与 Java 客户端、节俭和休息应用编程接口的集成
  • 地图缩减和 Hive/PIG 集成
  • 自动分区和分片
  • 低延迟数据访问
  • 用于查询优化的块缓存和布隆过滤器
  • HBase 允许数据压缩,非常适合稀疏数据

糖化血红蛋白酶的结构

HBase 通过设计是面向列的,其中 HBase 表存储在 ColumnFamilies 中,每个 ColumnFamily 可以有多个列。列族的数据存储在多个区域的多个文件中,其中一个区域保存特定范围的行键的数据。要管理区域,主服务器将多个区域分配给一个区域服务器。HBase 设计的灵活性源于灵活的区域服务器和区域,由单个主服务器控制。HBase Architecture 使用 Zookeeper 来管理分布式环境中高可用性所需的协调和资源管理方面。HBase 中的数据管理通过在区域中执行的拆分和压缩过程来高效地执行,以优化大容量读写的数据。为了处理大量的写请求,我们在区域服务器中有两级缓存 WAL,在区域服务器中有内存存储。如果区域中存在的特定范围或行关键字的数据增长超过阈值,则分割区域以利用群集。使用压缩过程合并和压缩数据。使用 WAL 管理数据恢复,因为它保存所有非持久编辑数据。

HBase 体系结构强调可扩展的并发读取和一致写入。设计 HBase 的关键在于提供高性能、可扩展的读取和一致的多次写入。HBase 使用以下组件,我们将在后面讨论:

  • 主服务器
  • 区域服务器
  • 地区
  • 动物园管理员

让我们看看下图:

The Architecture of HBase

主服务器

MasterServer 是管理员,在某个时间点,HBase 中只能有一个 Master。它负责以下工作:

  • 集群监控和管理
  • 将区域分配给区域服务器
  • 通过重新分配区域实现故障转移和负载平衡

区域服务器

区域服务器由主服务器识别,主服务器将区域分配给区域服务器。区域服务器在数据节点上运行,并执行以下活动:

  • 与主管协调管理区域
  • 区域中的数据拆分
  • 协调和服务读/写

除了管理区域之外,区域服务器还具有以下组件或数据结构:

RegionServer

墙面

用于写操作的数据首先保存在 WAL 中,然后放入 MemStore 中。MemStore 不保存数据,所以如果一个区域变得不可用,数据可能会丢失。在任何崩溃的情况下,或者在没有响应的区域恢复内存存储中的数据,WAL 是极其重要的。WAL 保存区域服务器管理的区域的内存存储中的所有数据。当数据从 MemStore 中刷新并保存为 HFile 时,数据也会从 WAL 中删除。只有在数据成功写入 WAL 后,才会向客户端发出成功写入的确认。

块缓存

从 HDFS 读取数据块时,HBase 会将数据块缓存在每个区域的数据块缓存服务器中,以备将来对该数据块的请求,从而优化了 HBase 中的随机读取。块缓存作为内存中的分布式缓存工作。它是一个接口,它的默认实现是 LruBlockCache,它基于最近使用的算法缓存。在较新版本的 HBase 中,我们可以使用 SlabCache 和 BucketCache 实现。我们将在接下来的章节中讨论这三个实现。

LRUBlockCache

数据块缓存在一个 JVM 堆中,根据访问请求,JVM 堆有三个区域,即单个、多个和内存中。如果块可以第一次被访问,那么它被保存在单个访问空间中。如果数据块被多次访问,那么它将被提升为多次访问。内存区域是为从内存标记列族加载的块保留的。使用最近最少使用的技术移除不频繁访问的块。

SlabCache

这个缓存是由 L1(JVM 堆)和 L2 缓存(JVM 堆外)组合而成的。使用 DirectByteBuffers 分配 L2 内存。可以根据需要将块大小配置为更大的大小。

七叶树

它使用桶区域来保存缓存的块。该缓存是 SlabCache 的扩展,除了 L1 和 L2 缓存之外,还有一个文件模式的缓存级别。文件模式旨在低延迟存储在内存文件系统或固态硬盘存储中。

如果系统必须以低延迟执行,以便我们可以利用外部 JVM 堆内存,并且当 RegionServer 的 RAM 内存可能耗尽时,SlabCache 或 BucketCache 是不错的选择。

地区

HBase 通过区域管理可用性和数据分发。区域是 HBase 执行高速读写的关键。区域还管理行键排序。它在表的每个列族中都有单独的存储,每个存储都有两个组件 MemStore 和多个 StoreFiles。糖化血红蛋白使用区域实现自动分割。如果启用了自动拆分,当数据增长超过存储的配置最大大小时,存储在区域中的文件将被拆分为两个相等的区域。在区域中,拆分过程维护数据分布,压缩过程优化存储文件。

一个区域可以有多个存储文件或数据块,这些文件或数据块以 HFile 格式保存用于存储的数据。存储文件将保存数据库中列族的数据。列族在 HBase 数据模型部分讨论。

记忆库

内存存储是一个存储数据文件的区域的内存存储空间,称为存储文件。我们已经讨论过写请求的数据首先写入区域服务器的 WAL,然后放入 MemStore。需要注意的一点是,只有当 MemStore 中的 StoreFiles 达到一个阈值,具体来说就是hbase-site.xml文件的属性hbase.hregion.memstore.flush.size的值时,数据才会在 MemStore 中不持久;数据作为区域中的存储文件刷新。由于数据必须按照排序的行键顺序,所以首先写入数据,然后在刷新之前进行排序,以实现更快的写入。由于用于写入的数据存在于 MemStore 中,因此它还充当为最近写入的块数据而访问的数据的缓存。

动物园管理员

HBase 使用 Zookeeper 监控一个区域服务器,并在它关闭时恢复它。所有的区域服务器都由动物园管理员监控。区域服务器向 ZooKeeper 发送心跳消息,如果在一段超时时间内没有收到心跳,则区域服务器被认为是死的,主服务器开始恢复过程。动物园管理员也用于识别活动的主人和选择活动的主人。

糖化血红蛋白数据模型

HBase 中数据的存储以多层次键值映射的形式面向列。HBase 数据模型非常灵活,其优点是可以动态添加或删除列数据,而不会影响性能。HBase 可用于处理半结构化数据。它没有任何特定的数据类型,因为数据是以字节存储的。

数据模型的逻辑组件

HbSe 数据模型有如下逻辑组成部分:

  • 桌子
  • 柱族/柱
  • 版本/时间戳
  • 细胞

下图显示了 HBase 表:

Logical components of a data model

让我们详细了解一下这些组件:

  • :HBase 中的一个表实际上是逻辑多于物理的。一个数据表可以被描述为一组行。表的数据呈现在不同的多个区域中,并按行键的范围分布。

  • Row:ARow 只是 HBase 中的一个逻辑表示。物理上,数据不是存储在行中,而是存储在列中。HBase 中的行是可以有多个列族的列的组合。HBase 中的每一行都由一个用作主键索引的 rowkey 标识。在表中,rowkey 是唯一的。如果要写入的行有一个现有的 rowkey,那么同一行将被更新。

  • Column Families/Columns: A Column Family is a group of columns which are stored together. Column Families can be used for compression. Designing Column Families is critical for the performance and the utilization of the advantages of HBase. In HBase we store data in denormalization form to create a file which will hold a particular dataset to avoid joins. Ideally, we could have multiple column families in a table but it is not advisable.

    需要注意的一点是,对于一个表来说,拥有两个以上级别的列族层次结构是不可取的,尤其是当一个族具有非常高的数据而另一个族具有相当低的数据时。这是因为较小尺寸的柱族数据必须分布在许多区域,并且冲洗和压缩的效率不如区域对相邻族的影响。

    可以使用列系列在 HBase 中访问列,列限定符用于访问列的数据,例如columnfamily:columnname

  • 版本/时间戳:在 HBase 中,一个 rowkey(行、列、版本)保存一个单元格,我们可以让同一个行、同一个列用不同的版本保存多个单元格。HBase 按版本降序存储版本,以便首先找到最近的单元格值。在 HBase 0.96 之前,默认保留的版本数是三个,但在 0.96 及更高版本中,它已更改为一个。

  • 单元格:一个单元格是在糖化血红蛋白中写入数值的地方。糖化血红蛋白中的一个单元格可以由糖化血红蛋白表中行关键字{行、列、版本}的组合来定义。数据类型将是字节[],存储的数据称为 HBase 中的值。

我们可以用以下方式表示糖化血红蛋白组分的关系:

(表、行键、列族、列、时间戳)→值

酸性

HBase 不不遵循 ACID 属性的所有属性。让我们来看看 HBase 是如何遵守特定属性的:

  • 原子性:在一行中,操作要么完全完成,要么根本不完成,但是跨节点的最终是一致的。
  • 持久性:HBase 中的更新不会因为 WAL 和 MemStore 而丢失。
  • 一致性和隔离 HBase 对于单个行级别是强一致的,但在不同级别之间不是。

更多细节可以查看 http://hbase.apache.org/acid-semantics.html网站

CAP 定理

CAP 定理也被称为布鲁尔定理。CAP 代表:

  • 一致性
  • 有效性
  • 分区容差

这些都是任何分布式系统的关键设计属性。我们在这里不讨论 CAP 定理的细节,但是简单地说,根据 CAP 定理,一个分布式系统只能保证上面三个特性中的两个。由于系统是分布式的,它必须是分区容忍的。这导致了两种可能性;要么是 CP,要么是 AP。

HBase 采用主从架构。主服务器进程是单点故障(我们可以为主服务器配置高可用性,这样可以随时提供备份主服务器),而对于区域服务器,从故障中恢复是可能的,但数据可能会在一段时间内不可用。实际上,HBase 被认为最终是一致的(行级一致性很强,而跨级别不太强),并实现一致性和分区容差。因此,糖化血红蛋白更倾向于 CP,而不是 AP。

图式设计

由于需求和约束不同,HBase 模式与 RDBMS 模式设计有很大的不同。应该根据应用的要求设计 HBase 模式,并且建议对该模式进行非规范化。数据分布取决于 rowkey,它被选择为在整个集群中是一致的。Rowkey 对请求的扫描性能也有很好的影响。

HBase 模式设计中需要注意的事项如下:

  • 热封装:热封装是指一个或几个区域有巨大的数据负载,数据范围被频繁写入或访问,导致性能下降。为了防止热封装,我们可以散列一个 rowkey 的值或一个特定的列,这样均匀分布的概率很高,并且读写将被优化。
  • 单调递增的行键/时间序列数据:多个区域出现的一个问题是,一系列行键可能会达到拆分的阈值,并可能导致一段时间的超时。为了避免这种情况,我们不应该将不断增加的列值作为 rowkey 的初始值。
  • 反向时间戳:如果我们在 rowkey 中有时间戳,那么更新的数据会被推到最后。如果时间戳像Long.MAX_VALUE时间戳一样存储,那么较新的数据将在开始时出现,并且会更快并且可以避免,尤其是在扫描的情况下。

让我们看看在 HBase 中设计模式的一些重要概念:

  • Rowkey : Rowkey 是 HBase 架构中极其重要的设计参数,因为数据是使用 Rowkey 进行索引的。Rowkey 是不可变的;更改 rowkey 的唯一方法是删除它,然后再次重新插入。行按行按排序,即如果行键为13200122506045,则数字的排序顺序为00106012253245。表文件通过一系列行键分布在区域中。通常顺序键和随机键的组合在 HBase 中表现更好。
  • 柱族:柱族提供了很好的可扩展性和灵活性,但是要精心设计。在 HBase 的当前体系结构中,建议不要超过两个列系列。
  • 反规格化数据:由于 HBase 本身不提供 Joins,数据应该反规格化。数据通常是稀疏的,并在许多列中重复,HBase 可以充分利用这一点。

写流水线

在 HBase 中写入管道是通过以下步骤进行的:

  1. 客户端请求将数据写入 HTable,请求到达区域服务器。
  2. 区域服务器首先在 WAL 中写入数据。
  3. 区域服务器识别将存储数据的区域,数据将保存在该区域的内存存储中。
  4. MemStore 将数据保存在内存中,不保存它。当 MemStore 中的阈值达到时,则数据在该区域中被刷新为 HFile。

读取管道

在中读取 HBase 按以下步骤进行:

  1. 客户端发送读取请求。请求由区域服务器接收,该服务器识别存在文件的所有区域。
  2. 首先,查询区域的记忆库;如果数据存在,则请求得到服务。
  3. 如果数据不存在,则查询块缓存以检查它是否有数据;如果是,则服务该请求。
  4. 如果数据不在块缓存中,则从区域中提取数据并提供服务。现在数据被缓存在内存存储和块缓存中..

压实

在操作系统中,区域中的记忆库为一个列族创建许多文件。如此大量的文件将需要更多的时间来读取,因此会影响读取性能。为了提高性能,HBase 执行压缩来合并文件,以减少文件数量并保持数据的可管理性。压缩过程通过运行一种称为压缩策略的算法来识别要合并的存储文件。有两种类型的压缩:次要压缩和主要压缩。

紧缩政策

压缩策略是可用于选择要合并的存储文件的算法。有两种策略是可能的,可用的是ExploringCompactionPolicyRatioBasedCompactionPolicy。要设置策略算法,我们必须设置hbase-site.xml的属性hbase.hstore.defaultengine.compactionpolicy.class的值。在 HBase 0.96 之前,RatioBasedCompactionPolicy 作为默认策略可用,现在仍然可用。ExploringCompactionPolicy 是 HBase 0.96 和更高版本的默认算法。简而言之,这些算法的不同之处在于,基于比率的公司操作策略选择第一个符合标准的集合,而探索公司操作策略选择工作量最少且更适合大容量数据加载的最佳存储文件集合。

轻微压实

次要压缩将相邻的和较小的大小的存储文件合并或重写为一个存储文件。较小的压缩会更快,因为它会创建一个新的存储文件,并且为压缩选择的存储文件是不可变的。请注意,小压缩不处理已删除和过期的版本。当存储文件的数量达到阈值时,就会发生这种情况;非常具体地说,hbase-site.xmlhbase.hstore.compaction.min属性的值。属性的默认值是2,小压缩只是合并较小的文件以减少文件数量。这将更快,因为数据已经排序。影响次要压缩的一些更可配置的属性如下:

  • hbase.store.compaction.ratio:这个值决定了读取成本和写入成本之间的平衡,值越高,读取速度快、写入成本高的文件数量就越少。较小的值将具有较低的写入成本,而读取成本将相对较高。建议值在 1.0 到 1.4 之间。
  • hbase.hstore.compaction.min.size:该值表示最小尺寸,低于该尺寸时,将包含用于压缩的存储文件。默认值为 128 兆字节。
  • hbase.hstore.compaction.max.size:该值表示最大尺寸,超过该尺寸,压缩时将不包括存储文件。默认值为Long.MAX_VALUE
  • hbase.hstore.compaction.min:该值表示最小文件数,低于该值时,将包含要压缩的存储文件。默认值为 2。
  • hbase.hstore.compaction.max.size:该值表示压缩时不包含存储文件的最大文件数。默认值为 10。

主要压实

主压缩将一个区域的所有存储文件合并为一个存储文件。主压缩过程需要大量时间,因为它实际上删除了过期版本和已删除的数据。该过程的启动可以是时间触发、手动和大小触发。默认情况下,主压缩每 24 小时运行一次,但建议手动启动它,因为这是一个写密集型和资源密集型的过程,并且可以阻止写请求以防止 JVM 堆耗尽。影响主要压缩的可配置属性有:

  • hbase.hregion.majorcompaction:这个表示两次主要压实之间的时间,单位为毫秒。我们可以通过将该属性的值设置为 0 来禁用时间触发的主要压缩。默认值为 604800000 毫秒(7 天)。
  • hbase.hregion.majorcompaction.jitter:主压实的实际时间由该属性值计算,并乘以上述属性值。该值越小,开始压缩的频率就越高。默认值为 0.5°f。

分裂

正如我们所讨论的在 HBase 中的文件和数据管理,除了压缩,分割区域也是一个重要的过程。当数据在区域和区域服务器之间均匀分布时,可以获得最佳的 HBase 性能,这可以通过最佳分割区域来实现。首次使用默认选项创建表时,只有一个区域分配给该表,因为主机没有足够的信息来分配适当数量的区域。我们有三种类型的拆分触发器,即预拆分、自动拆分和强制拆分。

预分裂

为了在创建表格时帮助分割区域,我们可以使用预分割来让 HBase 初步知道要分配给表格的区域数量。对于预分割,我们应该知道数据的分布,如果我们预分割区域,并且我们有数据倾斜,那么分布将是不均匀的,并且会限制集群性能。我们还必须计算表格的分割点,这可以使用 RegionSplitter 实用程序来完成。RegionSplitter 使用可插入的 SplitAlgorithm 和两个预定义的算法,它们是 HexStringSplit 和 UniformSplit。如果行键有十六进制字符串的前缀,则可以使用 HexStringSplit,如果它们是随机字节数组,则可以使用 UniformSplit,或者我们可以实现并使用自己定制的 SplitAlgorithm。

以下是使用预拆分的一个例子:

$ hbase org.apache.hadoop.hbase.util.RegionSplitter pre_splitted_table HexStringSplit -c 10 -f f1

在这个命令中,我们使用了带有表名pre_splitted_table的 RegionSplitter,带有SplitAlgorithm HexStringSplit10数量的区域,f1是 ColumnFamily 名称。它创建了一个名为pre_splitted_table的表格,其中包含 10 个区域。

自动拆分

当一个区域的大小增加到高于阈值时会执行自动分割,准确地说是hbase-site.xml文件的属性hbase.hregion.max.filesize的值,默认值为 10 GB。

强制拆分

很多情况下,数据增加后数据分布会不均匀。HBase 允许用户通过指定拆分键来拆分表的所有区域或特定区域。触发强制拆分的命令如下:

split 'tableName' 
split 'tableName', 'splitKey'
split 'regionName', 'splitKey'

命令

要使进入 HBase 外壳模式,请使用以下命令:

$ ${HBASE_HOME}/bin/hbase shell
.
.
HBase Shell; 
hbase>

您可以使用help获取所有命令的列表。

救命

hbase> help
HBASE SHELL COMMANDS:

创建

用于在 HBase 中创建新表。现在,我们将坚持最简单的版本,如下所示:

hbase> create 'test', 'cf'
0 row(s) in 1.2200 seconds

列表

使用list命令显示创建的表格列表,如下所示:

hbase> list 'test'
TABLE
test
1 row(s) in 0.0350 seconds

=> ["test"]

要将数据放入表格中,使用put命令:

hbase> put 'test', 'row1', 'cf:a', 'value1'
0 row(s) in 0.1770 seconds

hbase> put 'test', 'row2', 'cf:b', 'value2'
0 row(s) in 0.0160 seconds
hbase> put 'test', 'row3', 'cf:c', 'value3'
0 row(s) in 0.0260 seconds

扫描

Scan 命令用于扫描表格中的数据。您可以限制扫描,但目前,所有数据都已提取:

hbase> scan 'test'
ROW       COLUMN+CELL
 row1     column=cf:a, timestamp=1403759475114, value=value1
 row2     column=cf:b, timestamp=1403759492807, value=value2
 row3     column=cf:c, timestamp=1403759503155, value=value3
3 row(s) in 0.0440 seconds

获取

Get命令将一次检索一行数据,如下命令所示:

hbase> get 'test', 'row1'
COLUMN                CELL
 cf:a                 timestamp=1403759475114, value=value1
1 row(s) in 0.0230 seconds

禁用

要在表格中进行任何设置更改,我们必须使用disable命令禁用表格,执行该操作,然后重新启用它。您可以使用enable命令重新启用它。以下命令解释了禁用命令:

hbase> disable 'test'
0 row(s) in 1.6270 seconds

hbase> enable 'test'
0 row(s) in 0.4500 seconds

下降

Drop 命令删除一个表,如下所示:

hbase> drop 'test'
0 row(s) in 0.2900 seconds

糖化血红蛋白 Hive 整合

分析师通常更喜欢 Hive 环境,因为类似 SQL 的语法很舒服。HBase 与 Hive 很好地集成在一起,使用 Hive 与之接口的存储处理器。Hive 中的创建表语法如下所示:

CREATE EXTERNAL TABLE hbase_table_1(key int, value string) 
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,ColumnFamily:Column1, columnFalimy:column2")
TBLPROPERTIES ("hbase.table.name" = "xyz");

让我们了解表格的语法和关键字:

  • EXTERNAL:如果 HBase 中的表已经存在,或者 HBase 中的表是新的,并且您希望 Hive 只管理元数据而不管理实际数据,则使用此。
  • STORED BY:HBasetoragehandler 有用来处理来自 HBA ses 的输入和输出。
  • SERDEPROPERTIES : Hive 列到 HBase 列家族:列映射在这里需要指定。在本例中,键映射为 rowkey,值映射到 ColumnFamily cf1 的 val 列。
  • TBLPROPERTIES:映射 HBase 表名。

性能调整

HBase 架构提供了使用不同优化的灵活性,以帮助系统实现最佳性能,提高可扩展性和效率,并提供更好的性能。由于其灵活的数据模型及其接口组件,HBase 是最受欢迎的 NoSQL 技术。

非常有用且广泛使用的组件有:

  • 压缩
  • 过滤
  • 计数器
  • 糖化血红蛋白协同处理器

压缩

由于面向列的设计,HBase 可以利用压缩,这是对列族进行块压缩的理想选择。HBase 以最佳方式处理稀疏数据,因为空值不会占用任何引用或空间。压缩可以是不同的类型,并且可以根据压缩比、编码时间和解码时间进行比较。默认情况下,HBase 不应用或启用任何压缩;要使用压缩,必须启用“柱族”。

插件可用的压缩类型如下:

  • GZip :它提供了更高的压缩比,但是编码和解码比较慢,而且占用空间大。对于不常见的需要高压缩比的数据,我们可以使用 GZip 作为压缩。
  • LZO :它提供了更快的编码和解码,但是与 GZip 相比压缩率更低。LZO 获得了 GPL 许可,因此它没有与 HBase 一起发货。
  • 爽快:爽快是理想的压缩类型,提供更快的编码或解码。它的压缩率介于 LZO 和 GZip 之间。爽快是在谷歌的 BSD 许可下。

使用外壳程序对现有表的列族启用压缩的代码如下:

hbase> disable 'test'
hbase> alter 'test', {NAME => 'cf', COMPRESSION => 'GZ'}
hbase> enable 'test'

要在 ColumnFamily 上创建具有压缩功能的新表,代码如下:

hbase> create 'test2', { NAME => 'cf2', COMPRESSION => 'SNAPPY' }

过滤器

HBase 中的过滤器可用于根据某些条件过滤数据。它们对于减少要处理的数据量非常有用,尤其有助于为客户端节省网络带宽和要处理的数据量。过滤器将处理逻辑移向节点中的数据,结果被累积并发送给客户端。这通过可管理的流程和代码提高了性能。过滤器足够强大,可以处理行、列、列族、限定符、值、时间戳等。过滤器更适合作为一个 Java 应用编程接口使用,但也可以从一个 HBase 外壳中使用。过滤器也可以用来执行一些特别的分析。

一些常用的过滤器,如下面列出的过滤器,已经存在,并且非常有用:

  • 列值:最广泛使用的过滤器类型是列值,因为 HBase 具有面向列的架构设计。我们现在来看一些流行的面向列值的过滤器:

  • 单列值过滤器:单列值过滤器过滤糖化血红蛋白表的列值上的数据。

    Syntax:
    SingleColumnValueFilter ('<ColumnFamily>', '<qualifier>', <compare operator>, '<comparator>'
    [, <filterIfColumnMissing_boolean>][, <latest_version_boolean>]) 
    
    Usage:
    SingleColumnValueFilter ('ColFamilyA', 'Column1', <=, 'abc', true, false)
    SingleColumnValueFilter ('ColFamilyA', 'Column1', <=, 'abc')
    
    
  • 单列值排除过滤器:单列值排除过滤器用于从 HBase 表的列值中排除值。

    Syntax:
    SingleColumnValueExcludeFilter (<ColumnFamily>, <qualifier>, <compare operators>, <comparator> [, <latest_version_boolean>][, <filterIfColumnMissing_boolean>])
    Example:
    SingleColumnValueExcludeFilter ('FamilyA', 'Column1', '<=', 'abc', 'false', 'true')
    SingleColumnValueExcludeFilter ('FamilyA', 'Column1', '<=', 'abc')
    
    
  • 列测距仪过滤器:列测距仪过滤器对列进行操作,根据最小列、最大列或两者对列进行过滤。我们可以通过minColumnInclusive_bool布尔参数启用或禁用最小列值约束,通过maxColumnInclusive_bool禁用maxColumnValue

    Syntax:
    ColumnRangeFilter ('<minColumn >', <minColumnInclusive_bool>, '<maxColumn>', <maxColumnInclusive_bool>)
    Example:
    ColumnRangeFilter ('abc', true, 'xyz', false)
    
    
  • 键值:一些过滤器对键值数据进行操作。

  • FamilyFilter :它对 Column Family 进行操作,将每个姓氏与比较器进行比较;如果比较结果为真,它将返回该系列中的所有键值。

    Syntax:
    FamilyFilter (<compareOp>, '<family_comparator>')
    
    
  • 限定符过滤器:它对限定符进行操作,并将每个限定符名称与比较器进行比较。

    Syntax:
    QualifierFilter (<compareOp>, '<qualifier_comparator>')
    
    
  • RowKey :过滤器也可以进行行级比较,过滤数据。

  • 行过滤器:使用比较运算符比较每个行键和比较器。

    Syntax:
    RowFilter (<compareOp>, '<row_comparator>')
    Example:
    RowFilter (<=, 'binary:xyz)
    
    
  • 多个过滤器:我们可以将过滤器的组合添加到过滤器列表并扫描它们。我们可以使用:

    FilterList.Operator.MUST_PASS_ALL or FilterList.Operator.MUST_PASS_ONE.
    FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);
    // Use some filter and add it in the list.
    list.add(filter1);
    scan.setFilter(list);
    
    

    在过滤器之间选择“或”或“与”

我们有许多其他可用的过滤器,如果我们需要,我们还可以创建一个自定义过滤器。

计数器

HBase 的另一个有用功能是计数器。它们可以用作分布式计数器来增加一个列值,而不需要为增加一个值而锁定整个行并减少写入时的同步。在许多情况下需要递增或计数器,尤其是在许多分析系统中,如数字营销、点击流分析、文档索引模型等。HBase 计数器可以用非常少的开销进行管理。分布式计数器非常有用,但在分布式环境中会带来不同的挑战,因为计数器值将同时出现在多个服务器中,并且写入和读取请求将相当高。因此,为了提高效率,我们在 HBase 中有两种类型的计数器,即单计数器和多计数器。多个计数器可以被设计成根据 rowkey 分布在单个分层级别中计数,并且可以通过对计数器求和来获得整个计数器值。计数器的类型解释如下:

  • Single Counter: Single Counters work on specified columns in the HTable, row wise. The methods for Single Counters provided for an HTable, are as follows:

    long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,long amount) throws IOException
    long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,long amount, boolean writeToWAL) throws IOException
    

    我们应该使用带有writeToWAL的第二种方法来指定预写日志是否应该是活动的。

  • 多计数器:多计数器将在 HTable 中以限定符方式工作。为 HTable 提供的多计数器的方法如下:

    Increment addColumn(byte[] family, byte[] qualifier, long amount)
    

HbA1c 协处理器

协处理器是一个框架,HBase 提供来授权和执行区域服务器上的一些定制代码。协处理器使计算更接近数据,特别是区域方式。协处理器对于计算聚合器、二级索引、复杂过滤、审计和授权非常有用。

HBase 实现了一些有用的协处理器,并对协处理器的扩展和定制实现开放。协处理器可以基于两种策略来设计——观测器和端点,如下所示:

  • 观察者:顾名思义,观察者协处理器可以设计成作为回调或者在某些事件的情况下工作。观察者可以被认为是关系数据库管理系统中的触发器,可以在区域、主或沃尔级别操作。观察者分别在事件之前和之后有方法覆盖的PreXXXPostXXX约定。以下是根据不同级别的观察者类型:
    • 区域观察者:区域观察者处理区域级数据。这些可用于创建辅助索引,以帮助检索。对于每个可点击区域,我们可以有一个区域观察者。RegionObserver 为数据操作事件提供了钩子,如GetPutDeleteScan等。常见的例子包括Get操作的preGetpostGet以及prePutpostPut操作的Put
    • 主观察器:主观察器在主级别运行,处理 DDL 类型的操作,如创建、删除和修改表。使用 MasterObserver 时应格外小心。
    • 沃尔观察员:这为沃尔处理提供了挂钩。它只有两种方法;preWALWrite()postWALWrite()
  • 端点:端点是可以通过客户端接口直接调用来调用的操作。如果观察者可以被认为是触发器,那么端点可以被认为是关系数据库管理系统的存储过程。HBase 可以有数千万行或更多行;如果我们需要计算一个聚合函数,比如该表上的一个和,我们可以编写一个端点协处理器,它将在区域内执行,并像在地图端处理中一样从一个区域返回计算结果。随后,来自所有区域的结果可以像在减少边处理中一样执行求和。Endpoint 的优势在于处理将更接近数据,集成将更高效。

总结

在本章中,您已经了解到 HBase 是一个 NoSQL 的、面向列的数据库,具有灵活的模式。它有以下组件——主服务器、区域服务器和区域,并利用 Zookeeper 通过两个缓存来监控它们——区域服务器中的 WAL 和区域中的 MemStore。我们还看到了 HBase 如何通过执行区域拆分和压缩来管理数据。与 CAP 定理的可用性相比,HBase 提供了分区容差和高得多的一致性级别。

该数据库数据模型不同于传统的关系数据库管理系统,因为数据存储在面向列的数据库和键值对的多维映射中。行由 rowkey 标识,并使用一系列 rowkey 值分布在集群中。Rowkey 对于设计用于性能和数据管理的 HBase 模式至关重要。

在 Hadoop 项目中,数据管理是非常关键的一步。在大数据的背景下,Hadoop 具有数据管理方面的优势。但是用一些脚本来管理它变得很困难,并带来了许多挑战。我们将在下一章中介绍这些工具,这些工具可以帮助我们使用 Sqoop 和 Flume 管理数据。

六、Hadoop 中的数据摄取——SQOOP 和 Flume

数据摄取至关重要,对于任何大数据项目都应予以强调,因为数据量通常以万亿字节或千兆字节为单位,可能是千兆字节。处理海量数据始终是一项挑战和关键。由于大数据系统普遍用于处理非结构化或半结构化数据,这带来了大量数据的复杂数据源。随着每个数据源的增加,系统的复杂性也随之增加。许多领域或数据类型,如社交媒体、营销、医疗保健中的基因、视频和音频系统、电信 CDR 等,都有不同的数据来源。其中许多大规模一致地产生或发送数据。关键问题是管理数据一致性以及如何利用可用资源。尤其是数据摄取,在 Hadoop 或一般大数据中是复杂的,因为数据源和处理现在是批处理、流式、实时的。这也增加了复杂性和管理。

在这一章中,我们将研究 Hadoop 中数据摄取的一些挑战,以及使用 Sqoop 和 Flume 等工具的可能解决方案。我们将详细介绍 Sqoop 和 Flume。

数据来源

由于处理各种数据和大量数据的能力,Hadoop 的数据源增加了,复杂性也随之大大增加。我们现在看到 Hadoop 中处理了大量的批处理、流和实时分析,如果不按照要求设计,数据摄入可能会成为瓶颈或破坏系统。

让我们来看一些数据源,它们可以连续产生大量数据或一致数据:

  • 数据传感器:这些是上千个传感器,持续产生数据。
  • 机器数据:为产生应近实时处理的数据,避免巨大损失。
  • 电信数据 : CDR 数据和其他电信数据产生大量数据。
  • 医疗保健系统数据:基因、图像、ECR 记录都是非结构化且复杂的要处理。
  • 社交媒体:脸书、推特、谷歌 Plus、YouTube 等获得了巨大的数据量。
  • 地质数据:半导体和其他地质数据产生了巨大的数据量。
  • 地图:地图数据量巨大,处理数据也是地图中的一个挑战。
  • 航空航天:飞行细节和跑道管理系统实时产生大量数据和处理。
  • 天文学:行星和其他物体产生重影,必须以更快的速度进行处理。
  • 移动数据:移动以高速率产生许多事件和大量数据。

这些只是产生万亿字节或千兆字节数据的一些域或数据源。数据接收至关重要,它可以决定系统的成败。

数据摄取方面的挑战

以下是数据源摄取方面的挑战:

  • 多源摄入
  • 流/实时摄取
  • 可量测性
  • 并行处理
  • 数据质量
  • 机器数据可以以每分钟 GB 为单位进行大规模存储

Sqoop

Sqoop 可以高效地处理传统数据库、Hadoop 和像 HBase、Cassandra 这样的 NoSQL 数据库之间的数据传输。Sqoop 通过提供从这些数据源导入和导出 Hadoop 中的数据的实用程序来提供帮助。Sqoop 有助于并行执行进程,因此速度更快。Sqoop 利用连接器和驱动与底层数据库源连接,在多个 Mapper 进程中执行的导入和导出,以便并行更快地执行数据。Sqoop 可以在 HDFS、Hive 或 HBase 上处理批量数据传输。

连接器和驱动器

Sqoop 实用程序需要驱动程序和连接器,以便在数据库和 Hadoop 之间进行数据传输。配置 Sqoop 的一个重要步骤是获取驱动程序并用 Sqoop 进行配置。Sqoop 需要驱动程序来与之连接,并且应该是 Sqoop 1 的 JDBC 驱动程序,由数据库供应商为相应的数据库提供。驱动程序不随 Sqoop 一起提供,因为有些驱动程序是有许可证的,因此我们必须获得数据库的 JDBC 驱动程序,并将其保存在 Sqoop 库中。连接器需要通过获取数据库的元数据信息来优化数据传输。所有关系数据库管理系统数据库都使用 SQL,但是有些命令和语法随其他数据库而异。这使得获取元数据和优化数据变得困难。Sqoop 提供了通用连接器,可用于数据库,如 MySQL、Oracle、PostgreSQL、DB2 和 SQL Server,但不是最佳连接器。为了获得最佳性能,一些供应商发布了可以插入 Sqoop 的连接器,如下图所示:

Connectors and drivers

Sqoop 1 体系结构

Sqoop1 架构是客户端工具,与 Hadoop 集群紧密耦合。客户端启动的一个 Sqoop 命令根据连接器和驱动程序接口获取表、列和数据类型的元数据。导入或导出被转换为仅映射作业程序,以便在数据库和 Hadoop 之间并行加载数据。客户端应该有适当的连接器和驱动程序来执行这个过程。

Sqoop 架构如下图所示:

Sqoop 1 architecture

Sqoop 1 的限制

在对数据摄取的 Sqoop 1 进行广泛调整后,实现的一些限制导致了 Sqoop 2,它们是:

  • 连接器必须支持序列化格式,否则 Sqoop 无法以该格式传输数据,连接器必须是 JDBC 驱动程序。一些数据库供应商不提供它。
  • 不易配置和安装。
  • 监控和调试很困难。
  • 安全问题,因为 Sqoop 1 需要 root 访问权限来安装和配置它。
  • 仅支持命令行参数。
  • 连接器仅位于 JDBC。

Sqoop 2 体系结构

Sqoop 2 架构克服了我们之前讨论过的 Sqoop 1 的局限性。Sqoop 2 的特点是:

  • Sqoop 2 将 REST API 公开为 web 服务,可以很容易地与其他系统集成。
  • 连接器和驱动程序集中管理在一个地方。
  • Sqoop 2 配置良好,并与 HBase、Hive 和 Oozie 集成,以实现互操作性和管理。
  • 连接器可以不基于 JDBC。
  • 作为一个面向服务的设计,Sqoop 2 可以具有基于角色的身份验证和审计跟踪记录,以提高安全性。

以下是 Sqoop 2 的架构:

Sqoop 2 architecture

进口

Sqoop 导入分两步执行:

  1. 收集元数据
  2. 仅提交地图作业

下图解释了导入到 Sqoop 的过程:

Imports

Sqoop 导入提供以下选项:

  • 导入整个表格:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities
    
  • 导入数据子集:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --where "country = 'USA'"
    
  • 更改文件格式,默认情况下数据会以制表符分隔的 csv 格式保存,但 Sqoop 提供了以 Hadoop SequenceFile、Avro 二进制格式和 Parquet 文件保存数据的选项:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --as-sequencefile
    
    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --as-avrodatafile
    
  • 压缩导入数据:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --table cities \
    --compress \
    --compression-codec org.apache.hadoop.io.compress.BZip2Codec
    
  • 批量进口:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --table cities \
    --direct
    
  • 导入你所有的表:

    sqoop import-all-tables \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop
    
  • 增量导入:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table visits \
    --incremental append \
    --check-column id \
    --last-value 1
    
  • 自由形式查询导入:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --query 'SELECT normcities.id, \
        countries.country, \
        normcities.city \
        FROM normcities \
        JOIN countries USING(country_id) \
        WHERE $CONDITIONS' \
    --split-by id \
    --target-dir cities
    
  • 自定义边界查询导入:

    sqoop import \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --query 'SELECT normcities.id, \
    countries.country, \
    normcities.city \
    FROM normcities \
    JOIN countries USING(country_id) \
    WHERE $CONDITIONS' \
    --split-by id \
    --target-dir cities \
    --boundary-query "select min(id), max(id) from normcities"
    

出口

Sqoop Export 也在类似的流程,只是来源会是 HDFS。导出分两步进行;

  • 收集元数据
  • 提交仅地图作业

下图解释了导出到 Sqoop 的过程:

Exports

Sqoop 导出有以下选项:

  • 将 HDFS 目录下的文件导出到表中:

    sqoop export \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --export-dir cities
    
  • 批量插入导出:

    sqoop export \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --export-dir cities \
    --batch
    
  • 更新现有数据集:

    sqoop export \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --update-key id
    
  • 追加出口:

    sqoop export \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --update-key id \
    --update-mode allowinsert
    
  • 栏目导出:

    sqoop export \
    --connect jdbc:mysql://mysql.example.com/sqoop \
    --username sqoop \
    --password sqoop \
    --table cities \
    --columns country,city
    

ApacheFlume

Flume 是极为流行的数据摄取系统,可用于摄取来自不同多源的数据,并可将其放入多个目的地。Flume 提供了一个大规模处理数据的框架,非常可靠。

Flume 通常被描述为分布式的、可靠的、可扩展的、可管理的和可定制的,以从不同的多个数据源摄取和处理数据到多个目的地。

正如我们已经讨论过的不同类型的数据源。让设计变得更加困难的一件事是,数据格式在某些情况下会频繁变化,尤其是 JSON 中的社交媒体数据,通常一个大数据系统有多个数据源。Flume 在处理此类场景时非常高效,并且对每个数据源和处理层提供了更好的控制。Flume 可以配置为三种模式:单节点、伪分布式和全分布式模式。

由于 Flume 具有高度可靠、灵活、可定制、可扩展的能力,并且能够以分布式方式并行处理大数据,因此对其进行了调整。

可靠性

分布式环境下的可靠性难以设计和实现。Flume 在可靠性方面表现出色。Flume 动态处理逻辑组件,以实现负载平衡和可靠性。如果代理节点是活动的,它可以保证消息的传递。正如我们提到的,可靠性是很难实现的,尽管 Flume 可以用一些成本来实现,并且可能是资源密集型的。根据要求和需要,Flume 提供了三个可靠性级别,分别是:

  • 端到端:端到端级别是最可靠的级别,只要代理还活着,就保证了事件的交付。持久性是通过将事件写入 提前写入日志 ( WAL )文件来实现的,该文件可用于恢复事件,即使在崩溃的情况下。
  • 故障时存储:故障级存储依赖于发送事件的确认确认来接收。如果节点未收到确认,数据将存储在本地磁盘中,并等待直到识别出另一个节点的节点恢复。这个级别是可靠的,但是在静默故障的情况下可能会有数据丢失。
  • 尽力而为:尽力水平可靠性最低,会有数据丢失,但是数据处理会更快。尽最大努力,不会尝试重试或确认,因此数据可能会丢失。

Flume 建筑

Flume 架构是一个非常灵活和可定制的组合代理,可以配置为数据流进程的多层。数据流设计允许将源或数据从源传输或处理到目标。这些组件以链的形式连接在一起,位于不同的层中,称为逻辑节点的配置。逻辑节点配置在三个层中,即客户端、收集器和存储。第一层是从数据源捕获数据的客户端,将其转发给收集器,收集器在处理后整合数据并将其发送到存储层。

Flume 过程和逻辑组件由 Flume 管理员控制。逻辑节点非常灵活,可以由主节点动态添加或删除。

多层拓扑

在 Flume 中,代理可以配置为客户端、收集器或存储。客户端代理从数据源获取数据,并使用 Avro/节俭或中间存储区域将其推送到另一个代理。收集器代理从另一个代理获取输入,并充当存储代理的源。存储代理从收集器代理或其他代理获取输入,并将数据保存在最终存储位置。每层可以有多个独立的代理,它们可以充当负载平衡器。层接收器可以将事件转发到任何可用的下一跳目的地。Flume 拓扑如下图所示:

Multitier topology

Flume 实体有两个组件:Flume 主节点和 Flume 节点。

Flume 师傅

正如我们前面提到的,Flume 主控器分配和协调物理和动态逻辑层,因此,主控器对于实现的灵活性和可靠性非常重要。逻辑节点还与主节点一起检查配置中的任何更新。为了实现 Master 的高可用性,我们可以配置多个 Master 或者使用 Zookeeper 来管理 Master 和 Nodes。

Flume 节点

Flume 节点是物理 JVM 进程,运行在各个节点。在 Flume 中,每台机器都有一个 JVM 进程作为物理节点,充当多个逻辑进程的容器。即使代理和收集器在逻辑上是独立的进程,它们也可以在同一台机器上运行。

Flume 中的逻辑组件有两个,即事件和代理。我们将讨论以下组件:

  • 事件 : Flume 有一个数据流模型,流中的一个数据单位叫做一个事件。事件携带有效负载和一组可选的头。可以通过实现事件接口或覆盖 Flume 中的现有事件来自定义事件。事件通过一个或多个代理,特别是从源到通道,再到代理的接收器组件。

  • Agent: An Agent in Flume provides the flexibility to Flume architecture, as it runs on a separate JVM process. An Agent in Flume has three components: Source, Channel, and Sink. Agent works on hop-by-hop flow. It receives events from the Source and puts it in a Channel. It then stores or processes the events and forwards them via Sink to the next hop destination. An Agent can have multiple Sink to forward the events to multiple Agents. The following figure explains the Agent's role:

    Flume nodes

制剂中的成分

让我们看看代理的组件,也就是接下来几节中的源和宿。

来源

仅来源监听并接收来自数据源的事件。然后,它将其转换为事件,并将其放入通道队列。Flume 与各种源类型(如 Avro、节俭、HTTP 等)集成得非常好。为了定义一个源,我们必须设置属性类型的值。一些常用的源类型有:

|

来源类型

|

属性类型的值

|

要为源类型设置的强制属性

|
| --- | --- | --- |
| 欧罗欧欧欧罗欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧 | avro | 绑定:主机名或 IP 地址端口:要绑定的端口号 |
| 节约 | thrift | 绑定:主机名或 IP 地址端口:要绑定的端口号 |
| Unix 命令 | exec | 命令:像 tail 或 cat 一样执行的 unix 命令 |
| JMS 源 | jms | initialContextFactory:例:org.apache.activemq.jndi.ActiveMQInitialContextFactory``connectionFactory:连接工厂的 JNDI 名称应该显示为:providerURL:JMS 提供者的网址destinationName;目的名字destinationType:目的地类型(队列或主题) |
| 假脱机目录源 | spooldir | spoolDir:从中读取文件的目录 |
| 推特 | org.apache.flume.source.twitter.TwitterSource | 注:这个来源是高度实验性的,可能会在小版本的 Flume 之间改变。自担风险使用:consumerKey : OAuth 消费者密钥consumerSecret : OAuth 消费者秘密accessToken : OAuth 访问令牌accessTokenSecret : OAuth 令牌秘密 |
| NetCat 源 | netcat | 绑定:主机名或 IP 地址端口:要绑定的端口号 |
| 序列发生器源 | seq | 序列生成器从 0 开始,递增 1 索引。 |
| HTTP 源 | http | 端口:要绑定的端口号 |

更多详情,可以查看 ApacheFlume 用户指南页面https://flume.apache.org/FlumeUserGuide.html#flume-sources

示例:对于创建应该获取日志文件更新数据的代理源,强制参数和值应该是:

  • :T0
  • 命令 : tail –f log_file
  • 频道 : <channel_name>

以下命令解释了上述要点:

agent.sources.source_log-tail.type = exec
agent.sources.source_log-tail.command = tail -F /log/system.log
agent.sources.source_log-tail.channels = channel1

下沉

接收器从通道收集事件,并将其作为代理的输出转发到下一跳目的地。

为了定义接收器,我们必须设置属性类型的值。一些常用的 Flume 类型有:

|

Flume 类型

|

属性类型的值

|

为接收器类型设置的强制属性

|
| --- | --- | --- |
| HDFS Flume | hdfs | hdfs.path–HDFS 目录路径 |
| 记录器接收器 | logger |   |
| 欧罗欧欧欧罗欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧 | avro | 绑定:主机名或 IP 地址端口:要绑定的端口号 |
| 节约 | thrift | 绑定:主机名或 IP 地址端口:要绑定的端口号 |
| IRC 接收器 | irc | hostname:主机名或 IP 地址nick:昵称chan:通道 |
| 文件滚动接收器 | file_roll | sink.directory:存储文件的目录 |
| 零锌 | null |   |
| HBaseSinks | hbase | table:要写入的 HBase 中的表的名称。columnFamily:要写入的 HBase 中的列族。 |
| 异步接收器 | asynchbase | 表:Hbase 中要写入的表的名称。columnFamily:要写入的 HBase 中的列族。 |
| MorphlineSolrSink | org.apache.flume.sink.solr.morphline.MorphlineSolrSink | morphlineFile:本地文件系统上 morphline 配置文件的相对或绝对路径。示例:/etc/flume-ng/conf/morphline.conf |
| 弹性搜索 | org.apache.flume.sink.elasticsearch.ElasticSearchSink | hostNames:主机名:端口的逗号分隔列表,如果端口不存在,将使用默认端口 9300 |

示例:对于输出到 hdfs 的接收器:

agent.sinks.log-hdfs.channel = channel1
agent.sinks.log-hdfs.type = hdfs
agent.sinks.log-hdfs.hdfs.path = hdfs://<server> /log/system.log/

渠道

通道是代理中的临时存储,可用于保存从源接收的事件,并将事件传输到接收器。通道通常有两种形式:

  • 内存队列:这些通道提供高吞吐量,因为数据不会持久,因此如果代理出现故障,事件不会恢复。
  • 基于磁盘的队列:即使在事件失败的情况下,这些通道也提供完全恢复,但是由于事件的持续存在,比内存中的稍慢。

记忆通道、文件通道和 JDBC 通道是三种常用的 Flume 通道。我们将在接下来的章节中讨论它们。

记忆通道

内存通道在内存堆空间中存储事件。内存通道更快,因为内存,因为它不会将数据保存到磁盘。如果担心数据丢失,则不应使用内存通道,因为如果进程或机器发生崩溃,数据将无法恢复。可以配置用于定义内存通道的属性有:

  • 类型:房产价值应为org.apache.flume.channel.MemoryChannel
  • 容量:这是频道能容纳的最大赛事数量。默认值为100
  • transactionCapacity :这是每个事务中源可以向通道发送事件的最大事件数。默认值为100
  • 保持活动状态:这是添加和删除事件的超时时间。默认值为3
  • 字节容量:这是通道允许的最大空间大小。默认值是分配给 JVM 的总堆内存的 80%。
  • 字节容量缓冲区百分比:这是通道的字节容量和通道中当前所有事件主体的总大小之间的缓冲区百分比。默认值为20

文件通道

文件通道将事件保存在磁盘上,因此在崩溃时不会丢失事件数据。文件通道用于数据丢失不可接受的地方,用于实现处理的可靠性。可以设置的配置属性有:

  • 类型:房产的值应为file
  • 容量:频道可以容纳的最大事件数。默认值为1000000
  • 事务处理能力:每个事务中,源可以向通道发送事件的最大事件数。默认值为10000
  • 检查点目录:应该保存检查点数据的目录路径。
  • 数据目录:应该保存数据的目录。目录可以是多个,这可以提高文件通道的性能。
  • useualcheckpoints:默认情况下,该属性的值为false,表示不会备份检查点目录。如果true,将备份检查点目录。
  • 备份检查点目录:如果useDualCheckpoints为真,则保存检查点的目录。
  • 检查点间隔:检查点之间的时间。
  • 最大文件大小:单个日志文件的最大大小。默认值为2146435071
  • 最小要求空间:通道将停止运行以避免数据损坏的最小尺寸。默认值为524288000
  • 保持活动状态:添加和删除事件的超时时间。默认值为3

JDBC 海峡

JDBC 频道将事件保存在数据库中,目前只支持 derby 数据库。该通道可用于应恢复事件的地方,所有事件处理都至关重要。为 JDBC 频道设置的配置属性有:

  • 类型:类型的值应该是jdbc
  • db.type :数据库默认的类型,目前只能设置DERBY值。
  • 司机班:供应商 JDBC 司机班。默认值为org.apache.derby.jdbc.EmbeddedDriver
  • 驱动程序. url :连接 url。
  • db.username :要连接的数据库的用户标识。

示例:

db.password: password of the user id for database to connect.Example of a Channel:agent.channels = c1
agent.channels.c1.type = memory
agent.channels.c1.capacity = 10000
agent.channels.c1.transactionCapacity = 10000
agent.channels.c1.byteCapacityBufferPercentage = 20
agent.channels.c1.byteCapacity = 800000

下图显示了一个简单的 Flume 配置:

JDBC Channel

配置 Flume 的示例

Flume 可配置为单智能体或多智能体;我们将在接下来的章节中看到相应的例子。

单一代理示例

我们将查看记录器示例,并将其保存在 HDFS 和一个内存通道中,使用以下代码:

# Source of an Agent with tail
agent.source = source_log-tail
agent.sources.source_log-tail.type = exec
agent.sources.source_log-tail.command = tail -F /log/logger.log
agent.sources.source_log-tail.channels = memoryChannel

# Sink of an Agent to save in HDFS
agent.sinks = log-hdfs
agent.sinks.log-hdfs.channel = memoryChannel
agent.sinks.log-hdfs.type = hdfs
agent.sinks.log-hdfs.hdfs.path = /log/logger.log

# Channel of an Agent to store in memory
agent.channels = memoryChannel
agent.channels.memoryChannel.type = memory
agent.channels.memoryChannel.capacity = 10000
agent.channels.memoryChannel.transactionCapacity = 10000
agent.channels.memoryChannel.byteCapacityBufferPercentage = 20
agent.channels.memoryChannel.byteCapacity = 800000

使用以下命令启动 Flume 过程:

$ flume-ng agent -n agent -c conf -f conf/flume-conf.properties -Dflume.root.logger=INFO,console 

一个代理中的多个流

我们可以在一个代理配置中有多个源、通道和接收器,使用以下命令:

<Agent>.sources = <Source1> <Source2>
<Agent>.sinks = <Sink1> <Sink2>
<Agent>.channels = <Channel1> <Channel2>

我们可以在接下来的章节中定义相应的源、汇和通道。

配置多代理设置

要配置多代理设置,我们必须通过 Avro/节俭链接代理,其中一个代理的 Avro 接收器类型充当另一个代理的 Avro 源类型。我们应该有两个特工。第一个将有一个记录器源和一个 Avro 接收器,如以下代码所示:

# Source of an Agent with tail
agent1.source = source_log-tail
agent1.sources.source_log-tail.type = exec
agent1.sources.source_log-tail.command = tail -F /log/logger.log
agent1.sources.source_log-tail.channels = memoryChannel

agent1.sinks.avro-sink.type = avro
agent1.sinks.avro-sink.hostname = 192.168.0.1 #<hostname>
agent1.sinks.avro-sink.port = 1111

agent1.channels = memoryChannel
agent1.channels.memoryChannel.type = memory
agent1.channels.memoryChannel.capacity = 10000
agent1.channels.memoryChannel.transactionCapacity = 10000
agent1.channels.memoryChannel.byteCapacityBufferPercentage = 20
agent1.channels.memoryChannel.byteCapacity = 800000

第二个代理将拥有第一个代理接收器的 Avro 源:

# Source of an Agent with Avro source listening to sink of first Agent
agent2.source = avro-sink
agent2.sources.avro-sink.type = avro
agent2.sources.avro-sink.hostname = 192.168.0.1 #<hostname>
agent2.sources.avro-sink.port = 1111
agent2.sources.avro-sink.channels = memoryChannel

# Sink of an Agent to save in HDFS
agent2.sinks = log-hdfs
agent2.sinks.log-hdfs.channel = memoryChannel
agent2.sinks.log-hdfs.type = hdfs
agent2.sinks.log-hdfs.hdfs.path = /log/logger.log

agent2.channels = memoryChannel
agent2.channels.memoryChannel.type = memory
agent2.channels.memoryChannel.capacity = 10000
agent2.channels.memoryChannel.transactionCapacity = 10000
agent2.channels.memoryChannel.byteCapacityBufferPercentage = 20
agent2.channels.memoryChannel.byteCapacity = 800000

启动不同节点的 Flume 代理。

使用以下命令启动节点 1 中的代理 2:

$ flume-ng agent -n agent2 -c conf -f conf/flume-conf.properties -Dflume.root.logger=INFO,console 

使用以下命令启动节点 2 中的代理 1:

$ flume-ng agent -n agent1 -c conf -f conf/flume-conf.properties -Dflume.root.logger=INFO,console 

总结

大数据项目的关键阶段之一是数据摄取,我们已经讨论过了。开发和管理起来既困难又复杂。如今,数据源采用不同的格式,并以高速产生数据。我们在一个坚果外壳中探索了 Sqoop 和 Flume 架构及其应用。

我们还学习了如何使用连接器和驱动程序在 Hadoop 和数据库之间导入和导出数据。Sqoop 1 仅基于 JDBC,客户端责任和互操作性仅限于代码。Sqoop 2 不仅基于 JDBC,还公开了易于集成的 restful API 网络架构。

Apache Flume 是一个可靠、灵活、可定制和可扩展的框架,用于从扇入和扇出过程中获取数据。Flume 具有多层拓扑,其中代理可以配置为用作客户端、收集器或存储层。

Hadoop 主要是一个批处理系统,它具有有限的用例以及流数据分析和实时能力所需的许多大数据用例。对于处理实时分析,我们将在下一章讨论 Storm 和 Spark,以有效地处理数据。

七、流和实时分析–Storm 和 Spark

正如我们已经讨论过的,Hadoop 是一个批处理系统,一些数据源类型的速度或速率、数据量各不相同。许多系统,尤其是机器,会持续生成大量数据,它们需要处理如此大量的数据来保持质量并避免严重的损失,因此出现了对流处理的需求。为了设计构建为 Lambda 实现的系统,即批处理和流处理系统,我们应该结合不同的环境,这些环境可以相互集成来处理数据,这显然增加了系统设计的复杂性。流数据的存储、分析、处理和维护非常复杂。版本 2 之前。 x 的时候,Hadoop 只是一个批处理系统,在出现了 YARN 等框架以及这些框架与 YARN 的集成之后,Hadoop 可以设计成性能更好的流和实时分析。各种计划和贡献提升了 Hadoop 与 Storm 和 Spark 等系统的集成能力。

在本章中,我们将介绍 Storm 和 Spark 框架的范例,以便高效地处理流和进行实时分析。

Storm 入门

Storm 可以非常快速地处理流数据(每个节点每秒钟超过一百万条消息);它是可扩展的(集群的数千个工作节点)、容错的和可靠的(消息处理得到保证)。Storm 易于使用和部署,这也简化了它的可维护性。Hadoop 主要是为批处理和 Lambda 架构系统设计的。Storm 与 Hadoop 很好地集成在一起,以便为大数据提供可靠的分布式实时流分析和良好的容错能力。

Storm 由 Twitter 开发,后来贡献给了 Apache。Storm 的基准测试结果非常出色,每个节点每秒处理超过一百万组元组。Storm 利用了一个节俭界面;因此,客户端可以用任何语言编写,甚至非 JVM 语言也可以通过基于 JSON 的协议进行通信。考虑到 Storm 的复杂性,它是一个相当好用的 API。

Storm 特征

Storm 的一些重要特征如下:

  • 简单编程模型
  • 免费开放源码
  • 可以用于任何语言
  • 容错的
  • 分布式和水平可扩展—并行运行在一组机器上
  • 可靠—保证消息处理
  • 快速—实时处理流式数据
  • 易于部署和操作

Storm 的物理架构

Storm 架构基于主从模型,利用 Zookeeper 来协调主从。它由四个部分组成:

  • 光轮:掌握流程,在集群间分配处理
  • 主管:管理工人节点
  • 工作人员:执行光轮分配的任务
  • 动物园管理员:光轮和监工之间的坐标

工人通过动物园管理员主管光轮发送心跳。如果工作人员主管无法响应,则邻避将工作重新分配给集群中的另一个节点,如下图所示:

Physical architecture of Storm

Storm 的数据架构

Storm 数据架构有以下术语:

  • 喷口:产生流或数据源
  • Bolt :摄取壶嘴元组,然后对其进行处理,产生输出流;它可以用来过滤、聚合或连接数据,或者与数据库对话
  • 拓扑结构:喷口和螺栓之间的网络图

下图解释了上述要点:

Data architecture of Storm

《Storm》中的数据级抽象是:

  • 元组:Storm 数据的基本单位——一个命名的值列表
  • :一个无界的元组序列

下图显示了产生流的喷口和处理元组或流以产生不同流的螺栓:

Data architecture of Storm

Storm 拓扑

流可以通过使用流分组在螺栓之间进行划分,这允许流朝着螺栓行进。Storm 提供了以下内置流分组,您可以通过实现接口来实现自定义流分组:

  • 混洗分组:每个螺栓被统一配置以获得几乎相等数量的元组
  • 字段分组:对特定字段进行分组可以将相同字段值和不同值元组的元组合并到不同的螺栓上
  • 所有分组:每个元组可以发送到所有螺栓,但是会增加开销
  • 全局分组:所有的元组都归到一个螺栓上
  • 直接分组:生产者可以决定将哪些元组发送到哪个螺栓

Yarn 上的 Storm

对 Yarn 的 Storm 集成是在雅虎完成的,并作为开源发布。Storm 可以与 Yarn 集成,在与 Lambda 架构相同的集群上提供批处理和实时分析。Storm on YARN 将 Storm 的事件处理框架与 Hadoop 相结合,以提供低延迟处理。Storm 资源可以由 Yarn 管理,以提供 Hadoop 上 Storm 流处理的所有好处。“Yarn 上 Storm”在资源利用方面提供了高可用性、优化和弹性。

拓扑配置示例

Storm 拓扑可以由TopologyBuilder类通过创建喷口和螺栓,然后提交拓扑来配置。

喷口

在 Storm 中可以使用一些实现的喷口,例如 BaseRichSpoutclojuresportDRPCSpoutFeederSpoutfixed duplespoutMasterBatchCoordinatorRichShellSpoutrich bulotbatchtriggererShellSpout

我们可以通过扩展上述任何一个类或者实现 ISpout 接口来编写一个定制的螺栓:

public class NumberSpout extends BaseRichSpout 
{
    private SpoutOutputCollector collector;

    private static int currentNumber = 1;

    @Override
    public void open( Map conf, TopologyContext context, SpoutOutputCollector collector ) 
    {
        this.collector = collector;
    }

    @Override
    public void nextTuple() 
    {

        // Emit the next number
        collector.emit( new Values( new Integer( currentNumber++ ) ) );
    }

    @Override
    public void ack(Object id) 
    {
    }

    @Override
    public void fail(Object id) 
    {
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) 
    {
        declarer.declare( new Fields( "number" ) );
    }
}

螺栓

螺栓的一些实现在 Storm 中可用,如 BaseBasicBoltBatchProcessWordbatchrepataIdentityBoltPrepareBatchBoltPrepareRequestTestConfBolttestwordpcountertridentbluotcooler

我们可以通过扩展上述任何一个类或者实现 IBasicBolt 接口来编写一个定制的 bolt:

public class PrimeNumberBolt extends BaseRichBolt 
{
  private OutputCollector collector;
  public void prepare( Map conf, TopologyContext context, OutputCollector collector ) 
  {
    this.collector = collector;
  }

  public void execute( Tuple tuple ) 
  {
    int number = tuple.getInteger( 0 );
    if( isPrime( number) )
    {
      System.out.println( number );
    }
    collector.ack( tuple );
  }

  public void declareOutputFields( OutputFieldsDeclarer declarer )
  {
    declarer.declare( new Fields( "number" ) );
  }

  private boolean isPrime( int n )
  {
    if( n == 1 || n == 2 || n == 3 )
    {
      return true;
    }
    // Is n an even number?
    if( n % 2 == 0 )
    {
      return false;
    }

        //if not, then just check the odds
        for( int i=3; i*i<=n; i+=2 ) 
        {
            if( n % i == 0)
            {
                return false;
            }
        }
        return true;
    }
}

拓扑

TopologyBuilder类可用于配置喷口和螺栓,并提交拓扑,如本例所示:

public class PrimeNumberTopology
{
  public static void main(String[] args)
  {
    TopologyBuilder builder = new TopologyBuilder();
    builder.setSpout( "spout", new NumberSpout() );
    builder.setBolt( "prime", new PrimeNumberBolt() )
    .shuffleGrouping("spout");

    Config conf = new Config();
    LocalCluster cluster = new LocalCluster();
    cluster.submitTopology("test", conf, builder.createTopology());
    Utils.sleep(10000);
    cluster.killTopology("test");
    cluster.shutdown();
  }
}

Spark 介绍

Spark 是一个集群计算框架,它是在加州大学伯克利分校的 AMPLab 开发的,并作为一个开源项目贡献给了 Apache。Spark 是一个基于内存的数据处理框架,这使得它的处理速度比 MapReduce 快得多。在 MapReduce 中,中间数据存储在磁盘中,数据访问和传输会使它变慢,而在 Spark 中,它存储在内存中。由于 MapReduce 的局限性和开销,Spark 可以被认为是 MapReduce 的替代方案,但不能作为替代方案。Spark 广泛用于流数据分析、图形分析、快速交互式查询和机器学习。由于其内存特性,它吸引了许多贡献者的注意,并且实际上是 2014 年拥有 200 多名贡献者和 50 多个组织的顶级 Apache 项目之一。Spark 利用多线程而不是多个进程在单个节点上实现并行。

Spark 的主要动机是开发一个更快、更容易使用并可用于分析的处理系统。它的编程遵循更多的有向无环图 ( DAG )模式,其中多步数据流动且复杂,如下图所示:

An introduction to Spark

Spark 的特征

Spark 有许多值得一提的特性和功能,如下所示:

  • 在内存中运行时比 MapReduce 快 100 倍,在磁盘上运行时快 10 倍
  • 可以进行迭代和交互式分析
  • 许多函数和运算符可用于数据分析
  • 轻松设计功能的 DAG 框架
  • 基于内存的中间存储
  • 易于使用和维护
  • 用 Scala 编写,在 JVM 环境下运行;使用 Spark 的应用可以用 Scala、Java、Python、R、Clojure 编写
  • 在 Hadoop 和 Mesos 等环境中运行,或者独立运行,或者在云中运行

Spark 框架

Spark 贡献者利用了核心 Spark 框架,并在 Spark 之上开发了不同的库来增强其功能。这些库可以按照要求插入 Spark:

Spark framework

Spark SQL

Spark SQL 是 Spark 之上的一个 SQL 的包装器。它将 SQL 查询转换成 Spark 作业以产生结果。Spark SQL 可以处理各种数据源,如 Hive 表、Parquet 文件和 JSON 文件。

图形

顾名思义,GraphX 支持使用基于图形的算法。它已经实现了各种各样的基于图形的算法,并且还在增长。一些例子有 PageRank、连通分量、标签传播、SVD++、强连通分量、三角计数等等。

MLib

MLib 是一个可扩展的机器学习库,工作在 Spark 的之上。它的使用和部署要容易得多,其性能可以优化到比 MapReduce 快 100 倍。

Spark 流

Spark streaming 是一个库,使 Spark 能够执行可扩展、容错、高吞吐量的系统,以实时处理流数据。Spark 流很好地集成了许多来源,如驱动HDFSS3Flume卡夫卡****推特等等,其中为如下图所示:

Spark streaming

Spark streaming 可以与 MLib 和 GraphX 集成,在流数据中处理它们的算法或库。Spark streaming 从一个源接收输入数据,并将其分成多个批次。该批被存储为内部数据集(RDD,我们将详细讨论)进行处理,如下图所示:

Spark streaming

Spark 架构

Spark 架构基于 DAG 引擎,其数据模型在弹性分布式数据集 ( RDD )上工作,这是其在性能方面具有大量优势的 USP。在 Spark 中,计算是延迟执行的,这允许 DAG 引擎识别最终结果不需要的步骤或计算,并且根本不执行,从而提高性能。

有向无环图引擎

Spark 有一个先进的 DAG 引擎来管理数据流。Spark 中的一个作业被转换成带有任务阶段的 DAG,然后图形被优化。然后分析所识别的任务,以检查它们是否可以在一个阶段或多个阶段中处理。还分析了任务局部性,以优化流程。

弹性分布式数据集

根据白皮书“弹性分布式数据集,内存集群计算的容错抽象”2012 年 4 月,马泰·扎哈里亚、莫沙拉夫·乔杜里、如来佛·达斯、安库尔·戴夫、贾斯汀·马、墨菲·麦考利、迈克尔·富兰克林、斯科特·申克、扬·斯托伊察。该论文还获得了最佳论文奖和社区荣誉奖。RDD 是只读的分区记录集合。只有通过对(a)稳定存储中的数据或(b)其他 rdd 进行确定性操作,才能创建 rdd。

RDDs 是一个“不可变的弹性分布式记录集合”,可以存储在易失性存储器或持久存储器(HDFS、HBase 等)中,并可以通过一些转换转换成另一个 RDD。RDD 将数据尽可能长时间地存储在内存中。如果数据增长超过阈值,就会溢出到磁盘中。因此,计算变得更快。另一方面,如果某个将数据保存在内存中的节点出现故障,那么这部分计算必须再次处理。为了避免这种情况,检查点会在某些阶段后执行,如下图所示:

Resilient Distributed Dataset

rdd 有两种类型:

  • 并行化集合:通过调用 SparkContext 的并行化方法创建
  • Hadoop 数据集:从 HDFS 文件创建

一个 RDD 可以执行变换或动作。转换可用于某些过滤器或映射函数。操作可以在一些执行后返回值,如减少或计数。

一个 RDD 可以有两种类型的依赖:窄和宽。当 RDD 的一个分区仅被下一个 RDD 的一个分区使用时,就会出现狭窄的依赖关系。当一个 RDD 的一个分区被下一个 RDD 的多个分区使用时,通常会出现广泛的依赖关系。下图显示了两种类型的依赖关系:

Resilient Distributed Dataset

RDDs 的特点如下:

  • 具有弹性和容错性;如果出现任何故障,可以根据存储的数据进行重建
  • 分布的
  • 跨群集节点分区的数据集
  • 不变的
  • 内存密集型
  • 缓存级别可根据环境进行配置

物理架构

Spark 的物理架构组件由 Spark Master 和 Spark Worker 组成,其中作为 Hadoop Spark Worker 位于数据节点上。Spark Master 控制工作流程,它在 Yarn 网之上高度可用。我们可以配置一个备份 Spark 主机,以便于故障转移。Spark Worker 为每个任务启动适当的执行器,如下图所示:

Physical architecture

在部署中,一个分析节点运行 Spark Master,Spark Workers 在每个节点上运行。

Spark 中的操作

RDDs 支持两种类型的操作:

  • 转换
  • 行动

转换

变换操作执行一些功能并创建另一个数据集。转换在惰性模式下处理,并且只处理最终结果中需要的那些转换。如果发现任何转换都是不必要的,那么 Spark 会忽略它,这提高了效率。

转换在的 Spark Apache 文档中可用并提及,如下所示:

|

转换

|

意义

|
| --- | --- |
| map (func) | 返回通过函数func传递源的每个元素形成的新的分布式数据集。 |
| filter (func) | 返回通过选择源中func返回真的那些元素形成的新数据集。 |
| flatMap (func) | 类似来映射,但是每个输入项可以映射到 0 个或更多的输出项(所以func应该返回一个Seq而不是单个项)。 |
| mapPartitions (func) | 类似于映射,但在 RDD 的每个分区(块)上分别运行,因此在类型为 T 的 RDD 上运行时,func 必须是类型Iterator[T] => Iterator[U] |
| mapPartitionsWithSplit (func) | 类似于映射分区,但也为 func 提供了一个代表分割索引的整数值,因此 func 在类型为 T 的 RDD 上运行时必须是类型(Int, Iterator[T]) => Iterator[U]) |
| Sample (withReplacement,fraction, seed) | 使用给定的随机数发生器种子,用或不用替换对一小部分数据进行采样。 |
| Union (otherDataset) | 返回一个包含源数据集中元素和参数的并集的新数据集。 |
| Distinct ([numTasks])) | 返回包含源数据集不同元素的新数据集。 |
| groupByKey ([numTasks]) | 当在(K,V)对的数据集上调用时,返回(K,Seq[V])对的数据集。注意:默认情况下,这仅使用八个并行任务来进行分组。您可以通过可选的numTasks参数来设置不同数量的任务。 |
| reduceByKey (func, [numTasks]) | 当在(K,V)对的数据集上调用时,返回(K,V)对的数据集,其中使用给定的 reduce 函数聚合每个键的值。像在 groupByKey 中一样,reduce 任务的数量可以通过可选的第二个参数来配置。 |
| sortByKey ([ascending], [numTasks]) | 当在(K,V)对的数据集上调用时,其中 K 实现 Ordered,返回(K,V)对的数据集,按照布尔升序参数中指定的升序或降序按键排序。 |
| Join (otherDataset, [numTasks]) | 当在类型为(K,V)和(K,W)的数据集上调用时,返回一个(K,(V,W))对的数据集,其中包含每个键的所有元素对。 |
| Cogroup (otherDataset, [numTasks]) | 当在(K,V)和(K,W)类型的数据集上调用时,返回(K, Seq[V], Seq[W])元组的数据集。这个操作也叫组跟。 |
| Cartesian (otherDataset) | 当在类型为 T 和 U 的数据集上调用时,返回(T,U)对(所有元素对)的数据集。 |

行动

动作操作产生并返回一个结果。一个操作的结果实际上被写入一个外部存储系统。 Spark Apache 文档中可用和提及的操作,在https://Spark . Apache . org/docs/latest/programming-guide . html # actions中提及的是如下:

|

行动

|

意义

|
| --- | --- |
| Reduce (func) | 使用函数func聚合数据集的元素(该函数接受两个参数并返回一个参数)。该函数应该是可交换的和关联的,以便可以并行地正确计算。 |
| Collect () | 在驱动程序中将数据集的所有元素作为数组返回。这通常在返回足够小的数据子集的过滤器或其他操作之后有用。 |
| Count () | 返回数据集中的元素数量。 |
| First () | 返回数据集的第一个元素(类似于 take(1))。 |
| Take (n) | 返回带有数据集第一个 n 个元素的数组。请注意,这当前没有并行执行。相反,驱动程序计算所有的元素。 |
| takeSample (withReplacement,num, seed) | 使用给定的随机数生成器种子,返回一个带有数据集 num 元素随机样本的数组,有或没有替换。 |
| saveAsTextFile (path) | 将数据集的元素作为文本文件(或文本文件集)写入本地文件系统、HDFS 或任何其他 Hadoop 支持的文件系统中的给定目录。Spark 会在每个元素上调用toString将其转换为文件中的一行文本。 |
| saveAsSequenceFile (path) | 将数据集的元素作为 Hadoop 序列写入本地文件系统、HDFS 或任何其他 Hadoop 支持的文件系统中的给定路径。这仅在实现 Hadoop 的可写接口或隐式转换为可写的键值对的 RDD 上可用(Spark 包括像 Int、Double、String 等基本类型的转换)。 |
| countByKey () | 只有在类型(K,V)的 rdd 上可用。返回包含每个键的计数的(K,Int)对的映射。 |
| Foreach (func) | 对数据集的每个元素运行函数func。这通常是为了副作用,如更新累加器变量(见下文)或与外部存储系统交互。 |

Spark 示例

为了简单起见,我们以《星火》中的字数为例。

在 Scala 中:

val file = spark.textFile("hdfs://...")
val counts = file.flatMap(line => line.split(" "))
  .map(word => (word, 1))
  .reduceByKey(_ + _)
counts.saveAsTextFile("hdfs://...")

在 Java 中:

JavaRDD<String> file = spark.textFile("hdfs://...");JavaRDD<String> words = file.flatMap(new FlatMapFunction<String, String>() {
  public Iterable<String> call(String s) {
return Arrays.asList(s.split(" ")); }
});

JavaPairRDD<String, Integer> pairs = words.mapToPair(new PairFunction<String, String, Integer>() {
    public Tuple2<String, Integer> call(String s) {
return new Tuple2<String, Integer>(s, 1); }});
JavaPairRDD<String, Integer> counts = pairs.reduceByKey(new Function2<Integer, Integer>() {
  public Integer call(Integer a, Integer b) {
return a + b; }});
counts.saveAsTextFile("hdfs://...");

总结

大数据中的许多系统都需要流式传输和实时分析。Hadoop 很好地处理了批处理,Storm 和 Spark 等框架的集成提升了它们的流和实时能力。

我们讨论了 Storm 是一个开源、快速、流处理、可扩展、容错和可靠的系统,易于使用和部署。Storm 的物理架构包括光轮、监督者、工作者和动物园管理员流程。Storm 的数据架构包括喷口、螺栓和基于拓扑的数据流系统。

Spark 是一个非常流行的框架,它提供了内存中的数据处理能力,并且比 MapReduce 框架快得多。Spark 框架有一些库,如 Spark SQL、GraphX、MLib、Spark Streaming 和其他库来处理专门的数据和需求。Spark 架构基于 RDDs 和 DAG 引擎,提供内存数据处理能力,并根据数据流高效地优化处理。Spark RDD 可以执行许多转换和行动。

最后,我们来到了最后一章,介绍了 Hadoop 生态系统中的不同工具和实用程序集。我希望这本书对你有用,并让你快速了解组件和基本细节,以及如何使用它们。

posted @ 2025-10-01 11:29  绝不原创的飞龙  阅读(16)  评论(0)    收藏  举报