-
Gateway2.0基本介绍
- 使用reactor-netty作为网络模型。
- 全程为reactor 编程方式。
-
问题报错信息
-
问题现象
-
服务上线不久隔断时间就会无法访问,假死。
-
初期解决方案:定时重启服务。
- 原因:业务需求压力过大,无精力深入排查该问题。且问题发生不严重。
-
-
-
内存快照
-
问题复现
-
拿到代码,构建一个docker镜像,部署测试。
- 设置 JVM最大内存为 256M
- Jmeter 压测
-
-
复现结果
- 压测1.5个小时后,开始报错。 报错内容于 线上运行时异常一致。
问题分析
-
内存快照分析
- 明明已经使用到内存溢出了,但是内存快照才33M大小。
- 出现最多的为循环嵌套对象finalizer。
-
参考:
- 网络资料排查过程中,可以通过内存快照对象直接定位到哪里使用的这个对象,直接定位到问题点。
-
实际情况:
- 无限循环嵌套。无法定位到到底是哪里使用的这个对象。
-
代码检查
-
发现的问题
- 使用了redis
- 在网关中提供了API接口
- 在引入gateway的同时还引入了zuul
- 同时还引入了 spring-boot-starter-web
-
深入排查
- 在压测中第一个报错的信息为
-
问题分析
- ResourceLeakDetector 为 netty 内存泄漏检测机制 ,默认为1%的抽样检查。
- 可以得到信息,netty 发送了内存泄露。
- 但是,这只能说明是内存泄露了,但是定位不到泄露点。
- 问题开始变为定位泄露点。
-
继续压测后得到线上错误日志
- [网关异常处理]请求路径:/stars/cust/api/communicate/queryRecordByItemCode,异常信息:io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 16777216 byte(s) of direct
- memory (used: 1895825415, max: 1908932608)
- 当前日志同样定位不到泄露点
-
代码位置
- 把堆栈信息吃掉了!吃掉了!
-
信息分析
-
得到已知信息
- 确认为netty 内存泄露照成的服务不可用
- netty 使用的内存为 堆外内存(直接内存)
-
-
继续调整压测
- 修改 jvm 启动参数 -XX:MaxDirectMemorySize=50M 缩减固定堆外内存大小
-
新的问题出现
- 加入堆栈异常输入后 日志报错为 netty rides 内存溢出!
- 并未保留日志与截图,就不提供了。
-
新问题排查
- 百度得到的信息是 spring-boot-starter-data-redis 组件使用了netty为通讯模块,排查掉netty后 ,使用jedis,不在报错。
-
继续压测
- 问题并未解决,还是netty内存溢出。
-
逐行百度相关信息
- 网络上有报相同错误的,但是都说Netty 特定版本有问题,我们使用相关依赖并非该版本
-
继续压测
-
调整内容
- 只压测 getaway本身,将相关依赖全部去掉,排查是否 为getaway本身问题。
-
压测结果
- Getaway 本身无问题,不报错。
-
-
信息分析
- 既然getaway 本身没有问题,必然是相关依赖出现了问题。照成了 响应结果没释放引起的内存溢出。
-
继续排查
-
发现矛盾点
- 在内存快照中, netty 与 tomcat相关对象都有被创建。
- 初步还以为引入的 spring-boot-starter-web 的tomcat 照成的问题。
-
-
继续压测
-
调整内容
- 排除 spring-boot-starter-web 的 tomcat 相关依赖引用
-
-
结果
- 不在报错!!!!
-
排查结果
- getaway 2.0 使用的是 netty 做为容器, 在引入 spring-boot-starter-web 组件的时候会引入 tomcat 容器。
- tomcat 内对象也被创建了,在响应的时候,照成了netty 与 tomcat 类相关使用的问题。
-
从内存快照中其实也可以看到的,当时并未特别注意。
-
解决方案
-
排除 spring-boot-starter-web 的 tomcat 相关依赖引用
-
-
问题延时
- 打异常的时候,能打堆栈信息,就一定要打出来!要不真的不好排除定位问题!
- 在不是特别了解的情况下,那就劲量做到模块单一原则。让getaway 只做网关自己的事情!