最近在进行fregata2.0重构时,再次优化avro的反序列化过程。

背景

fregata-quasi任务是典型的cpu和内存都高度消耗的场景,主要是数据的

序列化和反序列化。通过JFR多次观测,其中一个热点是avro中的字符串类型

数据的处理(实际数据中字符串类型出现的比较多,201712的blog也提到过)。

问题源码

对相关代码进行分析后,把目光落在这个区域。

if (length < 0)
    throw new AvroRuntimeException("Malformed data. Length is negative: "+ length);
int remaining = limit - pos;
if (length <= remaining) {
    System.arraycopy(buf, pos, bytes, start, length);
    pos += length;
} else {
    // read the rest of the buffer
    System.arraycopy(buf, pos, bytes, start, remaining);
    start += remaining;
    length -= remaining;
    pos = limit;
    // finish from the byte source
    source.readRaw(bytes, start, length);
}

在字符串处理中,Avro引入了一个UTF8对象(本质就是一个byte数组),

在经过这段代码后,再将UTF8对象转为String,经过string的decode。

优化

int start = 0;
int length = readInt();
if (length < 0) {
    throw new AvroRuntimeException("Malformed data length : " + length);
}
int remaining = limit - pos;
if (length <= remaining) {
    result = new String(buf, pos, length);
    pos += length;
} else {
    //read the rest of the buffer
    result = new String(buf, pos, remaining);
    start += remaining;
    length -= remaining;
    pos = limit;
    //finish from the byte source
    source.readRaw(null, start, length);
}

这里主要是省掉了中间的UTF8对象,减少了一次System.arraycopy

结论

经过测试,这个优化可以提升10%左右的反序列化速度。