线上hdfs为何一直写失败,频繁丢数据?

171 阅读1分钟

问题发现

  • 首先业务逻辑是:离线日志会存在hdfs中,然后定期推到oss,用户会从oss中拉取数据核对计费数据。
  • 我们发现写hdfs会出现写失败的情况,然后用户做账单对比时发现对不上。

第一步尝试加重试

我们在client端加了多次重试

  • create重试
  • append重试
  • 写入一行失败后重试 但是依然存在数据丢失的问题

第二步分析源码

写入过程源码分析:juejin.cn/post/717665…
写错误恢复过程源码分析:juejin.cn/post/717702…
append过程源码分析:

streamer = new DataStreamer(lastBlock, stat, bytesPerChecksum);   
----> setPipeline(lastBlock);   
----> setupPipelineForAppendOrRecovery();initDataStreaming();  

pipline状态变化:PIPELINE_SETUP_APPEND -> DATA_STREAMING

第三步分析日志

client端日志:All datanodes XXX are bad. Aborting...
datanode端日志:Insufficient space for appending to XXX

线上写失败原因

datanode失败原因

  1. 集群中有一部分小盘机器磁盘写满
  2. 业务模式需要使用append模式,append模式会在最后一个block所在节点上创建pipline,如果是create方式会直接在有足够空间的节点上创建块,磁盘写满后会抛出异常。

所有datanode都失败的原因

default condition会判断副本数大于3才进行节点迁移,为了节省资源配置了2个节点,造成失败后无法追加节点,直到节点全部失败。

丢失多少数据?

如果在client端出现写失败后就直接close文件,这个时候close也会失败,还未发送的buffer和dataQueue以及ackQueue中的也会丢失。

解决方案

  1. 移除小磁盘机器,扩⼀一些⼤大磁盘机器,避免小磁盘机器成为短板。
  2. 判断是否追加节点使用always condition