读HDFS书笔记---5.1 DFSClient实现

5.1   DFSClient实现

        5.1.1 构造方法

        5.1.2 关闭方法

        5.1.3 文件系统管理与配置方法

        5.1.4 HDFS文件与目录操作方法

        5.1.5 HDFS文件读写方法

 

5.1 DFSClient实现

HDFS目前提供了三个客户端接口,这三个接口分别是DistributedFileSystem、FsShell和DFSAdmin。

DistributedFileSystem:用来给用户开发基于HDFS的应用程序提供API

FsShell:用户通过shell命令执行常见的文件系统操作,调用的就是该接口,例如创建文件、删除文件、创建目录等

DFSAdmin:系统管理员管理HDFS的工具,例如执行升级、管理安全模式等操作。

DFSClient类实现了分布式系统客户端功能,是用户使用HDFS各项功能的起点。DFSClient会连接到HDFS,对外提供管理文件/目录、读写文件以及管理与配置HDFS系统等功能。

对于管理文件/目录以及管理与配置HDFS系统这两个功能,DFSClient不需要与Datanode进行交互,而是直接通过远程接口ClientProtocol调用Namenode提供的服务即可。而文件的读写功能,除了调用ClientProtocol与Namenode交互外,还需要通过流式接口DataTransferProtocol与Datanode交互传输数据。

 

DFSClient提供的接口方法有以下几类:

(1)、DFSClient的构造方法和关闭方法

(2)、管理与配置文件系统相关方法

(3)、操作HDFS文件与目录方法

(4)、读写HDFS文件方法

 

5.1.1 构造方法

有5个构造函数,其中参数为Configuration的构造函数已经被废弃,其他4个构造函数都调用了最后一个构造函数,如下图

最后一个构造函数的代码如下:

/** 
   * Create a new DFSClient connected to the given nameNodeUri or rpcNamenode.
   * If HA is enabled and a positive value is set for 
   * {@link DFSConfigKeys#DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY} in the
   * configuration, the DFSClient will use {@link LossyRetryInvocationHandler}
   * as its RetryInvocationHandler. Otherwise one of nameNodeUri or rpcNamenode 
   * must be null.
   */
  @VisibleForTesting
  public DFSClient(URI nameNodeUri, ClientProtocol rpcNamenode,
      Configuration conf, FileSystem.Statistics stats)
    throws IOException {
    // Copy only the required DFSClient configuration
    this.dfsClientConf = new Conf(conf);
    if (this.dfsClientConf.useLegacyBlockReaderLocal) {
      LOG.debug("Using legacy short-circuit local reads.");
    }
    this.conf = conf;//HDFS配置信息
    this.stats = stats;//Client状态统计信息,包括Client读、写字节数等
    this.socketFactory = NetUtils.getSocketFactory(conf, ClientProtocol.class);
    //当Client读写数据时,如果Datanode出现故障,是否进行Datanode替换的策略
    this.dtpReplaceDatanodeOnFailure = ReplaceDatanodeOnFailure.get(conf);

    //获取当前用户信息
    this.ugi = UserGroupInformation.getCurrentUser();
    
    this.authority = nameNodeUri == null? "null": nameNodeUri.getAuthority();
    this.clientName = "DFSClient_" + dfsClientConf.taskId + "_" + 
        DFSUtil.getRandom().nextInt()  + "_" + Thread.currentThread().getId();
    provider = DFSUtil.createKeyProvider(conf);
    if (LOG.isDebugEnabled()) {
      if (provider == null) {
        LOG.debug("No KeyProvider found.");
      } else {
        LOG.debug("Found KeyProvider: " + provider.toString());
      }
    }
    int numResponseToDrop = conf.getInt(
        DFSConfigKeys.DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY,
        DFSConfigKeys.DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_DEFAULT);
    NameNodeProxies.ProxyAndInfo<ClientProtocol> proxyInfo = null;
    AtomicBoolean nnFallbackToSimpleAuth = new AtomicBoolean(false);
    if (numResponseToDrop > 0) {
      // This case is used for testing.
      LOG.warn(DFSConfigKeys.DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY
          + " is set to " + numResponseToDrop
          + ", this hacked client will proactively drop responses");
      proxyInfo = NameNodeProxies.createProxyWithLossyRetryHandler(conf,
          nameNodeUri, ClientProtocol.class, numResponseToDrop,
          nnFallbackToSimpleAuth);
    }
    
    if (proxyInfo != null) {
      this.dtService = proxyInfo.getDelegationTokenService();
      this.namenode = proxyInfo.getProxy();
    } else if (rpcNamenode != null) {
      // This case is used for testing.
      Preconditions.checkArgument(nameNodeUri == null);
      this.namenode = rpcNamenode;
      dtService = null;
    } else {
      Preconditions.checkArgument(nameNodeUri != null,
          "null URI");
      proxyInfo = NameNodeProxies.createProxy(conf, nameNodeUri,
          ClientProtocol.class, nnFallbackToSimpleAuth);
      this.dtService = proxyInfo.getDelegationTokenService();
      this.namenode = proxyInfo.getProxy();
    }

    String localInterfaces[] =
      conf.getTrimmedStrings(DFSConfigKeys.DFS_CLIENT_LOCAL_INTERFACES);
    //本地接口地址
    localInterfaceAddrs = getLocalInterfaceAddrs(localInterfaces);
    if (LOG.isDebugEnabled() && 0 != localInterfaces.length) {
      LOG.debug("Using local interfaces [" +
      Joiner.on(',').join(localInterfaces)+ "] with addresses [" +
      Joiner.on(',').join(localInterfaceAddrs) + "]");
    }
    
    //读取数据后,是否立即从操作系统缓冲区中删除
    Boolean readDropBehind = (conf.get(DFS_CLIENT_CACHE_DROP_BEHIND_READS) == null) ?
        null : conf.getBoolean(DFS_CLIENT_CACHE_DROP_BEHIND_READS, false);
    //预读取字节数
    Long readahead = (conf.get(DFS_CLIENT_CACHE_READAHEAD) == null) ?
        null : conf.getLong(DFS_CLIENT_CACHE_READAHEAD, 0);
    //写数据后,是否立即从操作系统缓冲区中删除
    Boolean writeDropBehind = (conf.get(DFS_CLIENT_CACHE_DROP_BEHIND_WRITES) == null) ?
        null : conf.getBoolean(DFS_CLIENT_CACHE_DROP_BEHIND_WRITES, false);
    this.defaultReadCachingStrategy =
        new CachingStrategy(readDropBehind, readahead);
    this.defaultWriteCachingStrategy =
        new CachingStrategy(writeDropBehind, readahead);
    this.clientContext = ClientContext.get(
        conf.get(DFS_CLIENT_CONTEXT, DFS_CLIENT_CONTEXT_DEFAULT),
        dfsClientConf);
    
    /*hedgedReadThresholdMillis保存触发"hedged read"机制的时长,
当Client发现一个数据块读取操作太慢时(读取时长超过hedgedReadThresholdMillis),
那么Client会启动另外一个并发操作读取数据块的另外一个副本,
之后Client会返回先完成读取副本的数据。*/
    this.hedgedReadThresholdMillis = conf.getLong(
        DFSConfigKeys.DFS_DFSCLIENT_HEDGED_READ_THRESHOLD_MILLIS,
        DFSConfigKeys.DEFAULT_DFSCLIENT_HEDGED_READ_THRESHOLD_MILLIS);
    int numThreads = conf.getInt(
        DFSConfigKeys.DFS_DFSCLIENT_HEDGED_READ_THREADPOOL_SIZE,
        DFSConfigKeys.DEFAULT_DFSCLIENT_HEDGED_READ_THREADPOOL_SIZE);
    if (numThreads > 0) {
      this.initThreadsNumForHedgedReads(numThreads);
    }
    //简单验证安全层 
    this.saslClient = new SaslDataTransferClient(
      conf, DataTransferSaslUtil.getSaslPropertiesResolver(conf),
      TrustedChannelResolver.getInstance(conf), nnFallbackToSimpleAuth);
  }

构造函数完成两个功能:

(1)、初始化成员变量

(2)、获取Namenode的RPCProxy引用,供DFSClient远程调用Namenode的RPC方法

5.1.2 关闭方法

关闭方法为close,代码如下:

/**
   * Close the file system, abandoning all of the leases and files being
   * created and close connections to the namenode.
   */
  @Override
  public synchronized void close() throws IOException {
    try {
      if(clientRunning) {
        //关闭所有正在进行写操作的IO流。
        closeAllFilesBeingWritten(false);
        //设置为false标志,停止DFSClient对外服务
        clientRunning = false;
        //停止租约管理
        getLeaseRenewer().closeClient(this);
        // close connections to the namenode,关闭与Namenode的RPC连接
        closeConnectionToNamenode();
      }
    } finally {
      if (provider != null) {
        provider.close();
      }
    }
  }

5.1.3 文件系统管理与配置方法

HDFS管理员通过DFSAdmin工具管理与配置HDFS,DFSAdmin也是通过持有DistributedFileSystem对象的引用,然后进一步调用DFSClient类提供的方法执行管理与配置操作的,整个流程比较简单,我们用DFSClient.rollEdits()方法为例,流程图如下:

流程图

DFSClient文件系统管理与配置方法对应关系图

DFSClient文件系统管理与配置方法对应关系图

DFSClient中还有许多命令是直接建立与Datanode或者Namenode的RPC连接,然后调用对应的RPC方法实现的,例如getDatanode、shutdownDatanode()等操作。

5.1.4 HDFS 文件与目录操作方法

除了管理与配置HDFS文件系统外,DFSClient的另外一个重要功能就是操作HDFS文件与目录,例如setPermission()、rename()、getFileInfo()、delete()等对文件/目录树的增、删、改、查等操作。

5.1.5 HDFS文件读写方法

DFSClient对文件进行读写操作,涉及的方法比较多,后面会进行详细讲解。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值