南宁建站免费模板,低价货源网站,哪个网站专门做二手电脑手机的,wordpress 不同页面不同侧边栏背景
目前本人在公司负责的模块中#xff0c;有一个模块是负责数据同步的#xff0c;主要是将我们数据产线使用的 AWS Dynamodb 同步的我们的测试QA 的环境的 MongoDB 的库中#xff0c;去年开始也提供了使用 EMR 批量同步的功能#xff0c;但是有时候业务也需要少量的数据…背景
目前本人在公司负责的模块中有一个模块是负责数据同步的主要是将我们数据产线使用的 AWS Dynamodb 同步的我们的测试QA 的环境的 MongoDB 的库中去年开始也提供了使用 EMR 批量同步的功能但是有时候业务也需要少量的数据进行同步测试所以也通过了抽样数据同步的功能。
过程
本周的时候LS项目研发的同事和我反馈一个问题主要是表现是发现同步到MongoDB库中的部分表的字段有问题下游没法解析使用随后我就开始排查代码 看下的这边同步的部分代码
/*** Synchronizes data by rewriting from source to sink database.** param syncMessage The message model containing synchronization details.* param source_db The source DynamoDB client.* param sink_db The sink DynamoDB client.* param parameters Parameters for querying the source database.* return The number of successful sync operations.*/private static int syncDataByRewrite(SyncPartDDBMessageModel syncMessage, AmazonDynamoDBClient source_db, AmazonDynamoDBClient sink_db, ListString parameters) {int syncSuccessCount 0;String table_name syncMessage.getTable_name();ListMapString, AttributeValue sync_items new ArrayList();for (String parameter : parameters) {QueryResult queryResult queryDataFromSource(source_db, syncMessage, parameter);if (queryResult ! null queryResult.getItems() ! null !queryResult.getItems().isEmpty()) {sync_items.addAll(queryResult.getItems());syncSuccessCount;}}try {log.info(start sync data: JSON.toJSONString(sync_items));AWSDynamoDBUtils.batchWrite(sink_db, table_name, sync_items);} catch (Exception e) {log.error(Error syncing data for table {}: {}, table_name, e.getMessage(), e);}return syncSuccessCount;}其实核心代码就如上面一样咋一看这段代码是没有问题的因为之前我也对齐进行过测试数据同步也是 OK 的后来同事和我说 正常的字段都是 OK 的但是 Binary 类型的字段存在问题由于公司的之前使用的 Dynamodb的数据库Dynamodb对每个 Item 的大小有限制即512K为了更多存储减少不必要的 Chunk,我们将很多大的字段进行的 GZIP 压缩后用二进制的Binary 存储。
定位问题
当我听到是 Binary 类型的字段有问题的时候第一反应是 想是不是我们的 proxy 有问题因为我这边使用的了写 Mongodb 适配Dynamodb 的 proxy, 后来问了组件的同事说代码也已经很久没问题了应该没问题的~ 后来也是考虑是不是batchWrite的底层写得有问题也是各种猜测去定位问题浪费了很长时间 后来无意之前我注释了下代码仅仅 就注释了一行代码你们猜是什么 ·· ·· ·· 就是 log.info(“start sync data:” JSON.toJSONString(sync_items)); 对我注释了一样记录日志的代码居然程序没问题了这搞的我很尴尬哎呀
寻找问题的根源
最近也比较忙当时定位到问题后我想找找为什么会这样~ 刚好今天周六有时间我吧 FastJson 的源码来了来我调试看下我使用的版本是 fastjson2 git:(2.0.26)
测试
在实际我们的数据同步过程中MapString, AttributeValue 里面的AttributeValue 是 Dynamodb返回的实体对象是一个比较复杂的对象我就不使用了我这边只是测试了Buffer的 Testpublic void testBufferObjectToJsonString1() throws Exception {String drugId 53b8acd8694f4ddabefc76b3a6d58976;ByteBuffer byteBuffer compressString(drugId);System.out.println(byteBuffer: byteBuffer);System.out.println(drugIdJSONString: JSON.toJSONString(byteBuffer));System.out.println(byteBuffer2: byteBuffer);System.out.println(drugIdJSONString2: JSON.toJSONString(byteBuffer));}Testpublic void testBufferObjectToJsonString2() throws Exception {String drugId 53b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d58976;ByteBuffer byteBuffer compressString(drugId);System.out.println(byteBuffer: byteBuffer);System.out.println(drugIdJSONString: JSON.toJSONString(byteBuffer));System.out.println(byteBuffer2: byteBuffer);System.out.println(drugIdJSONString2: JSON.toJSONString(byteBuffer));}可以给大家看下 这2个测试方法的返回 第一个测试的返回
byteBuffer:java.nio.HeapByteBuffer[pos0 lim32 cap32]
drugIdJSONString:{char:㔳,direct:false,double:1.4039733842967137E165,float:2.1439479E-7,int:1684103781,long:7377801321278300470,readOnly:false,short:25653}
byteBuffer2:java.nio.HeapByteBuffer[pos28 lim32 cap32]com.alibaba.fastjson.JSONException: toJSONString errorat com.alibaba.fastjson.JSON.toJSONString(JSON.java:1477)at com.patsnap.data.process.platform.job.syncPartDDB.SyncPartDDBJobTest.testBufferObjectToJsonString1(SyncPartDDBJobTest.java:143)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at junit.framework.TestCase.runTest(TestCase.java:176)at junit.framework.TestCase.runBare(TestCase.java:141)at junit.framework.TestResult$1.protect(TestResult.java:122)at junit.framework.TestResult.runProtected(TestResult.java:142)at junit.framework.TestResult.run(TestResult.java:125)at junit.framework.TestCase.run(TestCase.java:129)at junit.framework.TestSuite.runTest(TestSuite.java:252)at junit.framework.TestSuite.run(TestSuite.java:247)at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: java.nio.BufferUnderflowExceptionat java.nio.Buffer.nextGetIndex(Buffer.java:510)at java.nio.HeapByteBuffer.getDouble(HeapByteBuffer.java:531)at com.alibaba.fastjson2.writer.FieldWriterDoubleValueFunc.write(FieldWriterDoubleValueFunc.java:44)at com.alibaba.fastjson2.writer.ObjectWriter8.write(ObjectWriter8.java:97)at com.alibaba.fastjson.JSON.toJSONString(JSON.java:1469)... 21 more第二个测试的返回
byteBuffer:java.nio.HeapByteBuffer[pos0 lim96 cap96]
drugIdJSONString:{char:㔳,direct:false,double:1.4039733842967137E165,float:2.1439479E-7,int:1684103781,long:7377801321278300470,readOnly:false,short:25653}
byteBuffer2:java.nio.HeapByteBuffer[pos28 lim96 cap96]
drugIdJSONString2:{char:㠹,direct:false,double:9.958328793464587E-43,float:1.3592432E22,int:879113316,long:7233170664182724406,readOnly:false,short:25139}第一个测试居然报错了从报错的堆栈上看java.nio.HeapByteBuffer.getDouble(HeapByteBuffer.java:531)这个异常了 第二个测试没有报错但是存在问题就是明显2个对象不一样了我们从第二个HeapByteBuffer的position的值可以看到他的值偏移了说明了什么 说明了 FastJosn 读取了ByteBuffer的内容但是没有做buffer rewind重置位置的操作这也太坑了
查看源码
static String toJSONString(Object object) {
JSONWriter.Context writeContext new JSONWriter.Context(JSONFactory.defaultObjectWriterProvider);boolean pretty (writeContext.features JSONWriter.Feature.PrettyFormat.mask) ! 0;JSONWriter jsonWriter;
if (JVM_VERSION 8) {jsonWriter new JSONWriterUTF16JDK8(writeContext);
} else if ((writeContext.features JSONWriter.Feature.OptimizedForAscii.mask) ! 0) {....
} else {....
}try (JSONWriter writer pretty ?new JSONWriterPretty(jsonWriter) : jsonWriter) {if (object null) {writer.writeNull();} else {writer.rootObject object;writer.path JSONWriter.Path.ROOT;Class? valueClass object.getClass();if (valueClass JSONObject.class) {writer.write((JSONObject) object);} else {JSONWriter.Context context writer.context;boolean fieldBased (context.features JSONWriter.Feature.FieldBased.mask) ! 0;ObjectWriter? objectWriter context.provider.getObjectWriter(valueClass, valueClass, fieldBased);objectWriter.write(writer, object, null, null, 0);}}return writer.toString();
} catch (NullPointerException | NumberFormatException e) {throw new JSONException(JSON#toJSONString cannot serialize object , e);
}
}上面的toJSONString的部分代码的截取主要是看 objectWriter.write(writer, object, null, null, 0);这个地方的实现最终我调试发现调用了com.alibaba.fastjson2.writer.ObjectWriter8 里面的 write方法 Overridepublic void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {long featuresAll features | this.features | jsonWriter.getFeatures();boolean beanToArray (featuresAll BeanToArray.mask) ! 0;if (jsonWriter.jsonb) {if (beanToArray) {writeArrayMappingJSONB(jsonWriter, object, fieldName, fieldType, features);return;}writeJSONB(jsonWriter, object, fieldName, fieldType, features);return;}if (beanToArray) {writeArrayMapping(jsonWriter, object, fieldName, fieldType, features | this.features);return;}if (!serializable) {if ((featuresAll JSONWriter.Feature.ErrorOnNoneSerializable.mask) ! 0) {errorOnNoneSerializable();return;}if ((featuresAll JSONWriter.Feature.IgnoreNoneSerializable.mask) ! 0) {jsonWriter.writeNull();return;}}if (hasFilter(jsonWriter)) {writeWithFilter(jsonWriter, object, fieldName, fieldType, 0);return;}jsonWriter.startObject();if (((features | this.features) WriteClassName.mask) ! 0 || jsonWriter.isWriteTypeInfo(object, features)) {writeTypeInfo(jsonWriter);}fieldWriter0.write(jsonWriter, object);fieldWriter1.write(jsonWriter, object);fieldWriter2.write(jsonWriter, object);fieldWriter3.write(jsonWriter, object);fieldWriter4.write(jsonWriter, object);fieldWriter5.write(jsonWriter, object);fieldWriter6.write(jsonWriter, object);fieldWriter7.write(jsonWriter, object);jsonWriter.endObject();}最终代码是执行了fieldWriter0到fieldWriter7的8个方式这也解释了 我们的为什么我们打印的 Bytebuffer类型是这样的
{char:㔳,direct:false,double:1.4039733842967137E165,float:2.1439479E-7,int:1684103781,long:7377801321278300470,readOnly:false,short:25653
}这边也是刚好8个方式加起来读取了28 这边也同能解释了我第一个测试方式为什么会报错再回头看下我第一个的 buffer 对象byteBuffer:java.nio.HeapByteBuffer[pos0 lim32 cap32] byteBuffer2:java.nio.HeapByteBuffer[pos28 lim32 cap32] 为什么第二次 toJSONString 的错误就是因为读取的位置不够了~所以在第一个测试在at java.nio.HeapByteBuffer.getDouble(HeapByteBuffer.java:531)的位置发送了错误也应对了上面的源码的逻辑
解决方法
如果是的执行方法在使用toJSONString之前的那是没有问题的正常我们读取 buffer 完成后的会重置位置或者使用一个输出流去接收然后再去读取也是没有问题的或者使用 ByteBuffer wrap ByteBuffer.wrap(byteBuffer.array()); 也是没有问题的 当然你如果想要解决这个toJSONString的错误也是可以的正常我们都会将二进制使用 base64来表示的这样就不存在问题 上代码
public class ByteBufferValueFilter implements ValueFilter {Overridepublic Object process(Object object, String name, Object value) {if (value instanceof ByteBuffer) {ByteBuffer buffer (ByteBuffer) value;byte[] bytes new byte[buffer.remaining()];buffer.get(bytes); // 读取剩余的字节buffer.rewind(); // 重置 position 到起始位置return Base64.getEncoder().encodeToString(bytes);}return value;}
}是可以解决的
后续
这个问题其实我在官方的issues也找到了这个问题https://github.com/alibaba/fastjson/issues/2357 下面的回复是已经解决了这个问题的但是我使用的2.0.26 居然还有这个问题 我就顺便测试了1.2.83版本这个也是2.0.26版本引用之前1.X的fastjson 的版本 Test
public void testBufferObjectToJsonString2() throws Exception {String drugId 53b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d58976;ByteBuffer byteBuffer compressString(drugId);System.out.println(byteBuffer: byteBuffer);System.out.println(drugIdJSONString: com.alibaba.fastjson.JSON.toJSONString(byteBuffer));System.out.println(byteBuffer2: byteBuffer);System.out.println(drugIdJSONString2: JSON.toJSONString(byteBuffer));
}输出
byteBuffer:java.nio.HeapByteBuffer[pos0 lim96 cap96]
drugIdJSONString:{array:NTNiOGFjZDg2OTRmNGRkYWJlZmM3NmIzYTZkNTg5NzY1M2I4YWNkODY5NGY0ZGRhYmVmYzc2YjNhNmQ1ODk3NjUzYjhhY2Q4Njk0ZjRkZGFiZWZjNzZiM2E2ZDU4OTc2,limit:96,position:0}
byteBuffer2:java.nio.HeapByteBuffer[pos0 lim96 cap96]
drugIdJSONString2:{char:㔳,direct:false,double:1.4039733842967137E165,float:2.1439479E-7,int:1684103781,long:7377801321278300470,readOnly:false,short:25653}可以看到 在之前的做法也是将二进制去 base64表示的不知道为什么在2.0.26 还会出现上面的问题 那我就顺便去官方 提一个issues吧https://github.com/alibaba/fastjson2/issues/2877 后面看下是否会修复这个问题
总结
回顾上面其实最大的一个问题就是在记录日志的时候不应该添加在代码执行逻辑之前这是一个不好的代码习惯应该将日志记录放在代码执行逻辑之后。此外代码的测试用例要做全排查代码的时候定位问题的时候 更加敏锐些。 文章转载自: http://www.morning.tqygx.cn.gov.cn.tqygx.cn http://www.morning.rkyw.cn.gov.cn.rkyw.cn http://www.morning.dxxnq.cn.gov.cn.dxxnq.cn http://www.morning.pwmm.cn.gov.cn.pwmm.cn http://www.morning.gnfkl.cn.gov.cn.gnfkl.cn http://www.morning.hyhzt.cn.gov.cn.hyhzt.cn http://www.morning.kkwgg.cn.gov.cn.kkwgg.cn http://www.morning.rpzth.cn.gov.cn.rpzth.cn http://www.morning.ybgcn.cn.gov.cn.ybgcn.cn http://www.morning.kjgdm.cn.gov.cn.kjgdm.cn http://www.morning.twpq.cn.gov.cn.twpq.cn http://www.morning.phlwj.cn.gov.cn.phlwj.cn http://www.morning.nwllb.cn.gov.cn.nwllb.cn http://www.morning.rwfp.cn.gov.cn.rwfp.cn http://www.morning.dtgjt.cn.gov.cn.dtgjt.cn http://www.morning.wqrdx.cn.gov.cn.wqrdx.cn http://www.morning.hfrbt.cn.gov.cn.hfrbt.cn http://www.morning.pycpt.cn.gov.cn.pycpt.cn http://www.morning.mlzyx.cn.gov.cn.mlzyx.cn http://www.morning.xqcgb.cn.gov.cn.xqcgb.cn http://www.morning.mtgnd.cn.gov.cn.mtgnd.cn http://www.morning.xhddb.cn.gov.cn.xhddb.cn http://www.morning.kjsft.cn.gov.cn.kjsft.cn http://www.morning.ygztf.cn.gov.cn.ygztf.cn http://www.morning.dbrpl.cn.gov.cn.dbrpl.cn http://www.morning.ptlwt.cn.gov.cn.ptlwt.cn http://www.morning.grqlc.cn.gov.cn.grqlc.cn http://www.morning.jhwqp.cn.gov.cn.jhwqp.cn http://www.morning.bynf.cn.gov.cn.bynf.cn http://www.morning.pznnt.cn.gov.cn.pznnt.cn http://www.morning.tjcgl.cn.gov.cn.tjcgl.cn http://www.morning.rqwwm.cn.gov.cn.rqwwm.cn http://www.morning.rjmd.cn.gov.cn.rjmd.cn http://www.morning.qhmgq.cn.gov.cn.qhmgq.cn http://www.morning.mnrqq.cn.gov.cn.mnrqq.cn http://www.morning.krlsz.cn.gov.cn.krlsz.cn http://www.morning.lsmgl.cn.gov.cn.lsmgl.cn http://www.morning.ndrzq.cn.gov.cn.ndrzq.cn http://www.morning.okiner.com.gov.cn.okiner.com http://www.morning.hffpy.cn.gov.cn.hffpy.cn http://www.morning.rwls.cn.gov.cn.rwls.cn http://www.morning.lyhry.cn.gov.cn.lyhry.cn http://www.morning.kttbx.cn.gov.cn.kttbx.cn http://www.morning.bhxzx.cn.gov.cn.bhxzx.cn http://www.morning.jmspy.cn.gov.cn.jmspy.cn http://www.morning.zpstm.cn.gov.cn.zpstm.cn http://www.morning.rmryl.cn.gov.cn.rmryl.cn http://www.morning.qdrhf.cn.gov.cn.qdrhf.cn http://www.morning.tbplf.cn.gov.cn.tbplf.cn http://www.morning.xdpjf.cn.gov.cn.xdpjf.cn http://www.morning.ptdzm.cn.gov.cn.ptdzm.cn http://www.morning.qpnb.cn.gov.cn.qpnb.cn http://www.morning.rnqnp.cn.gov.cn.rnqnp.cn http://www.morning.rkfgx.cn.gov.cn.rkfgx.cn http://www.morning.zlfxp.cn.gov.cn.zlfxp.cn http://www.morning.mttck.cn.gov.cn.mttck.cn http://www.morning.fwcnx.cn.gov.cn.fwcnx.cn http://www.morning.pyzt.cn.gov.cn.pyzt.cn http://www.morning.pabxcp.com.gov.cn.pabxcp.com http://www.morning.tfzjl.cn.gov.cn.tfzjl.cn http://www.morning.rjnky.cn.gov.cn.rjnky.cn http://www.morning.kqylg.cn.gov.cn.kqylg.cn http://www.morning.tpfny.cn.gov.cn.tpfny.cn http://www.morning.wbllx.cn.gov.cn.wbllx.cn http://www.morning.smfbw.cn.gov.cn.smfbw.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.nwczt.cn.gov.cn.nwczt.cn http://www.morning.nafdmx.cn.gov.cn.nafdmx.cn http://www.morning.sfwfk.cn.gov.cn.sfwfk.cn http://www.morning.czzpm.cn.gov.cn.czzpm.cn http://www.morning.fksrg.cn.gov.cn.fksrg.cn http://www.morning.nmhpq.cn.gov.cn.nmhpq.cn http://www.morning.gfprf.cn.gov.cn.gfprf.cn http://www.morning.woyoua.com.gov.cn.woyoua.com http://www.morning.gxklx.cn.gov.cn.gxklx.cn http://www.morning.yhdqq.cn.gov.cn.yhdqq.cn http://www.morning.bzjpn.cn.gov.cn.bzjpn.cn http://www.morning.lyzwdt.com.gov.cn.lyzwdt.com http://www.morning.xyjlh.cn.gov.cn.xyjlh.cn http://www.morning.ntcmrn.cn.gov.cn.ntcmrn.cn