Hadoop 基础知识(二)
五、存储组件——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 使用以下组件,我们将在后面讨论:
- 主服务器
- 区域服务器
- 地区
- 动物园管理员
让我们看看下图:
主服务器
MasterServer 是管理员,在某个时间点,HBase 中只能有一个 Master。它负责以下工作:
- 集群监控和管理
- 将区域分配给区域服务器
- 通过重新分配区域实现故障转移和负载平衡
区域服务器
区域服务器由主服务器识别,主服务器将区域分配给区域服务器。区域服务器在数据节点上运行,并执行以下活动:
- 与主管协调管理区域
- 区域中的数据拆分
- 协调和服务读/写
除了管理区域之外,区域服务器还具有以下组件或数据结构:
墙面
用于写操作的数据首先保存在 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 表:
让我们详细了解一下这些组件:
-
表: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 对于单个行级别是强一致的,但在不同级别之间不是。
更多细节可以查看 hbase.apache.org/acid-semant…](hbase.apache.org/acid-semant…
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 的唯一方法是删除它,然后再次重新插入。行按行按排序,即如果行键为
1、32、001、225、060、45,则数字的排序顺序为001、060、1、225、32、45。表文件通过一系列行键分布在区域中。通常顺序键和随机键的组合在 HBase 中表现更好。 - 柱族:柱族提供了很好的可扩展性和灵活性,但是要精心设计。在 HBase 的当前体系结构中,建议不要超过两个列系列。
- 反规格化数据:由于 HBase 本身不提供 Joins,数据应该反规格化。数据通常是稀疏的,并在许多列中重复,HBase 可以充分利用这一点。
写流水线
在 HBase 中写入管道是通过以下步骤进行的:
- 客户端请求将数据写入 HTable,请求到达区域服务器。
- 区域服务器首先在 WAL 中写入数据。
- 区域服务器识别将存储数据的区域,数据将保存在该区域的内存存储中。
- MemStore 将数据保存在内存中,不保存它。当 MemStore 中的阈值达到时,则数据在该区域中被刷新为 HFile。
读取管道
在中读取 HBase 按以下步骤进行:
- 客户端发送读取请求。请求由区域服务器接收,该服务器识别存在文件的所有区域。
- 首先,查询区域的记忆库;如果数据存在,则请求得到服务。
- 如果数据不存在,则查询块缓存以检查它是否有数据;如果是,则服务该请求。
- 如果数据不在块缓存中,则从区域中提取数据并提供服务。现在数据被缓存在内存存储和块缓存中..
压实
在操作系统中,区域中的记忆库为一个列族创建许多文件。如此大量的文件将需要更多的时间来读取,因此会影响读取性能。为了提高性能,HBase 执行压缩来合并文件,以减少文件数量并保持数据的可管理性。压缩过程通过运行一种称为压缩策略的算法来识别要合并的存储文件。有两种类型的压缩:次要压缩和主要压缩。
紧缩政策
压缩策略是可用于选择要合并的存储文件的算法。有两种策略是可能的,可用的是ExploringCompactionPolicy和RatioBasedCompactionPolicy。要设置策略算法,我们必须设置hbase-site.xml的属性hbase.hstore.defaultengine.compactionpolicy.class的值。在 HBase 0.96 之前,RatioBasedCompactionPolicy 作为默认策略可用,现在仍然可用。ExploringCompactionPolicy 是 HBase 0.96 和更高版本的默认算法。简而言之,这些算法的不同之处在于,基于比率的公司操作策略选择第一个符合标准的集合,而探索公司操作策略选择工作量最少且更适合大容量数据加载的最佳存储文件集合。
轻微压实
次要压缩将相邻的和较小的大小的存储文件合并或重写为一个存储文件。较小的压缩会更快,因为它会创建一个新的存储文件,并且为压缩选择的存储文件是不可变的。请注意,小压缩不处理已删除和过期的版本。当存储文件的数量达到阈值时,就会发生这种情况;非常具体地说,hbase-site.xml中hbase.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 HexStringSplit和10数量的区域,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 实现了一些有用的协处理器,并对协处理器的扩展和定制实现开放。协处理器可以基于两种策略来设计——观测器和端点,如下所示:
- 观察者:顾名思义,观察者协处理器可以设计成作为回调或者在某些事件的情况下工作。观察者可以被认为是关系数据库管理系统中的触发器,可以在区域、主或沃尔级别操作。观察者分别在事件之前和之后有方法覆盖的
PreXXX和PostXXX约定。以下是根据不同级别的观察者类型:- 区域观察者:区域观察者处理区域级数据。这些可用于创建辅助索引,以帮助检索。对于每个可点击区域,我们可以有一个区域观察者。RegionObserver 为数据操作事件提供了钩子,如
Get、Put、Delete、Scan等。常见的例子包括Get操作的preGet和postGet以及prePut和postPut操作的Put。 - 主观察器:主观察器在主级别运行,处理 DDL 类型的操作,如创建、删除和修改表。使用 MasterObserver 时应格外小心。
- 沃尔观察员:这为沃尔处理提供了挂钩。它只有两种方法;
preWALWrite()和postWALWrite()。
- 区域观察者:区域观察者处理区域级数据。这些可用于创建辅助索引,以帮助检索。对于每个可点击区域,我们可以有一个区域观察者。RegionObserver 为数据操作事件提供了钩子,如
- 端点:端点是可以通过客户端接口直接调用来调用的操作。如果观察者可以被认为是触发器,那么端点可以被认为是关系数据库管理系统的存储过程。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 的连接器,如下图所示:
Sqoop 1 体系结构
Sqoop1 架构是客户端工具,与 Hadoop 集群紧密耦合。客户端启动的一个 Sqoop 命令根据连接器和驱动程序接口获取表、列和数据类型的元数据。导入或导出被转换为仅映射作业程序,以便在数据库和 Hadoop 之间并行加载数据。客户端应该有适当的连接器和驱动程序来执行这个过程。
Sqoop 架构如下图所示:
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 导入分两步执行:
- 收集元数据
- 仅提交地图作业
下图解释了导入到 Sqoop 的过程:
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 的过程:
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 拓扑如下图所示:
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 与各种源类型(如 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 用户指南页面flume.apache.org/FlumeUserGu…。
示例:对于创建应该获取日志文件更新数据的代理源,强制参数和值应该是:
- 型: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 配置:
配置 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 来协调主从。它由四个部分组成:
- 光轮:掌握流程,在集群间分配处理
- 主管:管理工人节点
- 工作人员:执行光轮分配的任务
- 动物园管理员:光轮和监工之间的坐标
工人通过动物园管理员向主管和光轮发送心跳。如果工作人员或主管无法响应,则邻避将工作重新分配给集群中的另一个节点,如下图所示:
Storm 的数据架构
Storm 数据架构有以下术语:
- 喷口:产生流或数据源
- Bolt :摄取壶嘴元组,然后对其进行处理,产生输出流;它可以用来过滤、聚合或连接数据,或者与数据库对话
- 拓扑结构:喷口和螺栓之间的网络图
下图解释了上述要点:
《Storm》中的数据级抽象是:
- 元组:Storm 数据的基本单位——一个命名的值列表
- 流:一个无界的元组序列
下图显示了产生流的喷口和处理元组或流以产生不同流的螺栓:
Storm 拓扑
流可以通过使用流分组在螺栓之间进行划分,这允许流朝着螺栓行进。Storm 提供了以下内置流分组,您可以通过实现接口来实现自定义流分组:
- 混洗分组:每个螺栓被统一配置以获得几乎相等数量的元组
- 字段分组:对特定字段进行分组可以将相同字段值和不同值元组的元组合并到不同的螺栓上
- 所有分组:每个元组可以发送到所有螺栓,但是会增加开销
- 全局分组:所有的元组都归到一个螺栓上
- 直接分组:生产者可以决定将哪些元组发送到哪个螺栓
Yarn 上的 Storm
对 Yarn 的 Storm 集成是在雅虎完成的,并作为开源发布。Storm 可以与 Yarn 集成,在与 Lambda 架构相同的集群上提供批处理和实时分析。Storm on YARN 将 Storm 的事件处理框架与 Hadoop 相结合,以提供低延迟处理。Storm 资源可以由 Yarn 管理,以提供 Hadoop 上 Storm 流处理的所有好处。“Yarn 上 Storm”在资源利用方面提供了高可用性、优化和弹性。
拓扑配置示例
Storm 拓扑可以由TopologyBuilder类通过创建喷口和螺栓,然后提交拓扑来配置。
喷口
在 Storm 中可以使用一些实现的喷口,例如 BaseRichSpout 、clojuresport、 DRPCSpout 、 FeederSpout 、fixed duplespout、 MasterBatchCoordinator 、 RichShellSpout 、rich bulotbatchtriggerer、 ShellSpout
我们可以通过扩展上述任何一个类或者实现 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 中可用,如 BaseBasicBolt 、 BatchProcessWord 、batchrepata、 IdentityBolt 、 PrepareBatchBolt 、 PrepareRequest 、 TestConfBolt 、testwordpcounter、tridentbluotcooler。
我们可以通过扩展上述任何一个类或者实现 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 )模式,其中多步数据流动且复杂,如下图所示:
Spark 的特征
Spark 有许多值得一提的特性和功能,如下所示:
- 在内存中运行时比 MapReduce 快 100 倍,在磁盘上运行时快 10 倍
- 可以进行迭代和交互式分析
- 许多函数和运算符可用于数据分析
- 轻松设计功能的 DAG 框架
- 基于内存的中间存储
- 易于使用和维护
- 用 Scala 编写,在 JVM 环境下运行;使用 Spark 的应用可以用 Scala、Java、Python、R、Clojure 编写
- 在 Hadoop 和 Mesos 等环境中运行,或者独立运行,或者在云中运行
Spark 框架
Spark 贡献者利用了核心 Spark 框架,并在 Spark 之上开发了不同的库来增强其功能。这些库可以按照要求插入 Spark:
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 可以与 MLib 和 GraphX 集成,在流数据中处理它们的算法或库。Spark streaming 从一个源接收输入数据,并将其分成多个批次。该批被存储为内部数据集(RDD,我们将详细讨论)进行处理,如下图所示:
Spark 架构
Spark 架构基于 DAG 引擎,其数据模型在弹性分布式数据集 ( RDD )上工作,这是其在性能方面具有大量优势的 USP。在 Spark 中,计算是延迟执行的,这允许 DAG 引擎识别最终结果不需要的步骤或计算,并且根本不执行,从而提高性能。
有向无环图引擎
Spark 有一个先进的 DAG 引擎来管理数据流。Spark 中的一个作业被转换成带有任务阶段的 DAG,然后图形被优化。然后分析所识别的任务,以检查它们是否可以在一个阶段或多个阶段中处理。还分析了任务局部性,以优化流程。
弹性分布式数据集
根据白皮书“弹性分布式数据集,内存集群计算的容错抽象”2012 年 4 月,马泰·扎哈里亚、莫沙拉夫·乔杜里、如来佛·达斯、安库尔·戴夫、贾斯汀·马、墨菲·麦考利、迈克尔·富兰克林、斯科特·申克、扬·斯托伊察。该论文还获得了最佳论文奖和社区荣誉奖。RDD 是只读的分区记录集合。只有通过对(a)稳定存储中的数据或(b)其他 rdd 进行确定性操作,才能创建 rdd。
RDDs 是一个“不可变的弹性分布式记录集合”,可以存储在易失性存储器或持久存储器(HDFS、HBase 等)中,并可以通过一些转换转换成另一个 RDD。RDD 将数据尽可能长时间地存储在内存中。如果数据增长超过阈值,就会溢出到磁盘中。因此,计算变得更快。另一方面,如果某个将数据保存在内存中的节点出现故障,那么这部分计算必须再次处理。为了避免这种情况,检查点会在某些阶段后执行,如下图所示:
rdd 有两种类型:
- 并行化集合:通过调用 SparkContext 的并行化方法创建
- Hadoop 数据集:从 HDFS 文件创建
一个 RDD 可以执行变换或动作。转换可用于某些过滤器或映射函数。操作可以在一些执行后返回值,如减少或计数。
一个 RDD 可以有两种类型的依赖:窄和宽。当 RDD 的一个分区仅被下一个 RDD 的一个分区使用时,就会出现狭窄的依赖关系。当一个 RDD 的一个分区被下一个 RDD 的多个分区使用时,通常会出现广泛的依赖关系。下图显示了两种类型的依赖关系:
RDDs 的特点如下:
- 具有弹性和容错性;如果出现任何故障,可以根据存储的数据进行重建
- 分布的
- 跨群集节点分区的数据集
- 不变的
- 内存密集型
- 缓存级别可根据环境进行配置
物理架构
Spark 的物理架构组件由 Spark Master 和 Spark Worker 组成,其中作为 Hadoop Spark Worker 位于数据节点上。Spark Master 控制工作流程,它在 Yarn 网之上高度可用。我们可以配置一个备份 Spark 主机,以便于故障转移。Spark Worker 为每个任务启动适当的执行器,如下图所示:
在部署中,一个分析节点运行 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 生态系统中的不同工具和实用程序集。我希望这本书对你有用,并让你快速了解组件和基本细节,以及如何使用它们。