记一次dubbo问题的排查过程

记一次dubbo问题的排查过程

项目上遇到了一个问题
排查了相当长的时间,终于在同事的帮助下解决
在此记录下排查过程,希望以后不会遇到此类问题了

先介绍项目环境和背景

原项目:dubbo-2.5.3, 未使用fst序列化
升级到:dubbo-2.8.4, 使用fst序列化

第一节

同事在赶一个项目,由于时间紧迫,我也就一起参与了进去
一切都有条不紊的进行着:gitlab获取代码、编译、运行
接着,dubbo服务调用失败(同事那边可以运行成功)……

部分错误日志如下(点击查看完整错误日志):

1
2
3
4
5
6
7
8
9
10
11
12
....前面省略...
Caused by: java.lang.NullPointerException: Class is null
at de.ruedigermoeller.serialization.FSTClazzInfoRegistry.getCLInfo(FSTClazzInfoRegistry.java:127)
at de.ruedigermoeller.serialization.FSTObjectInput.getClazzInfo(FSTObjectInput.java:299)
at de.ruedigermoeller.serialization.FSTObjectInput.readObjectWithHeader(FSTObjectInput.java:249)
at de.ruedigermoeller.serialization.FSTObjectInput.readObjectInternal(FSTObjectInput.java:230)
at de.ruedigermoeller.serialization.FSTObjectInput$2.readObjectOverride(FSTObjectInput.java:1131)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
at de.ruedigermoeller.serialization.FSTObjectInput$MyObjectStream.readObjectOverride(FSTObjectInput.java:1437)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
at java.util.ArrayList.readObject(ArrayList.java:771)
... 39 more

此处问题是fst类找不到(插一句:fst是序列化用的库,因为我们用到了PageList做分页,如果没有fst在序列化时不能序列化List,分页就会失败)
查看maven依赖树(mvn dependency:tree)发现包是存在的,并且类也是有的

经过前辈们的指点,于是对比一下双方打的包有什么区别
使用工具比较了一下,发现文件个数都是对的上的
当然,这里不能单单只比较文件个数,还要对比文件大小
最重要的还是要对比引入的jar版本是否一致(尤其关心内部打的jar包,因为版本号可能都是1.0.0啥的,第三方包因为带版本很容易看出来)

最后,排查的结果是,双方引用的一个xx-api.jar不一致导致的问题
也就是启动本地服务,跟服务器部署的服务所使用的api版本不一致(服务器上是之前部署的,没有及时更新,而我本地是用的最新的代码mvn install的)
于是,把服务器上的api替换掉我本地的api,dubbo服务成功调用

第二节

虽然是成功的调用了dubbo的服务,但是我们是不太希望降版本实现的
所以我接着就把测试服务器上dubbo服务依赖的xx-api.jar版本升级成跟我本地一致
也就是把服务器上的dubbo服务重新打包部署了一遍

然后:启动-OK,调用-超时

心累,继续排查
尝试使用telnet连接dubbo并调用成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Type `help' to learn how to use Xshell prompt.
[D:\~]$ telnet 123.123.456.46 20937

Connecting to 123.123.456.46 20937...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.

dubbo>help
Please input "help [command]" show detail.
log level - Change log level or show log
pwd - Print working default service.
trace [service] [method] [times] - Trace the service.
clear [lines] - Clear screen.
exit - Exit the telnet.
help [command] - Show help.
ls [-l] [service] - List services and methods.
invoke [service.]method(args) - Invoke the service method.
ps [-l] [port] - Print server ports and connections.
cd [service] - Change default service.
status [-l] - Show status.

dubbo>ls
com.xxx.SaleStatisticsServiceFacade
com.xxx.OrderServiceFacade
com.xxx.OrderQryServiceFacade

dubbo>invoke com.xxx.OrderQryServiceFacade.getOrder("1")
{"content":null,"resCode":"0","resMsg":"操作成功"}
elapsed: 7 ms.
dubbo>

为什么使用telnet本地调用能成功,但是在我的开发电脑上远程调用就超时呢??
又是经过指点:可能本地跟远程调用使用的序列化方式不一样,可能还是fst的问题

去标准输出里面查看dubbo服务的启动日志,找到这么一段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2018-09-14 20:23:05.462  [DUBBO] Decode rpc invocation failed: /usr/java/jdk-7u67-i586/jre/lib/i386/xawt/libmawt.so: libXext.so.6: cannot open shared object file: No such file or directory, dubbo version: 2.8.4, current host: 127.0.0.1
java.lang.UnsatisfiedLinkError: /usr/java/jdk-7u67-i586/jre/lib/i386/xawt/libmawt.so: libXext.so.6: cannot open shared object file: No such file or directory
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1965)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1890)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1851)
at java.lang.Runtime.load0(Runtime.java:795)
at java.lang.System.load(System.java:1062)
...省略部分...

2018-09-14 20:23:05.466 [DUBBO] Skip input stream 246, dubbo version: 2.8.4, current host: 127.0.0.1
2018-09-14 20:23:05.478 [DUBBO] Fail to encode response: Response [id=167458, version=2.0.0, status=40, event=false, error=Fail to decode request due to: RpcInvocation [methodName=null, parameterTypes=null, arguments=null, attachments={input=262}], result=null], send b
ad_response info instead, cause: Could not initialize class com.alibaba.dubbo.common.serialize.support.fst.FstFactory, dubbo version: 2.8.4, current host: 127.0.0.1
java.lang.NoClassDefFoundError: Could not initialize class com.alibaba.dubbo.common.serialize.support.fst.FstFactory
at com.alibaba.dubbo.common.serialize.support.fst.FstObjectOutput.<init>(FstObjectOutput.java:32)
at com.alibaba.dubbo.common.serialize.support.fst.FstSerialization.serialize(FstSerialization.java:41)
at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.encodeResponse(ExchangeCodec.java:286)
at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:78)
at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:39)
...省略部分...

果然,还是fst导致的,但是源头是找不到文件/usr/java/jdk-7u67-i586/jre/lib/i386/xawt/libmawt.so: libXext.so.6
那就继续查看文件目录,是不是真的没有这个文件

1
2
3
4
5
[root@wifiA ~]# cd /usr/java/jdk-7u67-i586/jre/lib/i386/xawt
[root@wifiA xawt]# ll
total 372
-rwxr-xr-x 1 uucp 143 380612 Jul 26 2014 libmawt.so
[root@wifiA xawt]#

好吧,文件存在,问题又出现在哪呢?
再仔细看jdk-7u67-i586,32位jdk???

看看dubbo启动脚本使用的jdk版本是不是32位的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 默认的jdk版本
[root@wifiA bin]# java -version
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) Server VM (build 24.65-b04, mixed mode)

// 我们还有个64位的jdk
[root@wifiA bin]# /usr/java/jdk1.7.0_71/bin/java -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

// dubbo启动脚本
[root@wifiA bin]# cat start.sh
#!/bin/sh
set -m

base_path='/opt/snp/snp-order-service'
project_name='snp-order-service'
project_version='1.0.0'

if [ ! -f "${base_path}/logs/${project_name}.pid" ];then
echo 'dubbo进程PID文件不存在,请重新运行命令!'
touch ${base_path}/logs/${project_name}.pid
exit 0
fi

PID=$(cat ${base_path}/logs/${project_name}.pid)
if [ -n "$PID" ];then
echo 'dubbo服务已启动,请先停止'
exit 0
fi

java -Xms512M -Xmx512M -jar ${base_path}/jar/${project_name}-${project_version}.jar >> ${base_path}/logs/${project_name}.log 2>&1 &

echo "启动进程的PID为$!"
if [ $? -eq 0 ];then
echo $! > ${base_path}/logs/${project_name}.pid
echo 'jar包运行成功!'
else
echo "jar包运行不成功!"
fi

果然,启动脚本使用的是java-32位启动的,换成64位jdk重启服务,终于搞定

1
/usr/java/jdk1.7.0_71/bin/java -Xms512M -Xmx512M -jar ${base_path}/jar/${project_name}-${project_version}.jar >> ${base_path}/logs/${project_name}.log 2>&1 &
后记

讲真,在工作中,我最怕遇到的问题不是代码的问题
恰恰就是这种,在别人的环境下可以运行,但是在自己的环境里就运行不了的这种奇怪问题
如果真是碰到了这种问题,就由不得你要脑壳疼一阵子了…

上面的排查过程,虽然此处记下了各种问题的原因,以及解决方案
但是,在这个寻找问题原因的过程中的艰辛,不经历过的,估计是不能体会的
虽然记录下了此问题,但真心希望以后在也别遇到了
就这样吧,脑壳现在还疼着呢…

作者

Trainoo

发布于

2018-09-14

更新于

2020-06-02

许可协议