前面重点介绍了Hadoop及其体系结构和计算模型MapReduce,现在开始介绍Hadoop的数据管理,主要包括Hadoop的分布式文件系统HDFS、分布式数据库HBase和数据仓库工具Hive的数据管理。
1 HDFS的数据管理
HDFS是分布式计算的存储基石,Hadoop分布式文件系统和其他分布式文件系统有很多类似的特质:
1.对于整个集群有单一的命名空间;
2.具有数据一致性。适合一次写入多次读取的模型,客户端在文件没有被成功创建之前是无法看到文件存在的;
3.文件会被分割成多个文件块,每个文件块被分配存储到数据节点上,而且会根据配置由复制文件块来保证数据的安全性。
从前面的介绍和图可以看出,HDFS通过三个重要的角色来进行文件系统的管理:NameNode、DataNode和Client
NameNode可以看做是分布式文件系统中的管理者,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等。NameNode会将文件系统的Metadata存储在内存中,这些信息主要包括文件信息、每一个文件对应的文件块的信息和每一个文件块在DataNode中的信息等。DataNode是文件存储的基本单元,它将文件块(Block)存储在本地文件系统中,保存了所有Block的Metadata,同时周期性地将所有存在的Block信息发送给NameNode。Client就是需要获取分布式文件系统文件的应用程序。以下通过三个具体的操作来说明HDFS对数据的管理。
(一) 文件写入
1) Client向NameNode发起文件写入的请求。
2) NameNode根据文件大小和文件块的配置情况,返回给Client它所管理的DataNode的信息。
3) Client将文件划分为多个Block,根据DataNode的地址信息,按顺序将其写入每一个DataNode块中。
(二) 文件读取
1) Client向NameNode发起读取文件的请求。
2) NameNode返回文件存储的DataNode信息。
3) Client读取文件信息。
(三) 文件块(Block)复制
1) NameNode发现部分文件的Block不符合最小复制数这一要求或部分DataNode失效。
2) 通知DataNode相互复制Block。
3) DataNode开始直接相互复制。
HDFS作为分布式文件系统在数据管理方面还有几个值得借鉴的功能:
1.文件块(Block)的放置:一个Block会有三份备份,一份放在NameNode指定的DataNode上,另一份放在与指定的DataNode不在同一台机器上的DataNode上,最后一份放在与指定的DataNode在同一Rack上的DataNode上。备份的目的是为了数据安全,采用这种配置方式主要是考虑同一Rack失败的情况,以及不同Rack之间的数据拷贝会带来的性能问题。
2.心跳检测:用心跳检测DataNode的健康状况,如果发现问题就采取数据备份的方式来保证数据的安全性。
3.数据复制(场景为DataNode失败、需要平衡DataNode的存储利用率和平衡DataNode数据交互压力等情况):使用Hadoop时可以用HDFS的balancer命令配置Threshold来平衡每一个DataNode的磁盘利用率。假设设置了Threshold为10%,那么执行balancer命令的时候,首先会统计所有DataNode的磁盘利用率的平均值,然后判断如果某一个DataNode的磁盘利用率超过这个均值,那么将会把这个DataNode的block转移到磁盘利用率低的DataNode上,这对于新节点的加入来说十分有用。
4.数据校验:采用CRC32做数据校验。在写入文件Block的时候,除了写入数据外还会写入校验信息,在读取的时候则需要校验后再读入。
5.单个NameNode:如果失败,任务处理信息将会记录在本地文件系统和远端的文件系统中。
6.数据管道性的写入:当客户端要写入文件到DataNode上时,客户端首先会读取一个Block,然后写到第一个DataNode上,接着由第一个DataNode将其传递到备份的DataNode上,直到所有需要写入这个Block的DataNode都成功写入后,客户端才会开始写下一个
Block。
7.安全模式:分布式文件系统启动的时候会有安全模式(系统运行期间也可以通过命令进入安全模式),当分布式文件系统处于安全模式时,文件系统中的内容不允许修改也不允许删除,直到安全模式结束。安全模式主要是为了在系统启动的时候检查各个DataNode上的数据块的有效性,同时根据策略进行必要的复制或删除部分数据块。在实际操作过程中,若在系统启动时修改和删除文件会出现安全模式不允许修改的错误提示,只需要等待一会儿即可。
2 HBase的数据管理
HBase是一个类似Bigtable的分布式数据库,它的大部分特性和Bigtable一样,是一个稀疏的、长期存储的(存在硬盘上)、多维度的排序映射表。这张表的索引是行关键字、列关键字和时间戳。每个值是一个不解释的字符数组,数据都是字符串,没有类型。用户在表格中存储数据,每一行都有一个可排序的主键和任意多的列。由于是稀疏存储的,所以同一张表里面的每一行数据都可以有截然不同的列。列名字的格式是“<family>:<label>”,它是由字符串组成的,每一张表有一个family集合,这个集合是固定不变的,相当于表的结构,只能通过改变表结构来改变表的family集合,但是label值相对于每一行来说都是可以改变的。
HBase把同一个family中的数据存储在同一个目录下,而HBase的写操作是锁行的,每一行都是一个原子元素,都可以加锁。所有数据库的更新都有一个时间戳标记,每次更新都会生成一个新的版本,而HBase会保留一定数量的版本,这个值是可以设定的。客户端可以选择获取距离某个时间点最近的版本,或者一次获取所有版本。
以上从微观上介绍了HBase的一些数据管理措施。那么HBase作为分布式数据库在整体上从集群出发又是如何管理数据的呢?
HBase在分布式集群上主要依靠由HRegion、HMaster、HClient组成的体系结构从整体上管理数据。
HBase体系结构的三大重要组成部分是:
1.HBaseMaster:HBase主服务器,与Bigtable的主服务器类似。
2.HRegionServer:HBase域服务器,与Bigtable的Tablet服务器类似。
3.HBaseClient:HBase客户端是由org.apache.hadoop.HBase.client.HTable定义的。
下面将对这三个组件进行详细的介绍。
(一) HBaseMaster
一个HBase只部署一台主服务器,它通过领导选举算法(Leader Election
Algorithm)确保只有唯一的主服务器是活跃的,ZooKeeper保存主服务器的服务器地址信息。如果主服务器瘫痪,可以通过领导选举算法从备用服务器中选择新的主服务器。
主服务器初始化集群。当主服务器第一次启动时,会试图从HDFS获取根或根域目录,若获取失败则创建根或根域目录,以及第一个元域目录。下次启动时,主服务器就可以获取集群和集群中所有域的信息了。
主服务器负责域的分配工作。首先,主服务器会分配根域,并存储指向根域所在域服务器地址的指针。其次,主服务器遍历根域查询元域,并分配元域到域服务器中。每个元域中包含了所有的用户域,用户域中存储了多个用户表。如果所有的元域分配完毕,主服务器将会分配用户域到相应的域服务器,以保持域服务器间的负载平衡。
主服务器时刻监视着域服务器的运行状态。一旦主服务器检测到某一域服务器不可达时,它将分离出域服务器上的每个域的预写日志(write-ahead
log)文件。之后,主服务器会将域重新分配到其他域服务器上,并运行之。如果主服务器发现一个域服务器超负荷运行,则会取消或关闭该域服务器的一些域,并将这些域分配到其他低负载的域服务器上。
主服务器还负责表格的管理。例如,调整表格的在线/离线状态和改变表格的模式(增加或删除列族)等。此外,客户端还可以请求本地域直接从域服务器上读取数据。
在Bigtable中,当主服务器和域服务器的连接断开时,域服务器仍然可以继续服务,因为Bigtable提供了一种额外的锁管理机制,这种机制中的锁管理器(Chubby)保证了域服务器服务的可用性。而在HBase中,由于没有提供锁管理机制,当主服务器崩溃时,整个集群系统都要重新启动,因为主服务器是所有域服务器的管理中心。
下面介绍元表和根表的概念:
元表(Meta Table)包含了所有用户域的基本信息,域信息包括起始关键字、结束关键字、域是否在线、域所在的域服务器地址等。元表会随着用户域的增长而增长。
根表(Root Table)被定义为存储单一域的信息,并指向元表中的所有域。与元表一样,根表也包含每个元域的信息和元域所在的域服务器地址。
根表和元表中的每行大约为1KB。域默认大小为256MB,根域可以映射2.6×105个元域。同样,元域可以映射相应数量的用户域。因此,根域可以映射6.9×1010个用户域,大约可以存储1.9×1019字节的数据。
(二) HRegionServer
HBase域服务器主要有服务于主服务器分配的域、处理客户端的读写请求、缓冲区回写、压缩和分割域等功能。
每个域只能由一台域服务器来服务。当它开始服务于某域时,它会从HDFS文件系统中读取该域的日志和所有存储文件。同时它还会管理操作HDFS文件的持久性存储工作。
客户端通过与主服务器通信获取域和域所在域服务器的列表信息后,就可以直接向域服务器发送域读写请求了。域服务器收到写请求时,首先将写请求信息写入一个预写日志文件中,该文件取名为HLog。同一个域的所有写请求都被记录在同一个HLog文件中。一旦写请求被记录在HLog中之后,它将被缓存在存储缓存区(MemCache)中。每个HStore对应一个存储缓存区。对于读请求,域服务器先要检测请求数据在存储缓存区中是否被命中,如果没有命中,域服务器再去查找相关的映射文件。
当存储缓存区的大小达到一定阈值后,需要将存储缓存区中的数据回写到磁盘上,形成映射文件,并在HLog日志文件中标记。因此当再次执行时,可以跳跃到最后一次回写之前的操作上。回写也可能因域服务器存储器压力而被触发。
当映射文件的数量达到一定阈值时,域服务器会将最近常写入的映射文件进行轻度的合并压缩。此外,域服务器还会周期性地对所有的映射文件进行压缩,使其成为单一的映射文件。之所以周期性地压缩所有的映射文件,是因为最早的映射文件通常都比较大,而最近的映射文件则要小很多,压缩要消耗很多的时间,具体消耗的时间主要取决于读取、合并和写出最大映射文件所需要的I/O操作次数。压缩和处理读写请求是同时进行的。在一个新的映射文件移入之前,读写操作将被挂起,直到映射文件被加入HStore的活跃映射文件列表中,且已合并的旧映射文件被删除后,才会释放读写操作。
当HStore中映射文件的大小达到一定的阈值时(目前默认的阈值为256MB),域服务器就要对域进行分割了。域被均分为两个子域,分割操作执行速度很快,因为子域是直接从父域中读取数据的。之后,父域处于离线状态。域服务器在元域中记录新的子域,并通知主服务器可以将子域分配给其他域服务器。如果域分割消息在网络传输中丢失,主服务器可以在周期性扫描元域中未被分配的域信息时发现分割操作。一旦父域被关闭,所有对父域的读写操作将被挂起。客户端则会探测域的分割信息,当新的子域在线时,客户端再发出读写请求。当子域触发压缩操作时,父域的数据将复制到子域中。父域将会在两个子域都完成压缩操作时被回收。
(三) HBaseClient
HBase客户端负责查找用户域所在的域服务器地址。HBase客户端会与HBase主机交换消息以查找根域的位置,这是两者之间唯一的交流。
定位根域后,客户端连接根域所在的域服务器,并扫描根域获取元域信息,元域包含所需用户域的域服务器地址。客户端再连接元域所在的域服务器,扫描元域来获取所需用户域所在的域服务器地址。定位用户域后,客户端连接用户域所在的域服务器并发出读写请求。用户域的地址将在客户端中被缓存,后续的请求无须重复上述过程。
不管是由于主服务器为了负载均衡而重新分配域还是域服务器崩溃,客户端都会重新扫描元表来定位新的用户域地址。如果元域被重新分配,客户端将扫描根域来定位新的元域地址。如果根域也被重新分配,客户端将会连接主机定位新的根域地址,并通过重复上述过程来定位用户域地址。
综上所述,在HBase的体系结构中,HBase主要由主服务器、域服务器和客户端三部分组成。主服务器作为HBase的中心,管理着整个集群中的所有域,监控每个域服务器的运行情况等;域服务器接收来自服务器的分配域,处理客户端的域读写请求并回写映射文件等;客户端主要用来查找用户域所在的域服务器地址信息。
3 Hive的数据管理
Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,用来进行数据提取、转化、加载,这是一种可以存储、查询和分析存储在
Hadoop 中的大规模数据的机制。Hive定义了简单的类 SQL 查询语言,称为 QL,它允许熟悉 SQL
的用户查询数据。作为一个数据仓库,Hive的数据管理按照使用层次可以从元数据存储、数据存储和数据交换三个方面来介绍。
(一) 元数据存储
Hive 将元数据存储在RDBMS 中,有三种模式可以连接到数据库:
Single User Mode:此模式连接到一个 In-memory
的数据库 Derby,一般用于 Unit Test。
Multi User Mode:通过网络连接到一个数据库中,这是最常用的模式。
Remote Server Mode:用于非 Java 客户端访问元数据库,在服务器端启动一个
MetaStoreServer,客户端则利用 Thrift 协议通过MetaStoreServer来访问元数据库。
(二) 数据存储
首先,Hive 没有专门的数据存储格式,也没有为数据建立索引,用户可以非常自由地组织
Hive 中的表,只需要在创建表的时候告诉 Hive 数据中的列分隔符和行分隔符,它就可以解析数据了。
其次,Hive 中所有的数据都存储在 HDFS 中,Hive 中包含4种数据模型:Table、External
Table、Partition、Bucket。
Hive 中的 Table 和数据库中的 Table 在概念上是类似的,每一个Table
在 Hive 中都有一个相应的目录来存储数据。例如,一个表 pvs,它在 HDFS 中的路径为:/wh/pvs,其中,wh
是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir}
指定的数据仓库的目录,所有的 Table 数据(不包括External Table)都保存在这个目录中。
Partition 对应于数据库中Partition 列的密集索引,但是
Hive 中 Partition 的组织方式与数据库中的很不相同。在 Hive 中,表中的一个 Partition
对应于表下的一个目录,所有的Partition 数据都存储在对应的目录中。例如:pvs 表中包含 ds
和 city 两个 Partition,则对应于 ds = 20090801, city = US 的
HDFS 子目录为:/wh/pvs/ds=20090801/city=US;对应于 ds = 20090801,
city = CA 的 HDFS 子目录为:/wh/pvs/ds=20090801/city=CA。
Buckets 对指定列计算 hash,根据 hash 值切分数据,目的是为了便于并行,每一个
Buckets对应一个文件。将user 列分散至 32 个Bucket上,首先对 user 列的值计算
hash,比如,对应 hash 值为 0 的 HDFS 目录为:/wh/pvs/ds=20090801/city=US/part-00000;对应hash
值为 20 的 HDFS 目录为:/wh/pvs/ds=20090801/city=US/part-00020。
External Table 指向已经在 HDFS 中存在的数据,可以创建
Partition。它和 Table 在元数据的组织结构上是相同的,而在实际数据的存储上则有较大的差异。
在Table 的创建过程和数据加载过程(这两个过程可以在同一个语句中完成)中,实际数据会被移动到数据仓库目录中。之后对数据的访问将会直接在数据仓库的目录中完成。删除表时,表中的数据和元数据将会被同时删除。
External Table 只有一个过程,因为加载数据和创建表是同时完成的。实际数据是存储在
Location 后面指定的 HDFS 路径中的,它并不会移动到数据仓库目录中。
(三) 数据交换
数据交换主要分为以下几个部分(如图所示):
1.用户接口:包括客户端、Web界面和数据库接口。
2.元数据存储:通常是存储在关系数据库中的,如MySQL、Derby等。
3.解释器、编译器、优化器、执行器。
4.Hadoop:用 HDFS进行存储,利用 MapReduce 进行计算。
用户接口主要有三个:客户端、数据库接口和Web界面,其中最常用的是客户端。Client
是 Hive 的客户端,当启动 Client 模式时,用户会想要连接Hive Server,这时需要指出
Hive Server 所在的节点,并且在该节点启动Hive Server。Web界面是通过浏览器访问Hive的。
Hive 将元数据存储在数据库中,如MySQL、Derby中。Hive
中的元数据包括表的名字、表的列和分区及其属性、表的属性(是否为外部表等)、表数据所在的目录等。
解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化到查询计划的生成。生成的查询计划存储在
HDFS 中,并在随后由MapReduce调用执行。
Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce
完成(包含 * 的查询不会生成 MapRedcue 任务,比如select * from tbl)。
以上从Hadoop的分布式文件系统HDFS、分布式数据库HBase和数据仓库工具Hive入手介绍了Hadoop的数据管理,它们都通过自己的数据定义、体系结构实现了数据从宏观到微观的立体化管理,完成了Hadoop平台上大规模的数据存储和任务处理。
|