压测emqx导致假死,java hook导致?

问题描述

我们测试环境对emqx进行压测,数量2w个连接,连接速率约每秒400个,一段时间后,压测程序停止。dashboard上客户端列表数量并未减少并且也踢不掉,踢掉时emqx响应超时。打开emqx remote_console看,MsgQ 积压了5k条并且数量没变化。后续启动压测程序,也无法连接。从整体看,emqx等于宕机。
emqx 接入了java hook,java hook 逻辑就是在客户端上下线对redis进行写操作。

为了减少对redis写的频次,在onClientConnected 和onClientDisconnected方法内,把事件插到全局的LinkedBlockingQueue。启一个worker 线程,每500ms,从LinkedBlockingQueue通过drainTo方法,把元素移到新的List,然后for循环处理。LinkedBlockingQueue是线程安全的,按道理说应该不会有问题的。

退一步讲,就算worker线程有异常,也不会影响也不应该影响到onClientConnected方法,何况这方法是void 返回。我还特地看了下内存情况,都是很正常的。LinkedBlockingQueue 长度我也没有做限制。

那么问题在哪呢?如何优化?

erlang 是如何调用java hook的呢 ?机制是什么?有什么限制?

PS: 后来我取消了worker线程和LinkedBlockingQueue,改成了直接在方法内调用redis相关方法,情况可以改善(测试时间不够长),直到有个同事修改了clientId为字符串,导致代码中的Long.parseLong方法抛出异常(多次),居然也导致了emqx 挂掉。

环境信息

  • EMQ X 版本:4.2.8
  • 操作系统及版本:ubuntu20.04
  • 其他 java hook 运行环境采用jdk1.8

相应的配置文件内容


详细日志

![微信图片_20210322221210|690x252](upload://lKTifcUZh28fRwBFkIxOOy6duc2.jpeg) 

相关截图

Hello @172141102 先一个问题一个问题的看… 你那边方便做个 Demo 么?仍然保留 Worker 和 LinkedBlockingQueue 的逻辑,Worker 仅做个打印就行了不用写 Redis。然后看看能不能复现问题,可以复现问题的话。Demo 的工程贴一下

我猜测可能是,emqx 的 erlport 和 java 这端的 erlport 数据收发出现死锁了
java 侧的代码在这里:erlport/priv/java/erlport at master · emqx/erlport · GitHub

你也可以自己手动编译它,打印日志的话用 System.err.printf(...) 这样的话日志应该会出现在 emqx 的控制台,不要用 System.out 标准输出流。

1 个赞

对了,有个比较重要的细节:输出用System.err, 不要用out,不然也会导致卡死。

1 个赞

这个问题我在很早期就知道了

我很早知道了得用err.println

只打印是没有问题的。我仔细看了LinkedBlockingQueue 源码,对于放入元素来说,它提供了两种方法一个put,一个是offer 带timeout ,今天得试试offer方法了

1 个赞

:ok_hand: 你看下LinkedBlockingQueue 的在多线程里面的使用方式。然后再多压一压试试

提个建议啊,hook 方法应该增加一个开关,有些hook点是同步阻塞的,有些hook点仅通知即可,不用管方法有没有返回

通过改写erlport 源码和优化hook ,仅连接速度都比未改之前提升好几倍,原先需要5~7 秒才能连接成功,现在是秒连

2 个赞

Cool!! @172141102 能通用么? 提个 PR 我们一起在 Github 上面看看?

有点取巧,可能对于我的业务来说适合一点。不过思路上确实值得通过配置,让用户自定义选择

可以看看…还有我们上次提到的 远程调试什么的…说不定可以把一些 jvm 的参数也可以暴露出来…给上层配置。这种可能要麻烦一些