开发的时候发现了es里面数据有缺失,排查了好久,最后怀疑是renameTo方法的时候,在renameTo还没有完成的时候,程序就对生成的文件进行了处理,实际上这个时候文件还没有完全进入目标文件夹
这完全是一个偶发的问题,但是,发生的频率并不算太低,基本上每小时12个点的文件,总会有一个点出现这种情况,我并没有做完全的统计,因为总体数据量比较大。
于是我在renameTo *** 作后加了一个线程等待一秒钟的 *** 作,就是为了防止出现这种文件还未转移完全的情况
并且我打印了两行日志,看一下被renameTo前后文件是不是有差异
结果果然是,renameTo前后的数据竟然相差相当大
我研究了一下renameTo的源码,发现最后是调用的native方法
private native boolean rename0(File f1, File f2);
我猜测是rename0方法是在开始执行的时候,发现文件可以移动就返回了true,而此时其实刚开始执行数据移动 *** 作,数据移动还没有完成,理论上这种移动会很快。程序进行 *** 作的文件,13000行的数据,也没有产生问题,为什么2000行的数据会缺失。是不是如果遇到了机器IO极大的时候,可能会影响数据的转移。在转移了部分数据之后,我的程序开始了读 *** 作,然后就出现了不可写入的情况。剩下的数据也就不会再写入了。
但是伴随而来的就是一个问题,rename0方法到底是以什么形式进行转移文件的,未完全转移的时候是否允许对文件进行读写 *** 作。如果允许,那么我猜测可能成立,如果不允许,我的猜测就不成立了。
我开始想调大一点sleep时间,但是每一秒对于上万个文件的处理速度都是很大的影响。我现在发现,我甚至没办法判断rename0是否完成了。
最后处理办法决定通过复制再删除的方法完成试一下,原来的renameTo换成了jdk提供的一个FileChannel的方式实现
try { FileUtil.copyFileUsingFileChannels(backFile,backuppath); backFile.delete(); }catch (Exception e){ LOGGER.error("文件复制失败:"+backPath); }
copyFileUsingFileChannels方法
public static void copyFileUsingFileChannels(File source, File dest) throws IOException { FileChannel inputChannel = null; FileChannel outputChannel = null; try { inputChannel = new FileInputStream(source).getChannel(); outputChannel = new FileOutputStream(dest).getChannel(); outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); } finally { inputChannel.close(); outputChannel.close(); } }
目前观察程序还没有出现缺失数据的情况,待后续观察
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)