Linux下ActiveMQ Apollo 1.7.1 CPU占用100%问题排查求助
ActiveMQ Apollo 1.7.1 CPU 100%、新TCP连接无法建立问题定位方案
问题场景
Linux环境部署ActiveMQ Apollo 1.7.1版本,基于MQTT协议实现服务端向客户端的消息推送,当前使用的Broker配置如下:
<broker xmlns="http://activemq.apache.org/schema/activemq/apollo"> <notes> The default configuration with tls/ssl enabled. </notes> <log_category console="console" security="security" connection="connection" audit="audit"/> <authentication domain="apollo"/> <!-- Give admins full access --> <access_rule allow="admins" action="*"/> <access_rule allow="*" action="connect" kind="connector"/> <virtual_host id="myapollo"> <host_name>myapollo</host_name> <access_rule allow="users" action="connect create destroy send receive consume"/> <leveldb_store directory="${apollo.base}/data"/> </virtual_host> <connector id="tcp" bind="tcp://0.0.0.0:61613"/> <key_storage file="${apollo.base}/etc/keystore" password="password" key_password="password"/> </broker>
故障表现为Apollo进程CPU占用率达100%,故障触发后无法通过TCP建立新连接,按以下步骤定位根因:
- 抓取高CPU线程的运行栈
首先执行top命令找到Apollo对应的Java进程PID,再执行top -Hp <Apollo进程PID>筛选出CPU占用最高的前5个线程ID,执行printf '%x\n' <线程ID>把线程ID转为16进制格式。连续执行3次jstack -l <Apollo进程PID> > apollo_stack_$(date +%s).log抓取间隔10秒的线程栈快照,在栈日志中搜索对应16进制线程ID,查看线程持续执行的逻辑:Apollo 1.7.1版本常见的高CPU栈场景包括NIO Selector空轮询、LevelDB Compaction空转、MQTT协议解析死循环、权限校验逻辑异常递归。 - 核对现有日志的异常记录
进入${apollo.base}/log目录,按故障发生时间点核对四类日志输出:- connection日志:排查故障前是否存在大量半开TCP连接、客户端重复短连接重连、客户端发送畸形MQTT报文的记录
- security日志:排查是否存在未授权客户端持续暴力连接、触发鉴权逻辑无限重试的记录
- console日志:排查是否存在LevelDB文件损坏、索引异常、Compaction任务卡住的报错,该版本自带LevelDB在存储文件磁盘占比超过70%时,容易出现Compaction线程空转占满CPU的问题
- audit日志:排查是否存在单Topic消息量突增、持续投递无消费者的记录
- 核对系统与进程运行指标
执行以下命令核对系统层限制:- 执行
ulimit -n查看进程最大文件句柄配置,再执行ls /proc/<Apollo进程PID>/fd | wc -l统计当前进程已打开的文件句柄数,如果句柄数触达上限,会出现新连接无法建立、NIO层持续抛出IO异常导致空轮询占满CPU的问题 - 执行
netstat -anp | grep 61613 | grep ESTABLISHED | wc -l统计当前端口的已建立连接数,排查是否超过connector配置的最大连接上限 - 如果能访问Apollo默认61680端口的web控制台,直接查看各Topic的消息堆积量,确认是否存在离线消息无过期策略、队列无限膨胀触发存储层持续全量扫描的问题
- 执行
- 验证当前配置的已知缺陷
现有配置存在三个已知可触发该故障的风险点,可逐一验证:- TCP connector未配置MQTT连接的空闲超时、心跳检测参数:该版本默认关闭MQTT空闲连接回收,遇到网络异常导致的半开连接时,NIO层会持续读取空数据进入空轮询,单个异常连接即可占满1核CPU,异常连接积累到一定数量就会占满所有CPU资源,同时阻塞新连接接入
- 虚拟主机未配置消息过期策略、Topic存储配额:服务端向离线客户端推送的消息如果没有配置过期时间,会永久持久化到LevelDB中,存储文件持续膨胀后会触发Compaction线程长期高CPU占用
- 配置了key_storage但未绑定对应的TLS connector:1.7.1版本存在已知逻辑bug,当普通TCP连接上收到类TLS握手的异常字节时,会触发SSL引擎异常处理逻辑死循环占满CPU
内容的提问来源于stack exchange,提问作者孙悟空
相关产品推荐
相关产品推荐

