# 3.5 GFS读文件（Read File)

有了之前的基础，我接下来会列出GFS读和写的步骤，最后，我会介绍出现故障之后，系统是如何保持正确的行为。

对于读请求来说，意味着应用程序或者GFS客户端有一个文件名和它想从文件的某个位置读取的偏移量（offset），应用程序会将这些信息发送给Master节点。Master节点会从自己的file表单中查询文件名，得到Chunk ID的数组。因为每个Chunk是64MB，所以偏移量除以64MB就可以从数组中得到对应的Chunk ID。之后Master再从Chunk表单中找到存有Chunk的服务器列表，并将列表返回给客户端。所以，第一步是客户端（或者应用程序）将文件名和偏移量发送给Master。第二步，Master节点将Chunk Handle（也就是ID，记为H）和服务器列表发送给客户端。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDYB9aeFvbdOMF7m_XK%2F-MDYhBGlEbBfEvggCdJw%2Fimage.png?alt=media\&token=da3cd61d-5ffc-4426-813b-79c1ec01c4a2)

现在客户端可以从这些Chunk服务器中挑选一个来读取数据。GFS论文说，客户端会选择一个网络上最近的服务器（Google的数据中心中，IP地址是连续的，所以可以从IP地址的差异判断网络位置的远近），并将读请求发送到那个服务器。因为客户端每次可能只读取1MB或者64KB数据，所以，客户端可能会连续多次读取同一个Chunk的不同位置。所以，客户端会缓存Chunk和服务器的对应关系，这样，当再次读取相同Chunk数据时，就不用一次次的去向Master请求相同的信息。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDYn-jrGewGThIvRgiQ%2F-MDYn2kJVIAr8ojMnlAs%2Fimage.png?alt=media\&token=4180ae29-1b12-4f12-8322-c3b927380815)

接下来，客户端会与选出的Chunk服务器通信，将Chunk Handle和偏移量发送给那个Chunk服务器。Chunk服务器会在本地的硬盘上，将每个Chunk存储成独立的Linux文件，并通过普通的Linux文件系统管理。并且可以推测，Chunk文件会按照Handle（也就是ID）命名。所以，Chunk服务器需要做的就是根据文件名找到对应的Chunk文件，之后从文件中读取对应的数据段，并将数据返回给客户端。

![](https://2933519158-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAkokVMtbC7djI1pgSw%2F-MDYn-jrGewGThIvRgiQ%2F-MDZMSQ_MaBlxMQ_xekr%2Fimage.png?alt=media\&token=e58e59b4-0e8a-41e9-ac54-2353363bcabe)

> 学生提问：可以再讲一下第一步吗？
>
> Robert教授：第一步是，应用程序想读取某个特定文件的某个特定的偏移位置上的某段特定长度的数据，比如说第1000到第2000个字节的数据。所以，应用程序将文件名，长度和起始位置发送给Master节点。Master节点会从其file表单中查询文件名并找到包含这个数据段的Chunk，这样可以吗？
>
> 学生提问：如果读取的数据超过了一个Chunk怎么办？
>
> Robert教授：我不知道详细的细节。我的印象是，如果应用程序想要读取超过64MB的数据，或者就是2个字节，但是却跨越了Chunk的边界，应用程序会通过一个库来向GFS发送RPC，而这个库会注意到这次读请求会跨越Chunk边界，因此会将一个读请求拆分成两个读请求再发送到Master节点。所以，这里可能是向Master节点发送两次读请求，得到了两个结果，之后再向两个不同的Chunk服务器读取数据。
>
> 学生提问：如果客户端有偏移量信息，那可以直接算出来是第几个Chunk吧？

> Robert教授：客户端可以算出来是哪个Chunk，但是客户端不知道Chunk在哪个服务器上。为了获取服务器信息，客户端需要与Master交互。我不能保证究竟是在哪里决定的要读取的是第几个Chunk。但是可以确定的是，Master节点找到了Chunk对应的ID，并确定了Chunk存储在哪个服务器上。
>
> 学生提问：能再介绍一下读数据跨越了Chunk边界的情况吗？
>
> Robert教授：客户端本身依赖了一个GFS的库，这个库会注意到读请求跨越了Chunk的边界 ，并会将读请求拆分，之后再将它们合并起来。所以这个库会与Master节点交互，Master节点会告诉这个库说Chunk7在这个服务器，Chunk8在那个服务器。之后这个库会说，我需要Chunk7的最后两个字节，Chunk8的头两个字节。GFS库获取到这些数据之后，会将它们放在一个buffer中，再返回给调用库的应用程序。Master节点会告诉库有关Chunk的信息，而GFS库可以根据这个信息找到应用程序想要的数据。应用程序只需要确定文件名和数据在整个文件中的偏移量，GFS库和Master节点共同协商将这些信息转换成Chunk。
>
> 学生提问：从哪个Chunk服务器读取数据重要吗？
>
> Robert教授：是也不是。概念上讲，它们都是副本。实际上，你可能已经注意到，或者我们之前也说过，不同Chunk服务器上的数据并不一定完全相同。应用程序应该要能够容忍这种情况。所以，实际上，如果从不同的Chunk服务器读取数据，可能会略微不同。GFS论文提到，客户端会尝试从同一个机架或者同一个交换机上的服务器读取数据。
