美文网首页
记一次Avro序列化bug

记一次Avro序列化bug

作者: 意梦春秋 | 来源:发表于2018-09-30 11:12 被阅读0次

bug描述

Avro 序列化 Event长度超过63后 反序列化失败

问题定位

1.程序中将avro序列化后的byte数组转了String又转了byte[]然后进行反序列化,在len>63时 两个byte[]出现了不一致

byte[] b = new String(f.serializeEvent(e, true)).getBytes()

初步判断编码方式的问题导致了byte数组的不一致
经过网上查询和亲自实践,在默认UTF-8编码下 如果byte有小于0的值,UTF-8会将它转为[char]0xFFFD 再次转byte时转为[-17,-65,-67]
关键代码如下

//CharsetDecoder line 229
protected CharsetDecoder(Charset cs,
                             float averageCharsPerByte,
                             float maxCharsPerByte)
    {
        this(cs,
             averageCharsPerByte, maxCharsPerByte,
             "\uFFFD");
    }
// UTF_8.class line 393
 else {
                                     if (this.malformedInputAction() != CodingErrorAction.REPLACE) {
                                            return -1;
                                        }

                                        if (var2 >= var5 || !isMalformed3_2(var9, var1[var2])) {
                                            var4[var6++] = this.replacement().charAt(0);
                                            return var6;
                                        }

                                        var4[var6++] = this.replacement().charAt(0);
                                    }
UTF_8.class line 559
var6[var7++] = (byte)(224 | var10 >> 12);
var6[var7++] = (byte)(128 | var10 >> 6 & 63);
var6[var7++] = (byte)(128 | var10 & 63);

如果不将byte[]转String 再转byte[]问题可以得到解决
但是为什么长度会影响呢?
我们查看序列化的代码 序列化bytes类型时代码如下

// BinaryEncoder.java line 59
  public void writeBytes(ByteBuffer bytes) throws IOException {
    int len = bytes.limit() - bytes.position();
    if (0 == len) {
      writeZero();
    } else {
      writeInt(len);
      writeFixed(bytes);
    }
  }

根据问题描述 应该出在写入长度上
查看代码

// DirectBinaryEncoder.java line 72
public void writeInt(int n) throws IOException {
    int val = (n << 1) ^ (n >> 31);
    if ((val & ~0x7F) == 0) {
      out.write(val);
      return;
    } else if ((val & ~0x3FFF) == 0) {
      out.write(0x80 | val);
      out.write(val >>> 7);
      return;
    }
    int len = BinaryData.encodeInt(n, buf, 0);
    out.write(buf, 0, len);
  }

首先 将len乘以2赋值到val
判断 val是否小于128(这就是63存在的原因) 大于128进入第一个else
将byte符号位置1后写入 这时候 就写入了负值 导致了问题的产生!

问题解决

  • 不使用byte转string再转回来
  • 使用ISO8859-1编码方式进行转换

相关文章

网友评论

      本文标题:记一次Avro序列化bug

      本文链接:https://www.haomeiwen.com/subject/mxtwoftx.html