问题
客户端发出请求,通过网关访问项目A的接口获取资源数据,访问超时,报504
解决过程
- 第一步:在项目A中先对接口进行单测,并打印耗时时间,显示500毫秒,故确认非接口性能问题
- 第二步:网关调用远程调试项目A,在客户端发起请求至项目A该接口返回最终数据,时间只在一瞬间,故确认问题出在网关接收返回数据的环节
- 第三步:远程调试网关,将断点定位在网关获取到项目A返回数据的那行代码,一步一步走下去,发现反序列返回数据的方法抛出StackOverflowError异常
- StackOverflowError是栈溢出异常,发生原因是方法调用太多,栈空间不够用,常见于递归调用
- 第四步:检查返回数据,发现返回数据内部一个属性值指向外部类的引用,发生了死循环引用,示例结构如下
data = {A@8281}{
name = "名称外部"
child = {Child@8284}{
name = "名称内部"
this$0 = {A@8281}{
name = "名称外部"
child = {Child@8284}{
...省略...循环
}
}
}
}
- 第五步:定位到问题出在返回数据出现了内部递归指向,即网关在反序列化返回数据时,先创建了A,然后创建A的属性name、child,但是属性child的属性又指向A,于是又初始化A属性,造成了死循环调用,最终抛出StackOverflowError异常
- 第六步:回到项目A检查返回数据的数据结构,发现发生递归引用的那个属性的类型是一个内部类,经查阅,了解到内部类在创建时会默认拥有一个外部类实例的引用,故将内部类改成静态内部类,问题解决
解决思路
- 先排查项目接口本身是否有问题
- 然后网关调用接口,判断接口返回速度是否有问题
- 最后定位到网关返回环节有问题
- 根据该环节所报异常排查最终问题