先说结论:

golang 关于较大规模且复杂结构的json反序列化时,可以考虑分两步的方式:先只反序列化key,然后再按需取key对应的结构再进行反序列化。这样可以避免一次性反序列化完整的结构导致性能出现巨大损耗。

问题背景:

最近收到内存告警,一个平常极其稳定的用于数据采集的服务出现OOM,经过排查并不是内存泄露,就是单纯的大数据量情况下反序列化内存不够用。

数据采用map[string]map[string]string方式接收进行动态反序列化,因为接口返回的异常,导致返回的json结构大小暴涨六十倍以上。pprof发现性能损失就在Unmarshal阶段,由于接受对象是map结构而非明确定义的struct,导致内存copy严重,临时对象过多。

解决办法:

考虑到实际使用的是其中部分key,就进行先只反序列化key。因此采map[string]json.RawMessage(其实就是map[string][]byte)的结构,先获取key,然后按需反序序列化key对应的value。实测,性能有巨大提升。

效果如下: