Hadoop学习杂记(二)

Hadoop HDFS 初探

1. 数据块的存取
HDFS集群上的从节点都会驻留一个数据节点的守护进程,来执行分布式文件系统中最忙碌的部分:将HDFS数据块写到Linux本地文件系统的实际文件中,或者从这些实际的文件读取数据块。
2. 客户端访问HDFS的过程
客户端进行文件内容操作时,先由名字节点告知客户端每个数据块驻留在哪个数据节点,然后客户端直接与数据节点守护进程进行通信,处理与数据块对应的本地文件。同时,数据节点会和其他数据节点进行通信,复制数据块,保证数据的冗余性。

HDFS是一种分布式文件系统。
设计分布式文件系统要考虑的一些问题:
访问透明性、性能透明性、伸缩透明性、复制透明性、并发透明性、故障透明性等

选取一些比较有特点的设计摘录如下:
设计一:FileStatus
文件信息对象,路径、长度、 副本数,块大小、所有者等。 block replication和block size专门为HDFS准备。
实现Writable接口,一次性将文件的所有属性读出返回到客户端,减少在分布式系统中进行网络传输的次数,针对性设计。

设计二:FSDataInputStream
它实现了Seekable、PositionedReadable接口。
利用前者的 seekToNewSource方法可以重新选择一个副本,用于HDFS中。
利用后者实现从流中某个位置开始读数据,并 不改变流的当前位置,且是 线程安全。(线程安全是如何实现的?实现方法时?)

注意,FSInputStream抽象类实现了PositionedReadable接口的read方法,通过sychronized关键字保证线程安全。通过Seekable中的方法保证流的当前位置不变。

设计该类的目的就是将FSInputStream包装进DataInputStream中,使之具备读取某种原生类型的功能。同时,构造FSDataInputStream的对象必须是实现了Seekable、PositionedReadable接口的类对象,比如FSInputStream。这样利用多态,每个方法的实现就依赖于构造器参数中流对象的方法实现了。构造器如下:
public FSDataInputStream( InputStream in)
    throws IOException {
    super(in);
    if( !(in instanceof Seekable) || !(in instanceof PositionedReadable) ) {
      throw new IllegalArgumentException(
          "In is not an instance of Seekable or PositionedReadable");
    }
  }
类似于一种装饰器。这样,原来只有任意位置读取功能的流,如FSInputStream,同时具有了读取某种类型数据的能力。
方法实现举例:
public int read(long position, byte[] buffer, int offset, int length)
    throws IOException {
    return ((PositionedReadable)in).read(position, buffer, offset, length);
  }
read方法就是利用in的read实现。in可以使FSInputStream等类型。


设计三:FileDataOutputStream
不实现Seekable接口,Hadoop文件系统 不支持随机写
但提供getPos的功能,当前写位置通过一个内部类PositionCache获得,这个类是个 过滤流
过滤流的作用就是在底层流基础上封装一些新的功能,是装饰器模式的基础。
构造器:
public FSDataOutputStream(OutputStream out, FileSystem.Statistics stats,
                            long startPosition) throws IOException {
    super(new PositionCache(out, stats, startPosition));
    wrappedStream = out;
  }

插入话题:装饰模式
动机: 透明地给一个对象增加功能,并实现功能的动态组合。所谓透明,就是给一个对象增加功能,但是不能让这个对象知道,也就是不能去改动这个对象。继承的缺点在于只能增加功能,不能删除或修改功能。

思想:在面向对象设计中,有一条基本的规则就是“尽量使用对象组合,而不是对象继承”来扩展和复用功能。装饰器模式思考起点就是这个规则。

装饰模式的一些对象:
1. Component 组件对象接口
2. ConcreteComponent 具体组件对象 被装饰器装饰的原始对象
3. Decorator:所有装饰器的抽象类  接口与组件接口一致通常继承于Component,目的是可以连续装饰) 要持有一个Component对象 即被修饰的对象
4. ConcreteDecorator:实现具体要向被装饰对象添加的功能

这里类比一下Java流的类
Component对应OutputStream
ConcreteComponent对应FSDataOutputStream
Decorator相当于FilterOutputStream
ConcreteDecorator相当于PositionCache

具体地,FilterOutputStream继承于OutputStream保持接口一致,并持有一个OutputStream对象,用于装饰,构造时要传入一个OutputStream对象。

public void write(int b) throws IOException {
out.write(b);
}

其中方法转发给组件对象,如上述的out.write


举例:PositionCache类是一个装饰器,目的是给输出流增加记录当前流写位置和一些统计功能。
FSDataOutputStream是一个装饰器类,它持有一个组件对象wrappedStream(先忽略这个对象)
这个类从父类那继承了一个OuputStream对象out,其实它的父类DataOutputStream类也是一个装饰器类,其增加了记录当前输出的字节数的功能。
这个类即在父类的基础上使用PositionCache装饰器进一步增加功能。


加入客户端有如下代码:
FSDataOutputStream fsdos = new FSDataOutputStream(new FileOutputStream("test.txt"), stats, 1000);
调用下面构造器:
public FSDataOutputStream(OutputStream out, FileSystem.Statistics stats,
                            long startPosition) throws IOException {
    super(new PositionCache(out, stats, startPosition));
    wrappedStream = out;
  }

构造PositionCache对象:
public PositionCache(OutputStream out, 
                         FileSystem.Statistics stats,
                         long pos) throws IOException {
      super(out);
      statistics = stats;
      position = pos;
    }
此时那个文件输出流对象被赋值给装饰器基类中的OutputStream对象out
回到上一层,刚构造的PositionCache对象被赋值给装饰器基类中的OutputStream对象out

当调用fsdos.write时,调用父类的write方法如下:
public synchronized void write(int b) throws IOException {
out.write(b);
        incCount(1);
    }
这里的out继承自DataOutputStream的父类,即FilterOutputStream,而在FSDataOutputStream对象初始化时,这个out对象已经被初始化为一个PositionCache对象。
因此调用PositionCache的write方法:
public void write(int b) throws IOException {
      out.write(b);
      position++;
      if (statistics != null) {
        statistics.incrementBytesWritten(1);
      }
    }
而这里的out对象是在PositionCache对象初始化时,被赋值为那个文件输出流对象,因此调用的是FileOutputStream.write方法。

这样便完成了从组件类(FileOutputStream)到装饰器类(FSDataOutputStream、DataOutputStream和PositionCache)的层层调用的递归过程。在每一层功能都有所增加。
其实装饰过程相当于
new FSDataOutputStream(new PointCache(new FileOutputStream(""),dd,dd),dd,dd);

每层装饰器的父类对象都使用下一层的装饰器对象初始化,一直到组件对象位置。调用方法时,则递归调用到底层组件对象,再逐层返回,每层都是先调用父类(也就是下层装饰器)方法,再添加装饰功能。

参考资料: 蔡斌 陈湘萍 《Hadoop技术内幕--深入解析Hadoop HDFS和Common架构设计与实现原理》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值