我们有一个大小为 1.4MB 的 XML 文档,我们对其进行 gzip 压缩并编码为 Base64 并保存在 cosmos 中。收到一些更新后,我们读取 cosmos,从 Base64 解码并解压缩以获取原始字符串。我们观察到的是,在某些高负载下,倾斜的撇号字符在更新处理时保存在 cosmos 中时会创建垃圾数据。 Base64 编码数据看起来像 -
/F9nYk3vKlhqHb65KybqXTJfLvTvuy24HFwOq1wOT55oEkdJ+0bmcuWJJisvbfanpsb7//2//w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA........
然后解码,解压,这会导致 OOM,其大小会随着这个字符增长到 GB � 就像
�����������������������������
编码和 gzip 的逻辑
String compressed;
try (var baos = new ByteArrayOutputStream(); var gzipOut = new GZIPOutputStream(baos);) {
gzipOut.write(data.getBytes(StandardCharsets.UTF_8));
gzipOut.close();
compressed = new String(Base64.getEncoder().encode( baos.toByteArray()));
} catch (IOException e) {
throw new FOSInjestorApplicationException(Errors.UNEXPECTED_ERROR
, Errors.UNEXPECTED_ERROR.getDescription());
}
解码和解压逻辑
byte[] decodebase64 = Base64.getDecoder().decode(arr);
byte[] gzip;
try (var bais = new ByteArrayInputStream(arr); var gzip = new GZIPInputStream(bais);) {
gzip = gzip.readAllBytes();
} catch (IOException e) {
throw new FOSInjestorApplicationException(Errors.UNEXPECTED_ERROR
, Errors.UNEXPECTED_ERROR.getDescription());
}
return new String(gzip);
当我们将这个带有倾斜撇号的相同文档放在非产品中时,它工作正常。
我正在使用 java 11 和 java cosmos 4.x SDK 什么会导致它在高负载下失败?
我们尝试在具有特殊字符(倾斜撇号)的文档上处理太多更新(一次 1 个),并且更新不应损坏数据,但我们在解码/解压缩后发现了这个垃圾字符 -
�����������������������������
其不断增长大小变为 1 GB 并给出 OOM
因此,在检查为什么解码和解压缩然后压缩和编码会产生这个倾斜撇号的问题时,我们发现 JAVA11 使用默认的 UTF-16 文件编码,而我们的应用程序 VM 使用一些 ISO-8859-1 文件编码。因此,这些编码不理解倾斜的撇号,并且当我们进行 zip-unzip 操作时,其大小是垃圾字符的大小??????随着每次更新呈指数增长,最后,如果解压和解码的大小增长到 1GB,或者在 cosmos 中保存了 2MB 垃圾有效负载,则应用程序会看到 OOM 错误。 修复方法是显式添加 -Dfile.encoding=UTF-8 JVM 参数,并观察到特殊字符(倾斜撇号)被正确读入撇号 '