没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
Hadoop 源代码分析(一)
关键字: 分布式 云计算
Google 的核心竞争技术是它的计算平台。Google 的大牛们用了下面 5 篇文章,介绍了它们的计算设施。
GoogleCluster: http://research.google.com/archive/googlecluster.html
Chubby:http://labs.google.com/papers/chubby.html
GFS:http://labs.google.com/papers/gfs.html
BigTable:http://labs.google.com/papers/bigtable.html
MapReduce:http://labs.google.com/papers/mapreduce.html
很快,Apache 上就出现了一个类似的解决方案,目前它们都属于 Apache 的 Hadoop 项目,对应的分别是:
Chubby-->ZooKeeper
GFS-->HDFS
BigTable-->HBase
MapReduce-->Hadoop
目前,基于类似思想的 Open Source 项目还很多,如 Facebook 用于用户分析的 Hive。
HDFS 作为一个分布式文件系统,是所有这些项目的基础。分析好 HDFS,有利于了解其他系统。由于 Hadoop 的 HDFS 和 MapReduce
是同一个项目,我们就把他们放在一块,进行分析。
下图是 MapReduce 整个项目的顶层包图和他们的依赖关系。Hadoop 包之间的依赖关系比较复杂,原因是 HDFS 提供了一个分布
式文件系统,该系统提供 API,可以屏蔽本地文件系统和分布式文件系统,甚至象 Amazon S3 这样的在线存储系统。这就造成
了分布式文件系统的实现,或者是分布式文件系统的底层的实现,依赖于某些貌似高层的功能。功能的相互引用,造成了蜘蛛
网型的依赖关系。一个典型的例子就是包 conf,conf 用于读取系统配置,它依赖于 fs,主要是读取配置文件的时候,需要使
用文件系统,而部分的文件系统的功能,在包 fs 中被抽象了。
Hadoop 的关键部分集中于图中蓝色部分,这也是我们考察的重点。
Hadoop 源代码分析(二)
下面给出了 Hadoop 的包的功能分析。
Package Dependences
tool 提供一些命令行工具,如 DistCp,archive
mapreduce
Hadoop 的 Map/Reduce 实现
filecache 提供 HDFS 文件的本地缓存,用于加快 Map/Reduce 的数据访问
速度
fs
文件系统的抽象,可以理解为支持多种文件系统实现的统一文
件访问接口
hdfs
HDFS,Hadoop 的分布式文件系统实现
ipc
一个简单的 IPC 的实现,依赖于 io 提供的编解码功能
参考:http://zhangyu8374.javaeye.com/blog/86306
io
表示层。将各种数据编码/解码,方便于在网络上传输
net 封装部分网络功能,如 DNS,socket
security 用户和用户组信息
conf 系统的配置参数
metrics 系统统计数据的收集,属于网管范畴
util 工具类
record 根据 DDL(数据描述语言)自动生成他们的编解码函数,目前
可以提供 C++和 Java
http 基于 Jetty 的 HTTP Servlet,用户通过浏览器可以观察文件系统
的一些状态信息和日志
log 提供 HTTP 访问日志的 HTTP Servlet
Hadoop 源代码分析(三)
由于 Hadoop 的 MapReduce 和 HDFS 都有通信的需求,需要对通信的对象进行序列化。Hadoop 并没有采用 Java 的序列化,而是
引入了它自己的系统。
org.apache.hadoop.io 中定义了大量的可序列化对象,他们都实现了 Writable 接口。实现了 Writable 接口的一个典型例子如
下:
Java 代码
1. publicclassMyWritableimplementsWritable{
2. //Somedata
3. privateintcounter;
4. privatelongtimestamp;
5.
6. publicvoidwrite(DataOutputout)throwsIOException{
7. out.writeInt(counter);
8. out.writeLong(timestamp);
9. }
10.
11. publicvoidreadFields(DataInputin)throwsIOException{
12.
counter=in.readInt();
13. timestamp=in.readLong();
14. }
15.
16. publicstaticMyWritableread(DataInputin)throwsIOException{
17. MyWritablew=newMyWritable();
18. w.readFields(in);
19. returnw;
20. }
21. }
其中的 write 和 readFields 分别实现了把对象序列化和反序列化的功能,是 Writable 接口定义的两个方法。下图给出了庞大
的 org.apache.hadoop.io 中对象的关系。
这里,我把 ObjectWritable 标为红色,是因为相对于其他对象,它有不同的地位。当我们讨论 Hadoop 的 RPC 时,我们会提到
RPC 上交换的信息,必须是 Java 的基本类型,String 和 Writable 接口的实现类,以及元素为以上类型的数组。ObjectWritable
对象保存了一个可以在 RPC 上传输的对象和对象的类型信息。这样,我们就有了一个万能的,可以用于客户端/服务器间传输的
Writable 对象。例如,我们要把上面例子中的对象作为 RPC 请求,需要根据 MyWritable 创建一个 ObjectWritable,
ObjectWritable 往流里会写如下信息
对象类名长度,对象类名,对象自己的串行化结果
这样,到了对端,ObjectWritable 可以根据对象类名创建对应的对象,并解串行。应该注意到,ObjectWritable 依赖于
WritableFactories,那存储了 Writable 子类对应的工厂。我们需要把 MyWritable 的工厂,保存在 WritableFactories 中(通
过 WritableFactories.
setFactory
)。
Hadoop 源代码分析(五)
介绍完 org.apache.hadoop.io 以后,我们开始来分析 org.apache.hadoop.rpc。RPC 采用客户机/服务器模式。请求程序就是一
个客户机,而服务提供程序就是一个服务器。当我们讨论 HDFS 的,通信可能发生在:
Client‐NameNode 之间,其中 NameNode 是服务器
Client‐DataNode 之间,其中 DataNode 是服务器
DataNode‐NameNode 之间,其中 NameNode 是服务器
DataNode‐DateNode 之间,其中某一个 DateNode 是服务器,另一个是客户端
如果我们考虑 Hadoop 的 Map/Reduce 以后,这些系统间的通信就更复杂了。为了解决这些客户机/服务器之间的通信,Hadoop
引入了一个 RPC 框架。该 RPC 框架利用的 Java 的反射能力,避免了某些 RPC 解决方案中需要根据某种接口语言(如 CORBA 的
IDL)生成存根和框架的问题。但是,该 RPC 框架要求调用的参数和返回结果必须是 Java 的基本类型,String 和 Writable接
口的实现类,以及元素为以上类型的数组。同时,接口方法应该只抛出 IOException 异常。(参考自
http://zhangyu8374.javaeye.com/blog/86306)
既然是 RPC,当然就有客户端和服务器,当然,org.apache.hadoop.rpc 也就有了类 Client 和类 Server。但是类 Server 是一
个抽象类,类 RPC 封装了 Server,利用反射,把某个对象的方法开放出来,变成 RPC 中的服务器。
下图是 org.apache.hadoop.rpc 的类图。
Hadoop 源代码分析(六)
既然是 RPC,自然就有客户端和服务器,当然,org.apache.hadoop.rpc 也就有了类 Client 和类 Server。在这里我们来仔细考
察 org.apache.hadoop.rpc.Client。下面的图包含了 org.apache.hadoop.rpc.Client 中的关键类和关键方法。
由于 Client 可能和多个 Server 通信,典型的一次 HDFS 读,需要和 NameNode 打交道,也需要和某个/某些 DataNode 通信。这
就意味着某一个 Client 需要维护多个连接。同时,为了减少不必要的连接,现在 Client 的做法是拿 ConnectionId(图中最右
侧)来做为 Connection 的 ID。ConnectionId 包括一个 InetSocketAddress(IP 地址+端口号或主机名+端口号)对象和一个用
户信息对象。这就是说,同一个用户到同一个 InetSocketAddress 的通信将共享同一个连接。
连接被封装在类 Client.Connection 中,所有的 RPC 调用,都是通过 Connection,进行通信。一个 RPC 调用,自然有输入参数,
输出参数和可能的异常,同时,为了区分在同一个 Connection 上的不同调用,每个调用都有唯一的 id。调用是否结束也需要
一个标记,所有的这些都体现在对象 Client.Call 中。Connection 对象通过一个 Hash 表,维护在这个连接上的所有 Call:
Java 代码
1. privateHashtable<Integer,Call>calls=newHashtable<Integer,Call>();
一个 RPC 调用通过 addCall,把请求加到 Connection 里。为了能够在这个框架上传输 Java 的基本类型,String 和 Writable 接
口的实现类,以及元素为以上类型的数组,我们一般把 Call 需要的参数打包成为 ObjectWritable 对象。
Client.Connection 会通过 socket 连接服务器,连接成功后回校验客户端/服务器的版本号(Client.ConnectionwriteHeader()
方法),校验成功后就可以通过 Writable 对象来进行请求的发送/应答了。注意,每个 Client.Connection 会起一个线程,不
断去读取 socket,并将收到的结果解包,找出对应的 Call,设置 Call 并通知结果已经获取。
Call 使用 Obejct 的 wait 和 notify,把 RPC 上的异步消息交互转成同步调用。
还有一点需要注意,一个 Client 会有多个 Client.Connection,这是一个很自然的结果。
Hadoop 源代码分析(七)
聊完了 Client 聊 Server,按惯例,先把类图贴出来。
需要注意的是,这里的 Server 类是个抽象类,唯一抽象的地方,就是
Java 代码
1. publicabstractWritablecall(Writableparam,longreceiveTime)throwsIOException;
这表明,Server 提供了一个架子,Server 的具体功能,需要具体类来完成。而具体类,当然就是实现 call 方法。
剩余82页未读,继续阅读
资源评论
- hhy5277062012-12-06非常详细的关于hadoop的源码分析的文档,关注nosql的朋友千万不能错过哈 可以用,非常不错
- EricaKang2012-08-17骗子,报错:不是一个pdf文件或已损坏。太坏了!
- AmazinGame2012-09-26可以用,非常不错
小猴大叔
- 粉丝: 9
- 资源: 14
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功