驱蚊器喵的翻译平台

Can you hear the gravity?

  1. 1. 从 Elastic MapReduce 开始!
  2. 2. 将数据放入我们的集群
  3. 3. 从文件中获取一个块!
  4. 4. 读取文件块

原文地址:https://jvns.ca/blog/2014/05/15/diving-into-hdfs/
原文标题:Diving into HDFS
原文作者:Julia Evans
原文写于:2014/05/15

译者:驱蚊器喵#ΦωΦ
翻译水平有限,有不通顺的语句,请见谅。


昨天我想开始学习 HDFS (Hadoop 分布式文件系统,Hadoop Distributed File System) 的内部工作方式。我知道的有:

  • 它是分布式的,所以一个文件可能被存储在许多不同的机器上
  • 有一个 namenode,记录了所有文件的存储位置
  • 有一些数据节点(data nodes),存储实际的文件数据

但我不太确定如何开始!我知道如何从命令行中浏览文件系统(hadoop fs -ls /,以及其他的一些命令),但不知道如何弄清楚它的内部运作。

Colin Marc 给我推荐了伟大的库,叫做 snakebite,是一个 Python HDFS 客户端。特别是他给我指出了从 HDFS 中读取文件内容的那部分代码。我们要把它拆开,看看它到底是做什么的。

从 Elastic MapReduce 开始!

我不想手工建立一个 Hadoop 集群,而且我有一些免费得到的 AWS 余额,所以我建立了一个小型的 Amazon Elastic MapReduce 集群。我与 Pablo TorresSasha Laundy 一起,我们花了一上午的时间来折腾,试图找出协议版本以及为什么 Snakebite 不能和它兼容。

最终,我们选择了 AMI 版本 “3.0.4(hadoop 2.2.0)”。这是 CDH5 和 Hadoop 协议版本 9。Hadooop 的版本很容易混淆。我们安装了这个版本和 Snakebite 2.4.1 版本,这快要成功了。

重要的事情:

  • 我们需要查看/home/hadoop/conf/core-site.xml以找到 namenode 的 IP 和端口(在 fs.default.name配置中)。
  • 我们需要编辑 snakebite/config.py,将 “fs.default.name” 改为 “fs.defaultFS”。为什么要这么改,我们也不知道,反正最终就是有用。

这样做了后,我们就可以成功地运行snakebite ls /了! 可以继续拆卸 HDFS 了!

将数据放入我们的集群

我从亚马逊的一个公共数据集中复制了一些维基百科的数据,像这样。

1
hadoop distcp s3://datasets.elasticmapreduce/wikipediaxml/part-116.xml /wikipedia

这将在 HDFS 中创建一个名为 /wikipedia 的文件。你可以在 https://s3.amazonaws.com/datasets.elasticmapreduce/ 看到更多可以从亚马逊复制到 HDFS 的数据集。

从文件中获取一个块!

现在我们有了一个 Hadoop 集群,HDFS 中的一些数据,以及一个可以查看这些数据的工具(snakebite),我们可以真正开始了!

HDFS 中的文件被分割成块。当从 HDFS 中获取一个文件时,我们需要做的第一件事就是询问 namenode ,文件的块存储在哪里。

在阅读了大量的 snakebite 代码后,我写了一个小的 Python 函数来做这件事,叫做find_blocks。你可以在我做的一个叫 hdfs_fun.py 的小 Python 模块中看到它。要让它工作,你需要一个 Hadoop 集群和 snakebite。

1
2
3
4
>>> cl = hdfs_fun.create_client()
>>> hdfs_fun.find_blocks(cl, '/wikipedia')
[snakebite.protobuf.hdfs_pb2.LocatedBlockProto at 0xe33a910,
snakebite.protobuf.hdfs_pb2.LocatedBlockProto at 0xe33ab40

我做的第一件事是使用 strace 来找出当我调用这个函数时,实际上有哪些数据在传输。下面是一个片段:(整个过程)

请求部分:请求提供 /wikipedia 文件的块位置。

1
2
3
4
sendto(7,
“\n\21getBlockLocations\22.org.apache.hadoop.hdfs.protocol.ClientProtocol\30\1”,
69, 0, NULL, 0) = 69
sendto(7, “\n\n/wikipedia\20\0\30\337\260\240]“, 19, 0, NULL, 0) = 19

响应部分。(我已经删除了大部分内容,只留下了一些重要的部分)

1
2
3
4
5
6
7
recvfrom(7,
“….BP-1019336183-10.165.43.39-1400088409498……………………..
10.147.177.170-9200-1400088495802……………………
BP-1019336183-10.165.43.39-1400088409498………….10.147.177.170-9200-1400088495802
\360G(\216G0\361G8\0\20\200\240\201\213\275\f\30\200\340\376]
\200\300\202\255\274\f(\200\340\376]0\212\306\273\205\340(8\1B\r/default-rackP\0
\0*\10\n\0\22\0\32\0\”\0\30\0\”\355”, 731, 0, NULL, NULL) = 731

回到我们的 Python 控制台,我们可以看一下这其中的一些数字是什么意思:

1
2
3
4
5
6
7
8
9
10
11
12
>>> blocks[0].b.poolId
u'BP-1019336183-10.165.43.39-1400088409498'
>>> blocks[0].b.numBytes
134217728L
>>> blocks[0].locs[0].id.ipAddr
u'10.147.177.170'
>>> blocks[0].locs[0].id.xferPort
9200
>>> blocks[1].b.poolId
u'BP-1019336183-10.165.43.39-1400088409498'
>>> blocks[1].b.numBytes
61347935L

所以我们有两个块! 这两个numBytes加起来就是这个文件的总大小! 很好! 它们都有相同的 poolId,而且还发现它们有相同的 IP 地址和端口。

读取文件块

让我们试着从一个块中读取数据吧 (你可以在 hdfs_fun.py 中看到 read_block 函数

1
2
3
>>> block = blocks[0]
>>> gen = hdfs_fun.read_block(block) # returns a generator
>>> load = gen.next()

如果我用 strace 查看,开头是

1
2
3
4
5
connect(8, {sa_family=AF_INET, sin_port=htons(9200),
sin_addr=inet_addr(“10.147.177.170”)}, 16) = 0
sendto(8,
“\nB\n5\n3\n(BP-1019336183-10.165.43.39-1400088409498\20\211\200\200\200\4\30\361\7\22\tsnakebite\20\0\30\200\200\200@“,
75, 0, NULL, 0) = 75

很好。我们可以很容易地看到,它正在连接到区块的数据节点(10.147.177.170,端口为 9200,并请求提供 id 为BP-1019336183-10.165.43.39-1400088409498 的东西)。然后数据节点开始发回数据!!!。

1
2
3
4
5
6
7
8
9
recvfrom(8, "ot, it's a painting. Thomas Graeme apparently lived in
the mid-18th century, according to the [[Graeme Park]] article. The
rationale also says that this image is "used on the biography
page about him by USHistory.org of Graeme Park." I cannot quite
figure out what this means, but I am guessing that it means the
uploader took this image from a page hosted on USHistory.org. A
painting of a man who lived in the mid-18th century is likely to be
the public domain, as claimed, but we have no good source", 512, 0,
NULL, NULL) = 512

不可思议. 我们就这样征服了 HDFS.

本文作者 : meow
This blog is under a CC BY-NC-SA 4.0 Unported License
本文链接 : https://translation.meow.page/post/diving-into-hdfs/

本文最后更新于 天前,文中所描述的信息可能已发生改变