【疑难杂症03】数据同步遇到的坑
这是发生在我身上的一个bug,困扰了我三天,已经让我多次怀疑人生。因为我这个工作是数据准备阶段,后续还有一系列工作需要依赖我这些初始数据,压力很大,感谢某人在这个时候给我的鼓励,虽然只是寥寥几句。这件事记起来仅为日后提醒自己不再犯相同的错误。
一、问题经过
简单来说,我做的是一个数据同步任务,将数据从es的一个type经过转换和操作同步到另一个type中,下面统一说A同步到B,而且这个同步是周期性执行的,下面通过一个流程图:
循环的部分的流程图不标准,大家懂意思就可以,程序其实很简单,除了引用的工具类,我就用了一个类就完成了上面的操作,每一个过程是一个方法,方法结束后也会打印相应日志,而且测试网经过测试也是没问题的(这句话是不是很熟悉,如果你经常这么说,那就小心了),结果到了生产网就出事了,具体两个奇怪现象:
- 首次同步的时候,B端少数据
- 再次同步的时候,B端有重复数据
因为B端开始是没数据的,所以出现上面两个问题只可能是我程序的问题。
二、解决经过
出现问题后,我直接蒙了,心想绝对不可能,然后一遍一遍的看程序,因为就一个类,所以看了好多遍,因为重复数据我是绝对认为不可能的,所以我的关注点就放在了怎么可能有重复,我的思路是两边全部查出来,以主机名加ip为key,value为本身,放到Map中。然后进行比较的。
- 我把整个处理类重新写了一遍,去掉了其中用到的lambda表达式,现在想想有点可笑,我怀疑lambda表达式有bug。
- 我把所有处理路径打印上日志,数量也都打印出来。
经过这样后,依然没有发现问题,数据平白无故丢失,重复数据出现的莫名其妙,因为生产网不能随意测试,所以每次出错都很难过,而测试网又复现不了(测试网数据是伪造的),心都碎了,最后又重新看代码,决定打印最详细的日志。主要是两个地方:
- Map的put操作前,先containsKey一下,如果有,打印日志说已有数据
- 之前打印数量日志的,全部打印实际内容
第二步,按我之前的风格,是绝对不会这么做的,感觉太低级,但是这么实在是没有办法了,然后重新测试,仔细看日志,发现一个异常现象,数据实际内容没有看,太多了,异常的是出现大量的已有数据的日志,这点引起我的注意,我核实过数据源,我这边提示重复的数据,在数据源处只有一个,然后我就去看我的工具类,查询工具类,发现了问题,程序如下:
batchSize在前边定义的为1000,及1000个批次查询一次 ================================ public static List<String> queryAll(String[] index,String types){ long count=count(index,types); List<String> result=new ArrayList<>(); while(count>0){ int from=0; <========== int size=0; if(count>batchSize){ size=batchSize; count-=batchSize; }else{ size=(int) count; count=0; } //通过 from 和 size 查询数据 并放到result中 from +=size; } return result; }
仔细看标红那一行,我终于找到错误原因了,我的同步类没有错,查询es的工具类写错了,改了以后重试才可以。
三、教训总结
3.1 工具类的使用
平时积累一些工具类,确实可以大大减少一般开发的工作量,但是一定要经过严格的测试,不然基于对工具类的信任,很少会怀疑工具类会出错。
3.2 数据处理
对于数据处理,如果假定不会有相同数据,也要containsKey一些,因为往往会有意想不到的数据产出,这种情况下出错了还不好查询。