HDFS 客户端读写超时时间解析

原创
2020/10/25 11:32
阅读数 4.1K

背景

前段时间我们Hadoop集群磁盘使用率比较高,部分硬盘空间使用超过了70%,这部分服务器的DataNode服务读写负载就比较高,造成部分数据同步任务因为读写超时而失败。具体场景和异常跟这篇博客里描述的很像。

DFSClient客户端与HDFS交互进行数据读写,需要从NameNode拿到元数据信息,再和DataNode交互,因此,超时时间也同时涉及这两个服务。以下分别是客户端与这两个服务交互的超时时间的解析。

客户端与NameNode超时时间

客户端与NameNode的操作超时时间由以下两个配置控制:

  • ipc.client.ping:默认值是true。当配置为true时,客户端会尽力等待服务端响应,定期发送ping消息,使得连接不会因为tcp timeout而断开。当配置为false时,客户端会使用配置项ipc.ping.interval对应的值,作为timeout时间,在该时间内没有得到响应,即会超时。

  • ipc.ping.interval:以毫秒为单位,默认值是1分钟。当ipc.client.ping配置为true时,表示发送ping消息的周期。当ipc.client.ping设置为false时,表示连接的超时时间。

NameNode节点处于满负载、NameNode所在节点的CPU 100%耗尽时,导致NameNode无法响应,对于新连接到该NameNodeHDFS客户端,能够主备切换连接到另一个NameNode,进行正常的操作,而对于已经连接到该NameNode节点的HDFS客户端可能会卡住,无法进行下一步操作。

HDFS客户端到NameNodeRPC连接存在keep alive机制,保持连接不会超时,尽力等待服务器的响应,因此导致已经连接的HDFS客户端的操作会卡住。

对于已经卡住的HDFS客户端,可以进行如下操作:

  • 等待NameNode响应,一旦NameNode所在节点的CPU利用率回落,NameNode可以重新获得CPU资源时,HDFS客户端即可得到响应。
  • 如果无法等待更长时间,需要重启HDFS客户端所在的应用程序进程,使得HDFS客户端重新连接空闲的NameNode

为了避免该问题出现,在上述问题场景下,可以在客户端的配置文件core-site.xml中做如下配置:

  • ipc.client.ping配置为false,让客户端会使用配置项ipc.ping.interval对应的值,作为timeout时间,在该时间内没有得到响应,即会超时
  • ipc.ping.interval配置一个较大的超时时间,避免服务繁忙时的超时,建议配置为900000,单位为ms

客户端与DataNode读写超时时间

DataNode的读写超时时间由以下两个配置控制:

  • 读超时时间:dfs.client.socket-timeout。默认值1分钟。
  • 写超时时间:dfs.datanode.socket.write.timeout。默认8分钟。

以上配置是在HDFS客户端进行设置,它们的默认值在org.apache.hadoop.hdfs.server.common.HdfsServerConstants类里:

// Timeouts for communicating with DataNode for streaming writes/reads
  // DataNode读写超时时间
  public static final int READ_TIMEOUT = 60 * 1000;
  public static final int READ_TIMEOUT_EXTENSION = 5 * 1000;
  public static final int WRITE_TIMEOUT = 8 * 60 * 1000;
  public static final int WRITE_TIMEOUT_EXTENSION = 5 * 1000; //for write pipeline

DataNode读写超时的时间是跟DataNode的数量有关的,最终是根据DataNode的数量确定读写超时时间,计算方式是以读写超时时间的值乘以节点的数量,逻辑在org.apache.hadoop.hdfs.DFSClient类里:

/**
 * Return the timeout that clients should use when writing to datanodes.
 * @param numNodes the number of nodes in the pipeline. 管道中节点的数量
 */
int getDatanodeWriteTimeout(int numNodes) {
  return (dfsClientConf.confTime > 0) ?
    (dfsClientConf.confTime + HdfsServerConstants.WRITE_TIMEOUT_EXTENSION * numNodes) : 0;
}

int getDatanodeReadTimeout(int numNodes) {
  return dfsClientConf.socketTimeout > 0 ?
      (HdfsServerConstants.READ_TIMEOUT_EXTENSION * numNodes +
          dfsClientConf.socketTimeout) : 0;
}

参考资料

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部