Java-216 RocketMQ 4.5.1 在 JDK9+ 从0到1全流程启动踩坑全解:脚本兼容修复(GC 参数/CLASSPATH/ext.dirs)

TL;DR

  • 场景:RocketMQ 4.5.1 在 JDK9+ 启动被「废弃/移除的 JVM 参数」和「类路径未加载 lib」卡住。
  • 结论:删 CMS/ParNew 与 java.ext.dirs,GC 日志切 -Xlog,CLASSPATH 补 ${BASE_DIR}/lib/*。
  • 产出:runserver/runbroker/tools 三处最小改动清单 + 版本矩阵 + 错误速查卡。

版本矩阵

项目 说明
RocketMQ 4.5.1 文中下载与脚本修改均以4.5.1的bin包路径结构为前提(conf、lib、bin)。
JDK 8 不属于本文"必须改脚本"的目标区间;旧参数体系更容易"还能跑",但与本文JDK9+统一日志改法不同。
JDK 9--17 本文修改点(删CMS/ParNew、删java.ext.dirs、-Xlog、补lib/*)面向该区间的典型兼容面。
JDK 18+ 文中未给出该区间的明确验证信号;仍按JDK9+逻辑处理,但不对"零差异可用"做一致性承诺。
Linux(通用) 路径与命令按常见发行版shell环境编写;/etc/profile、/dev/shm、~/logs写法依赖标准目录约定。

RocketMQ 环境搭建

软件下载

我们先进入到目录,然后对软件进行下载:

shell 复制代码
cd /opt/software

接着我们通过 wget 进行下载:

shell 复制代码
wget https://archive.apache.org/dist/rocketmq/4.5.1/rocketmq-all-4.5.1-bin-release.zip

对应内容如下所示:

解压移动

shell 复制代码
unzip rocketmq-all-4.5.1-bin-release.zip
mv rocketmq-all-4.5.1-bin-release ../server/rocketmq

对应的结果如下所示:

修改脚本

  • bin/runserver.sh
  • bin/runbroker.sh
  • bin/tools.sh

我们首先进入配置目录

shell 复制代码
cd /opt/server/rocketmq

runserver

shell 复制代码
vim bin/runserver.sh

根据下面的要求删除对应的内容(后续会解释为什么要删除):

删除

  • UseCMSCompactAtFullCollection
  • UseParNewGC
  • UseConcMarkSweepGC

修改内存

shell 复制代码
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=64mm -XX:MaxMetaspaceSize=160mm"

修改gc配置

shell 复制代码
-Xloggc 修改为 -Xlog:gc

整体修改完:

shell 复制代码
#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=160m"
JAVA_OPT="${JAVA_OPT} -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xlog:gc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT}  -XX:-UseLargePages"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"

classpath 这里需要补一个:

shell 复制代码
# 原来是
export CLASSPATH=".:${BASE_DIR}/conf:CLASSPATH
# 补充完
export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*"

基本内容如下所示了:

broker

shell 复制代码
vim bin/runbroker.sh

修改一下JVM的参数:

shell 复制代码
-Xms256m -Xmx256m -Xmn128m

删除

  • PrintGCDateStamps
  • PrintGCApplicationStoppedTime
  • PrintAdaptiveSizePolicy
  • UseGCLogFileRotation
  • NumberOfGCLogFiles=5
  • GCLogFileSize=30m

删除:

shell 复制代码
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"

整体上就是删除了一大段:

shell 复制代码
#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=15g"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"

classpath 这里需要补一个:

shell 复制代码
# 原来是
export CLASSPATH=".:${BASE_DIR}/conf:CLASSPATH
# 补充完
export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*"

整体如下:

tools

shell 复制代码
vim bin/tools.sh

删除:

shell 复制代码
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/lib:${JAVA_HOME}/jre/lib/ext"

classpath 这里需要补一个:

shell 复制代码
# 原来是
export CLASSPATH=".:${BASE_DIR}/conf:CLASSPATH
# 补充完
export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*"

整体结果如下:

针对修改的解释

这些改动的核心动机只有一个:让 RocketMQ 的启动脚本在 JDK9+(尤其 JDK14/15+)不再因为"过时/被移除的 JVM 参数"而告警或直接启动失败,同时把 GC 日志切到 JDK9 引入的统一日志体系。

runserver:删除 CMS/ParNew 相关参数 + 换 GC 日志体系 + 改内存

删除 UseCMSCompactAtFullCollection / UseParNewGC / UseConcMarkSweepGC

  • UseConcMarkSweepGC(CMS)在 JDK9 就被标记为 deprecated,后续版本彻底移除;继续带着该参数会从"警告"变成"直接报错退出"。
  • UseParNewGC 是 CMS 时代常见的年轻代收集器搭配项;当 CMS 被移除后,这类 仅对 CMS 有意义的参数会被废弃/作废。
  • UseCMSCompactAtFullCollection 是 CMS 体系内的 Full GC 压缩控制项;同样属于 CMS 专属参数,CMS 消失后它也没有语义价值。
  • JDK9 起默认 GC 已经切换到 G1("让 G1 成为默认"是 JDK9 的方向之一),所以很多人直接把 CMS/ParNew 参数整段删掉,避免版本兼容问题。

-Xloggc 改为 -Xlog:gc:JDK9 引入 Unified JVM Logging(统一日志框架),GC 日志也随之迁移到 -Xlog 体系;老式的 -Xloggc 与一堆 -XX:+PrintGC... 组合逐步被替代。

修改内存:-Xms/-Xmx/-Xmn/MetaspaceSize/MaxMetaspaceSize

  • -Xms/-Xmx:分别是堆初始/最大;设为相同通常是为了避免运行时扩容带来的抖动(脚本层面追求"固定堆")。
  • -Xmn:年轻代大小(影响 minor GC 频率与停顿形态)。
  • MetaspaceSize/MaxMetaspaceSize:类元数据区阈值与上限;控制类加载相关的内存占用与触发元空间回收的节奏。

broker:删掉一批 GC 日志旧参数(因为统一日志体系不吃这套了)

  • PrintGCDateStamps
  • PrintGCApplicationStoppedTime
  • PrintAdaptiveSizePolicy
  • UseGCLogFileRotation
  • NumberOfGCLogFiles
  • GCLogFileSize

本质都属于 JDK8 及以前的"老 GC 日志开关 + 老日志轮转方式"。

JDK9+ 统一切到 -Xlog 后,这些要么被忽略、要么报 deprecated/obsolete,最终目的是把配置收敛到类似下面的能力集合:

  • 时间戳/停顿/更细粒度标签(由 -Xlog:...:time,uptime,tags,level 之类表达)
  • 文件输出与轮转(在 -Xlog 的 file 语法里完成,而不是 UseGCLogFileRotation/GCLogFileSize/... 这一套老参数)

tools:删除 -Djava.ext.dirs=...(JDK9 起扩展机制被移除)

-Djava.ext.dirs 依赖的是 JRE 的 extension classloader 机制(把 jar 放到 lib/ext 或用 java.ext.dirs 注入)。这个机制在 JDK9 因模块化运行时(JPMS)被移除;只要设置该属性,启动器就可能直接失败。

因此把 tools.sh 里这行删掉,是为了避免在 JDK9+ 上"脚本先天不兼容"的硬错误。

环境变量

配置RocketMQ的环境变量,方便我们后续进行服务启动:

shell 复制代码
vim /etc/profile
shell 复制代码
# RocketMQ 环境变量
export ROCKET_HOME="/opt/server/rocketmq"
export PATH="${ROCKET_HOME}/bin:$PATH"

写入的内容如下所示:

最后记得刷新

shell 复制代码
source /etc/profile

启动服务

NameServer

shell 复制代码
mqnamesrv

查看当前的服务日志:

shell 复制代码
tail -f ~/logs/rocketmqlogs/namesrv.log

Broker

启动服务:

shell 复制代码
mqbroker -n 0.0.0.0:9876

启动结果如下所示:

查看日志:

shell 复制代码
tail -f ~/logs/rocketmqlogs/broker.log

服务测试

发送消息

设置环境变量

shell 复制代码
export NAMESRV_ADDR=0.0.0.0:9876

使用官方提供的Demo:

shell 复制代码
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

执行结果如下所示:

接收消息

设置环境变量

shell 复制代码
export NAMESRV_ADDR=0.0.0.0:9876

使用官方提供的Demo:

shell 复制代码
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

执行结果如下所示:

关闭RocketMQ

shell 复制代码
mqshutdown namesrv
mqshutdown broker

错误速查

症状 根因定位 修复
Unrecognized VM option 'UseConcMarkSweepGC' 或直接退出 JDK9+ 移除/废弃 CMS/ParNew 体系参数 java -version;启动日志首屏 JVM options 从 runserver.sh 删除 UseConcMarkSweepGC/UseParNewGC/UseCMSCompactAtFullCollection(保持 G1 或默认)
GC 日志参数告警/不生效(-Xloggc、PrintGCDateStamps 等) JDK9+ 统一日志体系迁移到 -Xlog,旧开关逐步废弃 搜索脚本中的 -Xloggc、PrintGC*、UseGCLogFileRotation 将 -Xloggc 改为 -Xlog:gc:...;在 broker 脚本删除老式 GC 日志与轮转参数
Error: Could not find or load main class org.apache.rocketmq.namesrv.NamesrvStartup CLASSPATH 未包含 ${BASE_DIR}/lib/*(或脚本中 CLASSPATH 拼错为字面量 CLASSPATH)导致核心类不在类路径 echo $CLASSPATHbash -x mqnamesrv 看最终 -cp 将 export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*" 固化到脚本;避免 ...:CLASSPATH 这种字面量拼接
tools.sh 执行 Demo 报 ClassNotFound / 直接启动失败 -Djava.ext.dirs=... 依赖 JRE ext 机制,JDK9 起移除 tools.sh 搜 java.ext.dirs;观察 JVM 启动报错 删除 JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=...";用 CLASSPATH=conf + lib/* 承载依赖
JVM 启动时报 Invalid -XX:MetaspaceSize=... 或参数解析失败 参数单位/拼写错误(如 64mm) 启动日志中的 "Improperly specified VM option" 把 -XX:MetaspaceSize=64mm 修正为 -XX:MetaspaceSize=64m(同理检查 MaxMetaspaceSize)
环境变量设置后仍找不到命令 脚本引用目录不一致变量名不一致(如 ROCKETMQ_HOME vs ROCKET_HOME)导致脚本/命令路径判断偏离 envgrep ROCKET;检查 bin 脚本对 HOME 变量的读取

其他系列

🚀 AI篇持续更新中(长期更新)

AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南!
AI研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地
🔗 AI模块直达链接

💻 Java篇持续更新中(长期更新)

Java-207 RabbitMQ Direct 交换器路由:RoutingKey 精确匹配、队列多绑定与日志分流实战

MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务已完结,Dubbo已完结,MySQL已完结,MongoDB已完结,Neo4j已完结,FastDFS 已完结,OSS已完结,GuavaCache已完结,EVCache已完结,RabbitMQ正在更新... 深入浅出助你打牢基础!
🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
🔗 大数据模块直达链接

相关推荐
austin流川枫2 小时前
🔥MySQL的大表优化方案 (实战分享)
java·mysql·性能优化
码界奇点2 小时前
基于Spring Boot和Vue.js的视频点播管理系统设计与实现
java·vue.js·spring boot·后端·spring·毕业设计·源代码管理
爱吃山竹的大肚肚2 小时前
MySQL 支持的各类索引
java·数据库·sql·mysql·spring·spring cloud
程序员水自流2 小时前
MySQL常用内置函数详细介绍
java·数据库·mysql
廋到被风吹走2 小时前
【Spring】Spring Boot详细介绍
java·spring boot·spring
期待のcode2 小时前
Java中的继承
java·开发语言
DX_水位流量监测2 小时前
地埋式积水监测仪:城市防涝的智能感知核心
大数据·网络·人工智能·数据分析·自动化
计算机毕设指导62 小时前
基于微信小程序的智慧社区娱乐服务管理系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·娱乐
回家路上绕了弯2 小时前
分布式事务本地消息表详解:中小团队的低侵入落地方案
分布式·后端