日常的可以远程debug程序,线上程序查看线程堆栈和日志寻找线索。还不够的话可以使用jdb进行命令行debug程序。
(1)修改java启动脚本,把远程调试端口打开
JAVA_OPTS="$JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"
(2)程序运行起来
(3)attach jdb到程序上,在程序所在机器上运行 下面的脚本
$JAVA_HOME$/bin/jdb -attach 127.0.0.1:8787
如果成功,会显示下面的信息
main是主函数入口
(4)指定断点,运行
在这个类的74行指定断点,使用stop at 语句,后面跟着类的全路径。冒号分隔,后面是行号。
stop at com.taobao.jingwei.server.core.ServerCoreThread:74回车,后在看到提示符main[1] , 输入 run,回车;
看到程序被断在line=74行的地方,这时对照源代码,进行调试。
next是执行下一步,相当于F6
(5)要查看局部变量,输入locals。
step 表示进入方法,相当于eclipse的F5。
(6)使用dump查看对象的值
(7)内部类如何stop断住?
jdb有两个语法,一个是stop at(行号)和stop in(方法)
stop in com.taobao.jingwei.core.internal.extractor.Metaq3Extractor$MetaOrderMessageListener.consumeMessage
(8)线程运行的位置 where all,告诉所有线程的当前运行位置
(9)一个实际的例子:现象是多台机器(20)消费metaq的消息,但是有部分分区消费失败,有的机器可以成功消费,有的机器却消费失败。
metaq消费回调看到消费失败的日志,但是精卫没有打印任何异常,业务的apply方法内部打开了debug,如果收到消息也会打印到指定目录的文件,但是没有收到日志。只好jdb上调试了。
一步一步的,追到了异常抛出的地方。
org.apache.thrift.protocol.TProtocol.getScheme()Ljava/lang/Class;
thrift-0.2.0.jar 和 libthrift-0.8.0.jar两个包,排除掉thrift-0.2.0.jar(因为dbsync使用的是 libthrift-0.8.0.jar),重启,发现没有效果,还是会抛出异常。在eclipse中查找这个类TProtocol (Ctl+Shift+T),发现hive-core这个包含有同名的类TProtocol,而且包路径也相同。其实系统没有用到hive,所以排除掉这hive-core包后,再部署启动,恢复正常~~~