问题发现
- 首先业务逻辑是:离线日志会存在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失败原因
- 集群中有一部分小盘机器磁盘写满
- 业务模式需要使用append模式,append模式会在最后一个block所在节点上创建pipline,如果是create方式会直接在有足够空间的节点上创建块,磁盘写满后会抛出异常。
所有datanode都失败的原因
default condition会判断副本数大于3才进行节点迁移,为了节省资源配置了2个节点,造成失败后无法追加节点,直到节点全部失败。
丢失多少数据?
如果在client端出现写失败后就直接close文件,这个时候close也会失败,还未发送的buffer和dataQueue以及ackQueue中的也会丢失。
解决方案
- 移除小磁盘机器,扩⼀一些⼤大磁盘机器,避免小磁盘机器成为短板。
- 判断是否追加节点使用always condition