protocol buffers[1]是google提供的一种将结构化数据进行序列化和反序列化的方法,其优点是语言中立,平台中立,可扩展性好,目前在google内部大量用于数据存储,通讯协议等方面。PB在功能上类似XML,但是序列化后的数据更小,解析更快,使用上更简单。用户只要按照proto语法在.proto文件中定义好数据的结构,就可以使用PB提供的工具(protoc)自动生成处理数据的代码,使用这些代码就能在程序中方便的通过各种数据流读写数据。PB目前支持Java, C++和Python3种语言。另外,PB还提供了很好的向后兼容,即旧版本的程序可以正常处理新版本的数据,新版本的程序也能正常处理旧版本的数据。
笔者在项目的测试过程中,遇到了一个protocal buffer使用不当倒是的模块内存不断上涨的问题。这里和大家分享一下问题的定位、分析以及解决过程。
1. 问题现象
5月,出现问题的模块(以下成为模块)内存有泄露的嫌疑,表现为程序在启动后内存一直在缓慢的上涨。由于该模块每天都存在重启的操作,因此没有带来较大的影响。
8月,发现线上模块的内存上涨速度加快。
9月,模块线上出现内存报警。内存使用量从启动时的40G,在70小时左右上涨到50G,由于会出现OOM的风险,模块不得不频繁重启。
9月底,模块的某个版本上线后,由于内存使用量稍有增加,导致程序在启动后不到24小时内就出现内存报警,线上程序的稳定受到非常大的影响。线上程序回滚,并且停止该模块的所有功能迭代,直到内存问题解决为止。
模块是整个系统最核心的模块,业务的停止迭代对产品的研发效率影响巨大。问题亟需解决!
2. 问题复现
出现这种问题后,首先要做的就是在线下复现问题,这样才能更好的定位问题,并且能够快速的验证问题修复的效果。但是经过多天的尝试,在QA的测试环境中,模块的内存表现情况均与线上不一致。具体表现为:
1)线上模块的内存一直在上涨,直到机器内存耗尽,模块重启;线下模块的内存在压力持续若干小时后就趋于稳定,不再上涨。
2)线下环境中,模块的内存上涨速度没有线上快。
出现这两种情况的原因后面再解释。线上线下表现的不一致给问题的复现和效果验证带来了一定的困难。但好在在线下环境中内存使用量依然是上涨的,可以用来定位问题。