如何快速排查生产问题
大家都遇到过哪些生产问题呢

  1. 磁盘满了?
  2. CPU 飙高?
  3. 内存溢出?

内存溢出又分好几种:
堆内存溢出、
元空间溢出、
线程栈溢出、
直接内存溢出。

在 Netty 中,最常见的当属直接内存溢出了,而内存溢出,往往又是内存泄漏导致的,所以,我们一般是排查内存泄漏。
那么,对于直接内存泄漏,我们该如何快速排查呢?这里,我总结了几个步骤以供参考:
1 查看监控,直接内存使用情况是否稳定;
2 查看日志,是否有直接内存相关的报错;
3 本地调试,关闭池化内存、添加内存泄漏检测、模拟大量请求、步步为营、耐心寻找泄漏点;
所以,我们这里多次使用的时候需要显式地给 msg 加一次引用次数,但是,一不小心,我手抖了一下,多加了一次引用次数就发到生产上了,会出现什么样的情况呢?
首先,程序是肯定可以正常运行的。
其次,内存溢出是一个非常缓慢的过程,可能十天半个月才会出现一次。
最后,导致的结果就是难以排查,无奈之下,只能重启,甚至,有的公司会写个定时任务,每天晚上系统没人用的时候偷偷地自动重启一次。
针对这种情况,我们来看看怎么排查。

1查看监控
查看监控,会发现,直接内存的使用情况,呈现一条缓慢上升的曲线,类似于这样:
这个时间的长度可能是几个小时、一天、几天、十几天,都有可能,取决于系统的流量,随着时间的推移,最终达到了监控告警值,半夜被喊起来排查问题。

2查看日志
遇到这种问题先不要慌,先去日志中查看是否有直接内存相关的报错,如果运气好是有相关日志的,拿出来分析一波,最坏的情况是完全没有,在完全没有日志可以参考的情况下,只能启用本地调试大法了。

3本地调试
本地调试不是说拿到代码胡乱调试一通,也要讲究一些策略。

第一步,关闭池化内存,为什么要关闭池化内存?
因为,使用池化内存的时候,创建第一个 ByteBuf 的时候会分配 16M 的内存块,等这 16M 的内存块不够使用的时候才会创建下一个 16M 的内存块,而且,这 16M 使用完了之后并不会立即释放,而是交给 Netty 的内存来进行管理,方便后续复用,有内存池的干扰,很难看出内存泄漏导致的直接内存缓慢增长的过程。
那么,要怎么关闭池化内存呢?
这就要使用到前面章节讲过的一个参数了:-Dio.netty.allocator.type=unpooled,将这个参数的值设置为 unpooled 即可。
第二步,添加内存泄漏检测,如何添加内存泄漏检测?
这就要使用一个我们没讲过的参数了:-Dio.netty.leakDetection.level=PARANOID,这个参数有四个值:
DISABLED,表示不检测内存泄漏;
SIMPLE,表示会追踪小部分对象的内存使用情况,同时会消耗少量的资源;
ADVANCED,表示会追踪大部分对象的内存使用情况,同时会消息大量的资源;
PARANOID,表示会追踪所有对象的内存使用情况。
其中,默认值是 SIMPLE,四个值的强度为依次增加。
上面在查看日志的时候说的运气好,就是指这里使用 SIMPLE 的情况下有可能会有相关的日志。
在本地调试,直接开启最高级别 ——PARANOID。

第三步,模拟大量请求,为什么要模拟大量请求呢?
因为,上面的内存泄漏检测,只有在 gc 的时候才会打印相关的日志,平时,这些信息会保存在 Set 中,有兴趣的同学可以看看 ResourceLeakDetector 这个类,怎么才能快速 gc 呢?模拟大量的请求不失为一种好方法。
那么,怎么模拟大量的请求呢?
其实,也很简单,只需要在 MockClient 中加一个循环即可:

public class MockClient {public static void start(Channel channel) {// 发送hello消息for (int i = 0; i < 1000; i++) {HelloRequest helloRequest = HelloRequest.newBuilder().setName("哥").build();MessageUtils.sendRequest(helloRequest);try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}

第四步,步步为营,耐心寻找泄漏点。
这一步没有什么取巧的办法,只能慢慢分析上面的日志,或者,使用调试大法跟踪 ByteBuf 走过的路径,再慢慢缩小范围一步一步排查。
在上面日志的最后,已经明确告诉了你这个 ByteBuf 是在哪里创建的了,所以,使用调试大法的时候直接把断点打在那里一步一步往后面跟就可以了。
调试大法,前面我们已经用过太多次了,这里就不细说了,主要还是看日志,找到上面日志的 “#”3 处:

好吧,原来是这里多加了一次引用计数,导致这个 msg 回收不掉,最终导致内存泄漏。
把 retain () 去掉一行,重启服务端和客户端,观察服务端日志:

好了,整个排查过程就介绍完了,那么,我们在平时的开发中有没有什么好的方法可以规避这种问题呢?
要想预防这种直接内存泄漏的问题,方法还是有的,最简单有效的方法就是在测试环境设置这两个参数:
-Dio.netty.allocator.type=unpooled
-Dio.netty.leakDetection.level=PARANOID
在测试同学压测的时候,观察一下监控的情况,如果监控出现了直接内存缓慢增长的情况,那说明就有内存泄漏了,提前排查问题提前规避,当然,排查的过程还是一样要分析日志,或者耐心调试,这是少不了的步骤。
最后,在生产环境,记得把这两个参数去掉,或者恢复到默认值。

如何快速排查生产问题相关推荐

  1. 线上服务Java进程假死快速排查、分析

    线上服务Java进程假死快速排查.分析 最近我们有一台服务器上的Java进程总是在运行个两三天后就无法响应请求了,具体现象如下: 请求业务返回状态码502,查看进程还在,意味着Java进程假死,无法响 ...

  2. Android BugReport异常快速排查手册

    快速排查 应用发生崩溃,如果是生产环境,通常容易找到,如果不是,那就麻烦很多.bug的发生总是那么突如其来,有时候让我们措手不及,现在我就来理一理如何淡定的解决bug: 应用异常退出有两种可能,一种是 ...

  3. 快速排查feign.FeignException: status 500 …

    feign.FeignException: status 500 - 总结一下feign报500的时候快速排查问题的方法, 这个bug容易出现的地方分别为: 1. 远程调用的时候feign的注册信息有 ...

  4. 【收藏】快速排查无线AP故障的十种方法

    [欢迎关注微信公众号:厦门微思网络] 众所周知,无线AP设备用于集中连接所有无线节点,并进行集中管理.一般的无线AP会提供一个有线以太网接口,用于与有线网络.工作站和路由设备的连接.下面介绍10种快速 ...

  5. 用于快速排查Java的CPU性能问题(top us值过高)

    转载于GIT路径 https://github.com/oldratlee/useful-scripts/blob/master/docs/java.md#beer-show-busy-java-th ...

  6. 【如何在linux环境下排查生产环境java线程阻塞问题】

    如何在linux环境排查生产环境java线程阻塞问题 开胃小菜 进入主题,这里以我自己的服务器为例子 开胃小菜 在进入主题前我们先看一下windows的一个小命令 注:在本地有java环境开启的时候执 ...

  7. show-busy-java-threads脚本初体验,快速排查Java的CPU性能问题

    前言 之前写过一篇文章,通过top和jstack命令来排查CPU使用率高的问题,详见:https://blog.csdn.net/yougou_sully/article/details/842624 ...

  8. 一文读懂,制造业怎么快速提高生产质量和生产效率?

    质量是企业生存的根本,没有质量保障的企业会被市场淘汰,效率是企业追逐利益的保障,高效生产不仅能降低企业成本,而且能给企业创造更多的利益,那么如何才能实现生产质量和效率的提高呢? 一.提高生产品质:从原 ...

  9. 阿里技术:如何快速排查线上故障?

    阿里技术:如何快速排查线上故障? 以下文章来源于阿里技术 ,作者小峯 阿里技术 阿里巴巴官方技术号,关于阿里的技术创新均呈现于此. 有哪些常见的线上故障?如何快速定位问题?本文详细总结工作中的经验,从 ...

最新文章

  1. java继承对象转换_java 继承的基础(转)
  2. openSSL命令、PKI、CA、SSL证书原理
  3. Linux进程通信之文件
  4. 【Breadth-first Search 】752. Open the Lock
  5. 突然无法连接数据库了(解决了)
  6. 剑指offer面试题[27]-二叉搜索树与双向链表
  7. Altium Designer(二):规则设置
  8. 实现两线程的同步一(wait/notify)
  9. 一步一步 IText.Sharp
  10. 千万不要花费时间和金钱学习火山软件开发平台 - 递归软件绝非易语言的延续!
  11. DB2数据库v10.5安装过程
  12. Amaze UI貌似挂了。。。附上amaze UI框架的图标
  13. C# 使用NPIO 导出导出EXECL
  14. 打造金融科技新生态,巨杉数据库与宇信科技完成产品兼容互认证
  15. 【SIGN】函数使用技巧
  16. HDU4847-Wow! Such Doge!
  17. Cocos Creator中退出游戏,暂停,继续
  18. 如何从技术岗位走向管理岗位:机会是留给有准备的人
  19. 【Oracle】RAC11gR2 Grid启动顺序及启动故障诊断思路
  20. 2007我们的铁路春运

热门文章

  1. Java内存模型(Java Memory Model,简称JMM)
  2. vue基础4——自定义指令
  3. 微服务模块综合管理(模块视图管理,自动化热部署,前端资源实时刷新......)
  4. php怎样使用pdo,PHP中使用PDO_PHP教程
  5. python中的pyinstaller库_Python(00):PyInstaller库,打包成exe基本介绍
  6. python的类里的属性是否可以为列表_是否有Python方法可以访问类的所有非私有和非内置属性?...
  7. Python基础班---第一部分(基础)---Python基础知识---计算机组成原理
  8. 我是不是在浪费生命?
  9. 给自己看的squid服务器配置笔记
  10. 职业生涯中的选择时机非常重要,各种条件还没成熟时的时候,因为诱惑而贸然行事,只会得到适得其反的结果...