今天同事遇到了一个问题。 就是hdfsreader->mysqlwriter这种的时候。
有的分区没有数据会报错。
com.tencent.s2.dataingestion.common.exception.DataXException: Code:[HdfsReader-08], Description:[您尝试读取的文件目录为空.]. - 未能找到待读取的文件,请确认您的配置项path: /user/hive/warehouse/dwdmdata.db/dm_tax_f_income_account_detail_y/year_id=2022/ou_code=105
问题很简单,因为该分区下没有数据文件所以报错。
这个解决也很容易。
1.当时想的是在shell里判断分区路径是否存在 然后hdfs dfs -ls /path |wc -l 看文件个数是否>0
后来发现这种不是很可取。
2.当时就觉得这种判断不太对,以前其他reader的时候怎么不见报错,hdfsReader就报错是吧。
哪里报错丢异常 我改成 warn就好了。
找到报错点
那全部原因就是 emptyDirIsExecption 再看
/**emptyDirIsExecption 默认值为true,当指定为false,空目录任务会返回成功,同步记录数为0**/ private Boolean emptyDirIsExecption=null;
再看,这里就是很清楚了
emptyDirIsExecption = this.readerOriginConfig.getBool(Key.EMPTY_DIR_IS_EXECPTION, true);
我们设置在json里设置 emptyDirIsExecption=false即可。
————————————————————————————————————————
至此你以为我就研究完了。前面提到了hdfsreader->mysqlwriter。在刚刚的报错过程中发现了一个问题或者说bug?
hdfsReader报错很正常。但是这里把mysql的presql也执行了。
由此有个疑问 writer和reader那个先运行? 一起还是分先后?
先思考下。
如果writer先reader后。这样writer先执行presql 然后等reader的数据进来,节约了时间
如果writer后reader先。 好处是reader先读数据 如果都没读到,writer都不用启动了。
我们再看看datax是怎么思考的。
所以 我上面思考的还是太简单了。
所有的pre post split 几乎都是同一时刻完成的。
当然真正的传输数据是在schedule的时候完成的。 那么我现在需要如果hdfs reader没有数据也不执行writer的presql怎么做呢?
1.按照我上面的第一种办法 在shell里判断文件个数,可以直接跳过datax结束任务
2.还是改源码? hdfs判断文件数是在split()方法里。我们看split方法
很明显hdfsreader这里会读取到0个文件。当我加了参数emptyDirIsExecption=false后 这里=1
然后走mysql的split方法后面会按照split的个数切分任务就不罗嗦了
按照datax的逻辑 走到这的时候presql已经执行了。
再仔细看看 job有prepare ,task有prepare
我们点进方法发现 如果tableNumber=1就是执行job的presql 如果tableNumber>1执行task的presql;
我只能说datax想的很好。但是感觉这个不可行。
比如hdfs 表student到mysql 的student1 和student2;我的presql是truncate table student1;truncate table student2;
那么执行每个task的时候都要truncate下。。好像不是很合理吧。
按照我的需求好像把presql放到task里执行比较合理。但是呢感觉有问题。
———————————————未完待续,有时间搞下—————————————————