ActiveMQ Classic启动时读取JDBC日志抛出异常的排查求助
核心机制背景
ActiveMQ Classic 5.x在JDBC持久化模式下,并非直接将消息写入数据库,而是先写入本地的activeio journal预写日志文件,待确认数据库写入成功后,再清理或滚动这些本地日志。这个机制是为了保证消息的原子性与可靠性,避免数据库写入失败导致的数据丢失。
故障触发链
数据库不可用导致日志无限制增长
当Oracle数据库运维故障无法访问时,Broker无法将journal中的操作同步到数据库,因此不会触发journal日志的滚动(按配置的30MB切割新文件)或清理逻辑,只能持续往同一个journal文件写入数据,最终突破配置的单个文件大小限制。32位整数偏移量溢出触发异常
org.apache.activeio.journal.active.LogFileManager类使用32位有符号整数维护文件读写偏移量,这类整数的最大值为2^31-1字节(约2GB)。当journal文件大小超过这个阈值后,偏移量计算会出现溢出,变成非法的负数或超出文件范围的数值,调用FileChannel.position()方法时就会抛出IllegalArgumentException,对应你看到的堆栈信息:
Caused by: java.lang.IllegalArgumentException
at sun.nio.ch.FileChannelImpl.position(FileChannelImpl.java:278)
at org.apache.activeio.journal.active.LogFile.seek(LogFile.java:64)
at org.apache.activeio.journal.active.LogFile.loadAndCheckRecord(LogFile.java:85)
at org.apache.activeio.journal.active.LogFileManager.checkAppendLog(LogFileManager.java:199)
at org.apache.activeio.journal.active.LogFileManager.initialize(LogFileManager.java:176)
at org.apache.activeio.journal.active.LogFileManager.(LogFileManager.java:103)
at org.apache.activeio.journal.active.JournalImpl.(JournalImpl.java:101)
- 恢复后无法自愈的原因
即使数据库恢复,Broker在启动或后续操作中需要读取这个超限的journal文件来完成未同步操作,但偏移量溢出导致的异常会阻断这个过程,无法完成日志同步与清理,因此重启Broker后异常依然存在。
测试环境与生产环境的差异解释
测试环境中journal文件增长到500-600MB后重置,是因为:
- 该大小未达到32位整数的溢出阈值(2GB),当JDBC恢复后,Broker可以正常读取journal文件,将未同步的操作写入数据库,完成后触发日志清理与滚动,将文件重置为初始大小。
- 重启后仅恢复数据库中已持久化的消息,是因为未同步到数据库的journal日志在测试环境中被正常处理,但生产环境中已溢出的日志文件无法被Broker读取,只能跳过这些未同步数据,仅从数据库加载已持久化的消息。
内容的提问来源于stack exchange,提问作者Subhrajit Sarkar

